>> bitwise operator not working as expected - javascript

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;
}

Related

How to get Number of bits from Hex

For example how do I get 8 from 0x01, or 16 from 0x0001.
I want to know the number of bits a variable has.
var someNumber = 0x123456;
var len = whatToDoHere(someNumber);
console.log(len); // => 24 for example
Here are few alternatives:
f1 = n => (Math.log2(n) & -8) + 8 // log2 (-Infinity & -8 = 0)
f2 = n => ((n >>= 8) && f2(n)) + 8 // recursion
f3 = n => n.toString(16).length + 1 << 2 & -8 // string length
for (n of [0, 0xff, 0x100, 0xffff, 0x10000, 0xffffff])
console.log( f1(n) + '\t' + f2(n) + '\t' + f3(n) + '\t0x' + n.toString(16) )
A number is just a number, it does not have any particular representation attached to it. Even if you say that it would be formatted in base16 (as hex) or base256 (bytes), that doesn't say anything about the number of leading zeroes (as in 0x01 vs 0x0001). If you know that however, you'd already know how many digits your formatted number has.
Another possible solution is to convert to a hex string and then measure the length of the string:
const someNumber = 0x123456;
const hexString = someNumber.toString( 16 );
const numberOfBits = hexString.length * 4; //each character is half a byte
console.log( "Number of bits: ", numberOfBits );

Convert hexadecimal color to integer in 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.

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))

Guidance to understand Base64 encoding algorithm

I found this algorithm on the net but I'm having a bit of trouble understanding exactly how it works. It encodes an Uint8Array to Base64. I would like to understand especially the sections under the comments "Combine the three bytes into a single integer" and "Use bitmasks to extract 6-bit segments from the triplet". I understood the concept of bit shifting used there, but can't understand what's its purpose in those two sections.
function base64ArrayBuffer(bytes) {
var base64 = ''
var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
var byteLength = bytes.byteLength
var byteRemainder = byteLength % 3
var mainLength = byteLength - byteRemainder
var a, b, c, d
var chunk
// Main loop deals with bytes in chunks of 3
for (var i = 0; i < mainLength; i = i + 3) {
// Combine the three bytes into a single integer
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
// Use bitmasks to extract 6-bit segments from the triplet
a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
d = chunk & 63 // 63 = 2^6 - 1
// Convert the raw binary segments to the appropriate ASCII encoding
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
}
// Deal with the remaining bytes and padding
if (byteRemainder == 1) {
chunk = bytes[mainLength]
a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
// Set the 4 least significant bits to zero
b = (chunk & 3) << 4 // 3 = 2^2 - 1
base64 += encodings[a] + encodings[b] + '=='
} else if (byteRemainder == 2) {
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
// Set the 2 least significant bits to zero
c = (chunk & 15) << 2 // 15 = 2^4 - 1
base64 += encodings[a] + encodings[b] + encodings[c] + '='
}
return base64
}
The first step takes each group of 3 bytes in the input and combines them into a 24-bit number. If we call them x = bytes[i], y = bytes[i+1], and z = bytes[i+2], it uses bit-shifting and bit-OR to create a 24-bit integer whose bits are:
xxxxxxxxyyyyyyyyzzzzzzzz
Then it extracts these bits in groups of 6 to get 4 numbers. The bits of a, b, c, and d correspond this way:
xxxxxxxxyyyyyyyyzzzzzzzz
aaaaaabbbbbbccccccdddddd
Then for each of these 6-bit numbers, it indexes the encodings string to get a corresponding character, and concatenates them into the base64 result string.
At the end there are some special cases to deal with the last 1 or 2 bytes in the input if it wasn't a multiple of 3 bytes long.

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);
}

Categories

Resources