Convert hexadecimal color to integer in javascript - javascript

I'm trying to convert a hexadecimal color string to a int in javascript.
The color int must be the same format as VB6. I think the bytes are not in the normal order. Ex: 255 is red (#ff0000) and 16776960 is Aqua (#00ffff)
I have a function to do the inverse: (But someone in the comments told me that it's not correct)
function VBColorToHEX(i) {
var hex = (i & 0xFF).toString(16) +
((i >> 8) & 0xFF).toString(16) +
((i >> 16) & 0xFF).toString(16) +
((i >> 24) & 0xFF).toString(16);
hex += '000000';
hex = hex.substring(0, 6);
return "#" + hex;
}
But was unable to write a function to return to my initial value.
Can you help me?
EDIT:
I corrected my original function by padding each separate colors:
function VBColorToHEX(i) {
var r = (i & 0xFF).toString(16);
var g = ((i >> 8) & 0xFF).toString(16);
var b = ((i >> 16) & 0xFF).toString(16);
r = ('0' + r).slice(-2);
g = ('0' + g).slice(-2);
b = ('0' + b).slice(-2);
return "#" + r + g + b;
}

Here's a working version of your original function, which I think will make more sense to you about how it actually works.
function VBColorToHEX(i) {
var bbggrr = ("000000" + i.toString(16)).slice(-6);
var rrggbb = bbggrr.substr(4, 2) + bbggrr.substr(2, 2) + bbggrr.substr(0, 2);
return "#" + rrggbb;
}
Then, to do the reverse, do this:
function HEXToVBColor(rrggbb) {
var bbggrr = rrggbb.substr(4, 2) + rrggbb.substr(2, 2) + rrggbb.substr(0, 2);
return parseInt(bbggrr, 16);
}

function VBColorToHEX(i) {
var hex = (i & 0xFF).toString(16) +
((i >> 8) & 0xFF).toString(16) +
((i >> 16) & 0xFF).toString(16) +
((i >> 24) & 0xFF).toString(16);
hex += '000000'; // pad result
hex = hex.substring(0, 6);
return "#" + hex;
}
You're padding the result with zeroes instead of padding each color value.
For instance if i = 657930, the string hex value is something like #0A0A0A but you'll output #AAA000 instead.
Beside, if you're extracting 4 color channels you need 8 chars and not 6.
PS for the padding, see for instance this solution.

Related

Decode fixed string from integers in Javascript

I am presented with two 32-bit integers which have a fixed length eight character ASCII string encoded in them.
For example, the string "HEYTHERE" is split into "HEYT" and "HERE" and each is split into four bytes to give 0x48455954 and 0x48455245 or 1212504404 and 1212502597 respectively.
What's the most efficient way of converting these two numbers back into a string in Javascript?
So far I have the following but I'm wondering if there is faster / less clumsy way:
let xx1 = [ 1212504404, 1212502597 ];
let xx1str = String.fromCharCode((xx1[0] >> 24) & 255) +
String.fromCharCode((xx1[0] >> 16) & 255) +
String.fromCharCode((xx1[0] >> 8) & 255) +
String.fromCharCode( xx1[0] & 255) +
String.fromCharCode((xx1[1] >> 24) & 255) +
String.fromCharCode((xx1[1] >> 32) & 255) +
String.fromCharCode((xx1[1] >> 8) & 255) +
String.fromCharCode( xx1[1] & 255);
I think you can have a hash table of two characters or four characters.
hash2 = { '4040': 'AA', '4041': 'AB',
'4845':'HE',
'5954':'YT',
'4845':'HE',
'5245':'RE'
}
function madDecode(num) {
return hash2[num.toString(16).substr(0, 4)]
+ hash2[num.toString(16).substr(4, 4)]
}
out.innerHTML = madDecode(0x40404041) +', '
+ madDecode(1212504404) + madDecode(1212502597)
<span id=out></span>
You can improve further by using 4 character hash. And even further to use array instead of object.
hash2 = []
function chCode(x) {
x = x.toString(16)
while (x.length < 2) x = '0' + x
return x
}
function makeHash() {
for (var i = 32; i < 128; i++) {
for (var j = 32; j < 128; j++) {
hash2[parseInt(chCode(i) + chCode(j), 16)] = String.fromCharCode(i, j)
}
}
}
function arrDecode(num) {
var na = (num & 0xffff0000) >> 16,
nb = num & 0xffff
return hash2[na] + hash2[nb]
}
makeHash()
document.write(arrDecode(1212504404) + arrDecode(1212502597))

>> bitwise operator not working as expected

I'm trying to create a simple utility for myself to be able to convert values from rgb to hex, and vice versa. It works for the most part, except for one flaw.
If I enter a hex value like '007aff', '00' gets trimmed and the result is '7aff'. The r/g/b/ still gets the correct value, but I don't want the zeroes trimmed from the hexadecimal value. Am I doing something incorrectly?
// for anyone unfamiliar with angular
// $watch runs when the variable in quotes changes in value
// the rest is basic javascript
AngularJS:
$scope.$watch('hex', function() {
var rgb = parseInt($scope.hex, 16);
$scope.r = (rgb >> 16) & 0xFF;
$scope.g = (rgb >> 8) & 0xFF;
$scope.b = rgb & 0xFF;
$scope.rgb = 'rgb(' + $scope.r + ',' + $scope.g + ',' + $scope.b + ');';
});
$scope.$watch('r+g+b', function() {
$scope.rgb = 'rgb(' + $scope.r + ',' + $scope.g + ',' + $scope.b + ');';
$scope.hex = parseInt($scope.r << 16 | $scope.g << 8 | $scope.b).toString(16);
});
Here is a sample Plunker:
The 00 aren't directly trimmed. When your convert the rgb number to a string, you don't format it with leading zeros.
Try this to format with leading zeros:
var value = parseInt($scope.r << 16 | $scope.g << 8 | $scope.b);
$scope.hex = ('000000' + value.toString(16)).slice(-6);
After:
$scope.hex = parseInt($scope.r << 16 | $scope.g << 8 | $scope.b).toString(16);
add the following lines:
var len = $scope.hex.length;
for ( var i = 0 ; i < 6 - len ; i++ ) {
$scope.hex = '0' + $scope.hex;
}

RGBToHex with float r,g,b

I am trying the solutions in this thread: RGB to Hex and Hex to RGB without luck:
function rgbToHex(my_color) {
r = my_color.r;
g = my_color.g;
b = my_color.b;
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
When I call the above with the following:
my_color= {r: 51, g: 51, b: 9.180000000000003}
I get:
#333309.2e147ae
which doesn't seem right. Considering how my input is formatted, am I supposed to pass values in a different way?
Your function only works for integer values now, so that if there are float numbers in the color object the return is not doing its job properly.
I personal recommend using the built in function for javascript to return integer values from any given value.
The function is parseInt()
In your case the code would change from
function rgbToHex(my_color) {
r = my_color.r;
g = my_color.g;
b = my_color.b;
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
to
function rgbToHex(my_color) {
r = parseInt(my_color.r);
g = parseInt(my_color.g);
b = parseInt(my_color.b);
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
You may trim out float point values for the function to work properly.. You could use this:
function rgbToHex(my_color) {
r = Math.floor(my_color.r);
g = Math.floor(my_color.g);
b = Math.floor(my_color.b);
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}

Convert rgb to hex

I wanted to find a way to code a program that would convert ANY rgb including ones with negative integers into a hex number, like this software.
http://www.javascripter.net/faq/rgbtohex.htm
I have this already but it doesn't seem to be working with the rgb:
rgb(-5, 231, -17)
function rgb2hex(rgb){
rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
return (rgb && rgb.length === 4) ? "#" +
("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : '';
}
Thanks to anyone who can help!
Try this,
function colorToHex(color) {
if (color.substr(0, 1) === '#') {
return color;
}
var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color);
var red = parseInt(digits[2]);
var green = parseInt(digits[3]);
var blue = parseInt(digits[4]);
var rgb = blue | (green << 8) | (red << 16);
return digits[1] + '#' + rgb.toString(16);
};
colorToHex('rgb(120, 120, 240)');
Ref: http://haacked.com/archive/2009/12/29/convert-rgb-to-hex.aspx/

IP-addresses stored as int results in overflow?

I'm writing a chat-server in node.js, and I want to store connected users IP-addresses in a mysql database as (unsigned) integers.
I have written a javascript method to convert an ip-address as string to an integer. I get some strange results however.
Here is my code:
function ipToInt(ip) {
var parts = ip.split(".");
var res = 0;
res += parseInt(parts[0], 10) << 24;
res += parseInt(parts[1], 10) << 16;
res += parseInt(parts[2], 10) << 8;
res += parseInt(parts[3], 10);
return res;
}
When I run call the method as ipToInt("192.168.2.44"); the result I get is -1062731220.
It seems like an overflow has occurred, which is strange, because the expected output (3232236076) is inside the number range in javascript (2^52).
When I inspect -1062731220 in binary form, I can see the 3232236076 is preserved, but filled with leading 1's.
I'm not sure, but I think the problem is with signed vs. unsigned integers.
Can any of you explain what is going on?
And possibly how to parse -1062731220 back to an string ip?
Why is the converted IP negative?
It's NOT an overflow. The first part of your IP address is 192 which converts to 11000000 in binary. You then shift that all the way to the left. When there is a 1 in the leftmost position of a 32 bit number, it's negative.
How do you convert back to a string?
Do the same thing you did to convert from a string but in reverse. Shift right (and mask)!
function intToIP(int) {
var part1 = int & 255;
var part2 = ((int >> 8) & 255);
var part3 = ((int >> 16) & 255);
var part4 = ((int >> 24) & 255);
return part4 + "." + part3 + "." + part2 + "." + part1;
}
Why reinvent the wheel? From Google:
OR, you can use what I found here:
http://javascript.about.com/library/blipconvert.htm
function dot2num(dot)
{
var d = dot.split('.');
return ((((((+d[0])*256)+(+d[1]))*256)+(+d[2]))*256)+(+d[3]);
}
function num2dot(num)
{
var d = num%256;
for (var i = 3; i > 0; i--)
{
num = Math.floor(num/256);
d = num%256 + '.' + d;
}
return d;
}
The result of the "<<" operator is always a signed, 32-bit integer, as per the spec.
When you shift back, use ">>>" to do an unsigned right shift.
You might also find this pattern useful:
ip.toLong = function toInt(ip){
var ipl=0;
ip.split('.').forEach(function( octet ) {
ipl<<=8;
ipl+=parseInt(octet);
});
return(ipl >>>0);
};
ip.fromLong = function fromInt(ipl){
return ( (ipl>>>24) +'.' +
(ipl>>16 & 255) +'.' +
(ipl>>8 & 255) +'.' +
(ipl & 255) );
};
If you're using something like node.js where you can add functionality through something like Npm then you can simply do:
npm install ip
To get that functionality from the source which is here:
https://github.com/indutny/node-ip/blob/master/lib/ip.js
You will also get a bunch of other IP utility functions with that.
You shifted left to get the original number - which is just 4 sets of bits regardless of the sign.
Shift right to get back to the IP. Doesn't matter what the sign is.
const ip2int = (x) => (x.split('.').reduce((a, v) => ((a << 8) + (+v)), 0) >>> 0);
One-Liner:
const ipToLong = ip => ip.split('.').map(parseFloat).reduce((total, part) => total * 256 + part);
Use this
function num2string(ip) {
return [24,16,8,0].map(n => (ip >> n) & 0xff).join(".")
}
function string2num(ip) {
return ip.split(".").reduce((sum,x,i) => sum + (x << 8*(3-i)), 0)
}
IP Addresses in the V4 space are unsigned 32 bit numbers, hence the IP address of FF.FF.FF.FF is 2^32 and cannot be greater then that number. Please see:
This stack overflow article on the same subject
To turn that number back into an IP address you must break the number down into its 4 parts since each byte is one octet of the address so convert the number to hex and then parse out each pair. You may or may not have to add a leading zero for the first octet.
Additionally you may have to deal with byte order of the integer ( endien issues ) but since most systems are intel based these days you might not have to deal with that.
var aaa = Number("0b"+ "192.168.2.44".split(".").map(
function(dec){
return ("00000000" + Number(dec).toString(2)).slice(-8);
}).join(""));
aaa.toString(2).match(/.{1,8}/g).map(
function(bin){
return Number("0b"+bin);
}).join(".");
I revised Evan's final answer a bit, particularly dot2num. It functions the same but might be more readable and is marginally slower.
function ip2num(ip) {
var parts = ip.split('.');
var num = 0;
num += d[0] * Math.pow(2, 24);
num += d[1] * Math.pow(2, 16);
num += d[2] * Math.pow(2, 8);
num += d[3];
return num;
}
function num2ip(num) {
var ip = num % 256;
for (var i=3; i > 0; i--) {
num = Math.floor(num / 256);
ip = num % 256 + '.' + ip;
}
return ip;
}
Try this solution, it might help:
function IpToInteger(ipAddr)
{
var parts = ipAddr.split('.');
return (((parts[0] ? parts[0] << 24 : 0) |
(parts[1] ? parts[1] << 16 : 0) |
(parts[2] ? parts[2] << 8 : 0) |
(parts[3])) >>> 0);
}
function IpAddressToLong(ip){
return ip.split('.').map((octet, index, array) => {
return parseInt(octet) * Math.pow(256, (array.length - index - 1));
}).reduce((prev, curr) => {
return prev + curr;
});
}
Taken from repo
function ip2num(ip) {
var d = ip.split(".");
var num = 0;
num += Number(d[0]) * Math.pow(256, 3);
num += Number(d[1]) * Math.pow(256, 2);
num += Number(d[2]) * Math.pow(256, 1);
num += Number(d[3]);
return num;
}
function num2ip(num) {
var ip = num % 256;
for (var i = 3; i > 0; i--) {
num = Math.floor(num / 256);
ip = (num % 256) + "." + ip;
}
return ip;
}
console.log(ip2num("192.168.0.1"));
console.log(num2ip(3232235521))
<h1>YOU IS WELCOME</h1>

Categories

Resources