Finding average of colors? - hexadecimal strings - javascript

INSTRUCTIONS
Write a function that takes 2 colors as arguments and returns the average color.
The parameters will be two 6-digit hexadecimal strings. This does not need to be validated.
The return value should be a 6-digit hexadecimal string.
The hexadecimal strings represent colors in RGB, much like in CSS.
The average color is to be determined by taking the arithmetic mean for each component: red, green and blue.
CODE
const avgColor = (str1, str2) => {
return (str1 + str2) / 2
}
QUESTION
Hexadecimal is something like this 0000ff right?
I'm not sure what it means when I need to take the arithmetic mean for each component and lists 3 colors. How do you take an average of strings?

Here's a plain JS function:
You have to split the hex string into it's three color components before converting them to calculate the mean:
function calcAvg(hex1,hex2) {
//parsed into decimal from hex
//for each color pair
let hexC11 = parseInt(hex1.slice(0,2), 16);
let hexC12 = parseInt(hex1.slice(2,4), 16);
let hexC13 = parseInt(hex1.slice(4,6), 16);
let hexC21 = parseInt(hex2.slice(0,2), 16);
let hexC22 = parseInt(hex2.slice(2,4), 16);
let hexC23 = parseInt(hex2.slice(4,6), 16);
//calculate mean for each color pair
let colorMean1 = (hexC11 + hexC21) / 2;
let colorMean2 = (hexC12 + hexC22) / 2;
let colorMean3 = (hexC13 + hexC23) / 2;
//convert back to hex
let colorMean1Hex = colorMean1.toString(16);
let colorMean2Hex = colorMean2.toString(16);
let colorMean3Hex = colorMean3.toString(16);
//pad hex if needed
if (colorMean1Hex.length == 1)
colorMean1Hex = "0" + colorMean1Hex;
if (colorMean2Hex.length == 1)
colorMean2Hex = "0" + colorMean2Hex;
if (colorMean3Hex.length == 1)
colorMean3Hex = "0" + colorMean3Hex;
//merge color pairs back into one hex color
let avgColor = colorMean1Hex +
colorMean2Hex +
colorMean3Hex;
return avgColor;
}
let avg = calcAvg("999999","777777");
console.log(avg);

You can do it with this snippet:
function avg(a,b){
const regex=/^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ //regular expression to parse string
a=regex.exec(a).slice(1) //create array from string 'a' using regex
b=regex.exec(b).slice(1) //create array from string 'b' using regex
let output=''
for(let i=0;i<3;i++){
const value=Math.floor(
(
parseInt(a[i],16) + //parse decimal from hexadecimal
parseInt(b[i],16) //parse decimal from hexadecimal
)/2 //perform averaging
).toString(16) //convert back to hexadecimal
output += (value.length<2?'0':'') + value //add leading zero if needed
}
return output
}

Hexadecimal is something like this 0000ff right?
Yes.
To elaborate, each two characters of the "hexadecimal string" represents a color in hexadecimal (16 numbers per digit), rather than decimal (10 numbers per digit). So the first two characters represent the Red value of the color, the second two characters represent the Green value of the color, and the last two characters represent the Blue value of the color. Combining these values results in the final color.
To further elaborate, the "ff" hexadecimal value equals 256 as a decimal value. Hexadecimal digits go from 0-9, then continue to a, b, c, d, e, and f, before wrapping around to 0 again, so a hexadecimal "0f" number, would equal 16 in decimal. A hexadecimal "10" number would equal 17 as a decimal value. Counting from 0 to 17 in hexadecimal would look like this:
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0f", "10".

In order to calculate the average of a hexadecimal string value, you need to:
Convert the hexadecimal string to integer (something similar to parseInt('0000ff', 16))
Split the color components
Calculate the average value for each color component
Reconstruct the final value from the color components
Convert the result back to hexadecimal string (with padding), you can refer to this question How to convert decimal to hexadecimal in JavaScript .
An example of full code snippet will be something similar to
const avgColor = (str1, str2) => {
// Convert the hexadecimal string to integer
const color1 = parseInt(str1, 16);
const color2 = parseInt(str2, 16);
let avgColor = 0;
for (let i = 0; i < 3; i++) {
// Split the color components
comp1 = (color1 >> (8 * i)) & 0xff;
comp2 = (color2 >> (8 * i)) & 0xff;
// Calculate the average value for each color component
let v = parseInt((comp1 + comp2) / 2) << 8 * i;
// Reconstruct the final value from the color components
avgColor += parseInt((comp1 + comp2) / 2) << 8 * i;
}
return decimalToHex(avgColor, 6);
}
// Reference from https://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hexadecimal-in-javascript
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
console.log(avgColor("0000ff", "ff0000"))

There is a jQuery plugin for this if you can use jQuery -
$.xcolor.average(color, color)

Related

Trouble converting Javascript source to Python

I'm trying to convert a Javascript function to Python. Most of it was no problem but there's one statement I'm not sure how to convert:
color = +("0x" + color.slice(1).replace(color.length < 5 && /./g, '$&$&'))
The Python so far is:
color = +("0x" + color[:1].replace(
len(color) < 5 and /./g, '$&$&')
)
idk what +() or /./g are for. The complete JS function is:
function lightOrDark(color) {
// Variables for red, green, blue values
var r, g, b, hsp;
var threshold = 127.5
// Check the format of the color, HEX or RGB?
if (color.match(/^rgb/)) {
// If RGB --> store the red, green, blue values in separate variables
color = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
r = color[1];
g = color[2];
b = color[3];
} else {
// If hex --> Convert it to RGB: http://gist.github.com/983661
color = +("0x" + color.slice(1).replace(color.length < 5 && /./g, '$&$&'))
console.log(color)
r = color >> 16;
g = color >> 8 & 255;
b = color & 255;
}
// HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html
hsp = Math.sqrt(
0.299 * (r * r) +
0.587 * (g * g) +
0.114 * (b * b)
)
// Using the HSP value, determine whether the color is light or dark
return hsp > threshold;
}
The /./g is a regular expression and the +() coerces a string into a number (and the 0x makes it hexadecimal). In Python you'd use the re module and the int() builtin for that.
The replace duplicates the characters if the color is written in its short form. The Python equivalent is a re.sub(). You use a backslash instead of a dollar for back-references in Python's regex dialect. So \1 refers to the first matching group.
>>> import re
>>> color = "#123456"
>>> re.sub("(.)", r"\1\1" if len(color)<5 else r"\1", color[1:])
'123456'
>>> color = "#abc"
>>> re.sub("(.)", r"\1\1" if len(color)<5 else r"\1", color[1:])
'aabbcc'
So for a short string, this replaces each character with itself twice, but for a long string this replaces each character with itself once (no change).
Then you use a base of 16 to convert a hexadecimal string to an int:
>>> int('aabbcc', 16)
11189196
All together:
int(re.sub("(.)", r"\1\1" if len(color)<5 else r"\1", color[1:]), 16)
That's a fairly compact line of code. Let's deconstruct it.
First, +() is the same as Number() in this case it can also be alternatively implemented using parseInt().
Next /./g is just a regular expression. On its own it does not do anything. It is just a value like "hello" or 3. It is the first argument to replace().
So the line can be rewritten as:
let temp1 = color.slice(1); // In this case can also be rewritten as color.substr(1)
// It basically removes the first character
if (color.length < 5) {
temp1 = temp1.replace(/./g, '$&$&'); // This replaces each character with itself twice.
// For example "123" is replaced with "112233"
}
let temp2 = "0x" + temp1. // This adds "0x" to the previous string so that
// it will look like a hexadecimal number.
color = parseInt(temp2); // Convert string of hexadecimal number to a number.
I personally don't know Python but the above should be easy to rewrite in any language.
In case you're not comfortable with regular expressions you can rewrite the number doubling code using a loop. The following is an alternative implementation that does not use any fancy functions/methods at all:
// Remove first character (color.slice(1))
let temp1 = "";
for (let i=1; i<color.length; i++) { // copy every character except color[0]
temp1 = temp1 + color[i];
}
// Convert 3-letter color to 6-letter color, eg #69a to #6699aa
if (color.length < 5) {
let temp2 = "";
for (let i=0; i<3; i++) {
temp2 = temp2 + temp1[i] + temp1[i];
}
temp1 = temp2;
}
let temp3 = "0x" + temp1. // This adds "0x" to the previous string so that
// it will look like a hexadecimal number.
color = parseInt(temp3); // Convert string of hexadecimal number to a number.
Note that both versions of the code above does exactly the same thing as the line:
color = +("0x" + color.slice(1).replace(color.length < 5 && /./g, '$&$&'))

How to convert hex to decimal WITH A LOOP in JavaScript

Is it possible to convert a hex number to a decimal number with a loop?
Example: input "FE" output "254"
I looked at those questions :
How to convert decimal to hex in JavaScript?
Writing a function to convert hex to decimal
Writing a function to convert hex to decimal
Writing a function to convert hex to decimal
How to convert hex to decimal in R
How to convert hex to decimal in c#.net?
And a few more that were not related to JS or loops. I searched for a solution in other languages too in case that I find a way to do it,but I didn't. The first one was the most useful one. Maybe I can devide by 16,compare the result to preset values and print the result, but I want to try with loops. How can I do it?
Maybe you are looking for something like this, knowing that it can be done with a oneliner (with parseInt)?
function hexToDec(hex) {
var result = 0, digitValue;
hex = hex.toLowerCase();
for (var i = 0; i < hex.length; i++) {
digitValue = '0123456789abcdef'.indexOf(hex[i]);
result = result * 16 + digitValue;
}
return result;
}
console.log(hexToDec('FE'));
Alternative
Maybe you want to have a go at using reduce, and ES6 arrow functions:
function hexToDec(hex) {
return hex.toLowerCase().split('').reduce( (result, ch) =>
result * 16 + '0123456789abcdefgh'.indexOf(ch), 0);
}
console.log(hexToDec('FE'));
Just another way to do it...
// The purpose of the function is to convert Hex to Decimal.
// This is done by adding each of the converted values.
function hextoDec(val) {
// Reversed the order because the added values need to 16^i for each value since 'F' is position 1 and 'E' is position 0
var hex = val.split('').reverse().join('');
// Set the Decimal variable as a integer
var dec = 0;
// Loop through the length of the hex to iterate through each character
for (i = 0; i < hex.length; i++) {
// Obtain the numeric value of the character A=10 B=11 and so on..
// you could also change this to var conv = parseInt(hex[i], 16) instead
var conv = '0123456789ABCDEF'.indexOf(hex[i]);
// Calculation performed is the converted value * (16^i) based on the position of the character
// This is then added to the original dec variable. 'FE' for example
// in Reverse order [E] = (14 * (16 ^ 0)) + [F] = (15 * (16 ^ 1))
dec += conv * Math.pow(16, i);
}
// Returns the added decimal value
return dec;
}
console.log(hextoDec('FE'));
Sorry that was backwards, and I can't find where to edit answer, so here is corrected answer:
function doit(hex) {
var num = 0;
for(var x=0;x<hex.length;x++) {
var hexdigit = parseInt(hex[x],16);
num = (num << 4) | hexdigit;
}
return num;
}
If you want to loop over every hex digit, then just loop from end to beginning, shifting each digit 4 bits to the left as you add them (each hex digit is four bits long):
function doit(hex) {
var num = 0;
for(var x=0;x<hex.length;x++) {
var hexdigit = parseInt(hex[x],16);
num = (num << 4) | hexdigit;
}
return num;
}
JavaScript can natively count in hex. I'm finding out the hard way that, in a loop, it converts hex to decimal, so for your purposes, this is great.
prepend your hex with 0x , and you can directly write a for loop.
For example, I wanted get an array of hex values for these unicode characters, but I am by default getting an array of decimal values.
Here's sample code that is converting unicode hex to dec
var arrayOfEmojis = [];
// my range here is in hex format
for (var i=0x1F600; i < 0x1F64F; i++) {
arrayOfEmojis.push('\\u{' + i + '}');
}
console.log(arrayOfEmojis.toString()); // this outputs an array of decimals

JavaScript convert RGB integers to Hexadecimal [duplicate]

This question already has answers here:
RGB to hex and hex to RGB
(59 answers)
Closed 7 years ago.
I'm using Vivagraph JS library to render some graphs.
I would like to change the color of the node like this
nodeUI.color = 0xFFA500FF;
^ This is a random example. Not the corresponding hexadecimal value for RGB below
I get from server RGB values as an array like this
rgb = [229,64,51]
How do i convert RGB to the Hexadecimal type value metioned above?
Thanks
According to the comments in code here: https://github.com/anvaka/VivaGraphJS/blob/master/demos/other/webglCustomNode.html
The value 0xFFA500FF is a 32 bit value that includes an alpha channel, so ignoring the alpha channel it's equivalent to rgb(255,165,0).
Some functions to convert from 32 bit hex to 24 bit rgb and back are below, the comments should suffice to explain how they work.
/* #param {number} v - value to convert to RGB values
** #returns {Array} - three values for equivalent RGB triplet
** alpha channel is ingored
**
** e.g. from32toRGB(0xaec7e8) // 255,165,0
*/
function from32toRGB(v) {
var rgb = ('0000000' + v.toString(16)) // Convert to hex string with leading zeros
.slice(-8) // Get last 8 characters
.match(/../g) // Split into array of character pairs
.splice(0,3) // Get first three pairs only
.map(function(v) {return parseInt(v,16)}); // Convert each value to decimal
return rgb;
}
/* #param {Array} rgbArr - array of RGB values
** #returns {string} - Hex value for equivalent 32 bit color
** Alpha is always 1 (FF)
**
** e.g. fromRGBto32([255,165,0]) // aec7e8FF
**
** Each value is converted to a 2 digit hex string and concatenated
** to the previous value, with ff (alpha) appended to the end
*/
function fromRGBto32(rgbArr) {
return rgbArr.reduce(function(s, v) {
return s + ('0' + v.toString(16)).slice(-2);
},'') + 'ff'
}
// Tests for from32toRGB
[0xFFA500FF, 0xaec7e8ff,0,0xffffffff].forEach(function(v) {
document.write(v.toString(16) + ' : ' + from32toRGB(v) + '<br>')
});
document.write('<br>');
// Tests for fromRGBto32
[[255,165,0],[174,199,232], [0,0,0], [255,255,255]].forEach(function(rgbArr) {
document.write(rgbArr + ' : ' + fromRGBto32(rgbArr) + '<br>');
});
Note that in the assignment:
odeUI.color = 0xFFA500FF
the hex value 0xFFA500FF is immediately converted to decimal 11454440. To convert the result of fromRGBto32 to a number that can be assigned to odeUI.color, use parseInt:
parseInt(fromRGBto32([229,64,51]), 16);
or if you want to hard code it, just add '0x' in front.
If you have a string like 'rgb(229,64,51)', you can convert it to a hex value by getting the numbers, converting to hex strings and concatenating:
var s = 'rgb = [229,64,51]';
var hex = s.match(/\d+/g);
if (hex) {
hex = hex.reduce(function(acc, value) {
return acc + ('0' + (+value).toString(16)).slice(-2);
}, '#')
}
document.write(hex + '<br>');
// Append FF to make 32 bit and convert to decimal
// equivalent to 0xe54033ff
document.write(parseInt(hex.slice(-6) + 'ff', 16)); // 0xe54033ff -> 3846190079

JavaScript - Convert 24 digit hexadecimal number to decimal, add 1 and then convert back?

For an ObjectId in MongoDB, I work with a 24 digit hexadecimal number. Because I need to keep track of a second collection, I need to add 1 to this hexadecimal number.
In my case, here's my value
var value = "55a98f19b27585d81922ba0b"
What I'm looking for is
var newValue = "55a98f19b25785d81922ba0c"
I tried to create a function for this
function hexPlusOne(hex) {
var num = (("0x" + hex) / 1) + 1;
return num.toString(16);
}
This works with smaller hex numbers
hexPlusOne("eeefab")
=> "eeefac"
but it fails miserably for my hash
hexPlusOne(value)
=> "55a98f19b275840000000000"
Is there a better way to solve this?
This version will return a string as long as the input string, so the overflow is ignored in case the input is something like "ffffffff".
function hexIncrement(str) {
var hex = str.match(/[0-9a-f]/gi);
var digit = hex.length;
var carry = 1;
while (digit-- && carry) {
var dec = parseInt(hex[digit], 16) + carry;
carry = Math.floor(dec / 16);
dec %= 16;
hex[digit] = dec.toString(16);
}
return(hex.join(""));
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("ffffffffffffffffffffffff"));
This version may return a string which is 1 character longer than the input string, because input like "ffffffff" carries over to become "100000000".
function hexIncrement(str) {
var hex = str.match(/[0-9a-f]/gi);
var digit = hex.length;
var carry = 1;
while (digit-- && carry) {
var dec = parseInt(hex[digit], 16) + carry;
carry = Math.floor(dec / 16);
dec %= 16;
hex[digit] = dec.toString(16);
}
if (carry) hex.unshift("1");
return(hex.join(""));
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("ffffffffffffffffffffffff"));
I was curious te see whether user2864740's suggestion of working with 12-digit chunks would offer any advantage. To my surprise, even though the code looks more complicated, it's actually around twice as fast. But the first version runs 500,000 times per second too, so it's not like you're going to notice in the real world.
function hexIncrement(str) {
var result = "";
var carry = 1;
while (str.length && carry) {
var hex = str.slice(-12);
if (/^f*$/i.test(hex)) {
result = hex.replace(/f/gi, "0") + result;
carry = 1;
} else {
result = ("00000000000" + (parseInt(hex, 16) + carry).toString(16)).slice(-hex.length) + result;
carry = 0;
}
str = str.slice(0,-12);
}
return(str.toLowerCase() + (carry ? "1" : "") + result);
}
document.write(hexIncrement("55a98f19b27585d81922ba0b") + "<BR>");
document.write(hexIncrement("000000000000ffffffffffff") + "<BR>");
document.write(hexIncrement("0123456789abcdef000000000000ffffffffffff"));
The error comes from attempting to covert the entire 24-digit hex value to a number first because it won't fit in the range of integers JavaScript can represent distinctly2. In doing such a conversion to a JavaScript number some accuracy is lost.
However, it can be processed as multiple (eg. two) parts: do the math on the right part and then the left part, if needed due to overflow1. (It could also be processed one digit at a time with the entire addition done manually.)
Each chunk can be 12 hex digits in size, which makes it an easy split-in-half.
1 That is, if the final num for the right part is larger than 0xffffffffffff, simply carry over (adding) one to the left part. If there is no overflow then the left part remains untouched.
2 See What is JavaScript's highest integer value that a Number can go to without losing precision?
The range is 2^53, but the incoming value is 16^24 ~ (2^4)^24 ~ 2^(4*24) ~ 2^96; still a valid number, but outside the range of integers that can be distinctly represented.
Also, use parseInt(str, 16) instead of using "0x" + str in a numeric context to force the conversion, as it makes the intent arguably more clear.

How to convert decimal to hexadecimal in JavaScript

How do you convert decimal values to their hexadecimal equivalent in JavaScript?
Convert a number to a hexadecimal string with:
hexString = yourNumber.toString(16);
And reverse the process with:
yourNumber = parseInt(hexString, 16);
If you need to handle things like bit fields or 32-bit colors, then you need to deal with signed numbers. The JavaScript function toString(16) will return a negative hexadecimal number which is usually not what you want. This function does some crazy addition to make it a positive number.
function decimalToHexString(number)
{
if (number < 0)
{
number = 0xFFFFFFFF + number + 1;
}
return number.toString(16).toUpperCase();
}
console.log(decimalToHexString(27));
console.log(decimalToHexString(48.6));
The code below will convert the decimal value d to hexadecimal. It also allows you to add padding to the hexadecimal result. So 0 will become 00 by default.
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
function toHex(d) {
return ("0"+(Number(d).toString(16))).slice(-2).toUpperCase()
}
For completeness, if you want the two's-complement hexadecimal representation of a negative number, you can use the zero-fill-right shift >>> operator. For instance:
> (-1).toString(16)
"-1"
> ((-2)>>>0).toString(16)
"fffffffe"
There is however one limitation: JavaScript bitwise operators treat their operands as a sequence of 32 bits, that is, you get the 32-bits two's complement.
With padding:
function dec2hex(i) {
return (i+0x10000).toString(16).substr(-4).toUpperCase();
}
The accepted answer did not take into account single digit returned hexadecimal codes. This is easily adjusted by:
function numHex(s)
{
var a = s.toString(16);
if ((a.length % 2) > 0) {
a = "0" + a;
}
return a;
}
and
function strHex(s)
{
var a = "";
for (var i=0; i<s.length; i++) {
a = a + numHex(s.charCodeAt(i));
}
return a;
}
I believe the above answers have been posted numerous times by others in one form or another. I wrap these in a toHex() function like so:
function toHex(s)
{
var re = new RegExp(/^\s*(\+|-)?((\d+(\.\d+)?)|(\.\d+))\s*$/);
if (re.test(s)) {
return '#' + strHex( s.toString());
}
else {
return 'A' + strHex(s);
}
}
Note that the numeric regular expression came from 10+ Useful JavaScript Regular Expression Functions to improve your web applications efficiency.
Update: After testing this thing several times I found an error (double quotes in the RegExp), so I fixed that. HOWEVER! After quite a bit of testing and having read the post by almaz - I realized I could not get negative numbers to work.
Further - I did some reading up on this and since all JavaScript numbers are stored as 64 bit words no matter what - I tried modifying the numHex code to get the 64 bit word. But it turns out you can not do that. If you put "3.14159265" AS A NUMBER into a variable - all you will be able to get is the "3", because the fractional portion is only accessible by multiplying the number by ten(IE:10.0) repeatedly. Or to put that another way - the hexadecimal value of 0xF causes the floating point value to be translated into an integer before it is ANDed which removes everything behind the period. Rather than taking the value as a whole (i.e.: 3.14159265) and ANDing the floating point value against the 0xF value.
So the best thing to do, in this case, is to convert the 3.14159265 into a string and then just convert the string. Because of the above, it also makes it easy to convert negative numbers because the minus sign just becomes 0x26 on the front of the value.
So what I did was on determining that the variable contains a number - just convert it to a string and convert the string. This means to everyone that on the server side you will need to unhex the incoming string and then to determine the incoming information is numeric. You can do that easily by just adding a "#" to the front of numbers and "A" to the front of a character string coming back. See the toHex() function.
Have fun!
After another year and a lot of thinking, I decided that the "toHex" function (and I also have a "fromHex" function) really needed to be revamped. The whole question was "How can I do this more efficiently?" I decided that a to/from hexadecimal function should not care if something is a fractional part but at the same time it should ensure that fractional parts are included in the string.
So then the question became, "How do you know you are working with a hexadecimal string?". The answer is simple. Use the standard pre-string information that is already recognized around the world.
In other words - use "0x". So now my toHex function looks to see if that is already there and if it is - it just returns the string that was sent to it. Otherwise, it converts the string, number, whatever. Here is the revised toHex function:
/////////////////////////////////////////////////////////////////////////////
// toHex(). Convert an ASCII string to hexadecimal.
/////////////////////////////////////////////////////////////////////////////
toHex(s)
{
if (s.substr(0,2).toLowerCase() == "0x") {
return s;
}
var l = "0123456789ABCDEF";
var o = "";
if (typeof s != "string") {
s = s.toString();
}
for (var i=0; i<s.length; i++) {
var c = s.charCodeAt(i);
o = o + l.substr((c>>4),1) + l.substr((c & 0x0f),1);
}
return "0x" + o;
}
This is a very fast function that takes into account single digits, floating point numbers, and even checks to see if the person is sending a hex value over to be hexed again. It only uses four function calls and only two of those are in the loop. To un-hex the values you use:
/////////////////////////////////////////////////////////////////////////////
// fromHex(). Convert a hex string to ASCII text.
/////////////////////////////////////////////////////////////////////////////
fromHex(s)
{
var start = 0;
var o = "";
if (s.substr(0,2).toLowerCase() == "0x") {
start = 2;
}
if (typeof s != "string") {
s = s.toString();
}
for (var i=start; i<s.length; i+=2) {
var c = s.substr(i, 2);
o = o + String.fromCharCode(parseInt(c, 16));
}
return o;
}
Like the toHex() function, the fromHex() function first looks for the "0x" and then it translates the incoming information into a string if it isn't already a string. I don't know how it wouldn't be a string - but just in case - I check. The function then goes through, grabbing two characters and translating those in to ASCII characters. If you want it to translate Unicode, you will need to change the loop to going by four(4) characters at a time. But then you also need to ensure that the string is NOT divisible by four. If it is - then it is a standard hexadecimal string. (Remember the string has "0x" on the front of it.)
A simple test script to show that -3.14159265, when converted to a string, is still -3.14159265.
<?php
echo <<<EOD
<html>
<head><title>Test</title>
<script>
var a = -3.14159265;
alert( "A = " + a );
var b = a.toString();
alert( "B = " + b );
</script>
</head>
<body>
</body>
</html>
EOD;
?>
Because of how JavaScript works in respect to the toString() function, all of those problems can be eliminated which before were causing problems. Now all strings and numbers can be converted easily. Further, such things as objects will cause an error to be generated by JavaScript itself. I believe this is about as good as it gets. The only improvement left is for W3C to just include a toHex() and fromHex() function in JavaScript.
Without the loop:
function decimalToHex(d) {
var hex = Number(d).toString(16);
hex = "000000".substr(0, 6 - hex.length) + hex;
return hex;
}
// Or "#000000".substr(0, 7 - hex.length) + hex;
// Or whatever
// *Thanks to MSDN
Also isn't it better not to use loop tests that have to be evaluated?
For example, instead of:
for (var i = 0; i < hex.length; i++){}
have
for (var i = 0, var j = hex.length; i < j; i++){}
Combining some of these good ideas for an RGB-value-to-hexadecimal function (add the # elsewhere for HTML/CSS):
function rgb2hex(r,g,b) {
if (g !== undefined)
return Number(0x1000000 + r*0x10000 + g*0x100 + b).toString(16).substring(1);
else
return Number(0x1000000 + r[0]*0x10000 + r[1]*0x100 + r[2]).toString(16).substring(1);
}
Constrained/padded to a set number of characters:
function decimalToHex(decimal, chars) {
return (decimal + Math.pow(16, chars)).toString(16).slice(-chars).toUpperCase();
}
For anyone interested, here's a JSFiddle comparing most of the answers given to this question.
And here's the method I ended up going with:
function decToHex(dec) {
return (dec + Math.pow(16, 6)).toString(16).substr(-6)
}
Also, bear in mind that if you're looking to convert from decimal to hex for use in CSS as a color data type, you might instead prefer to extract the RGB values from the decimal and use rgb().
For example (JSFiddle):
let c = 4210330 // your color in decimal format
let rgb = [(c & 0xff0000) >> 16, (c & 0x00ff00) >> 8, (c & 0x0000ff)]
// Vanilla JS:
document.getElementById('some-element').style.color = 'rgb(' + rgb + ')'
// jQuery:
$('#some-element').css('color', 'rgb(' + rgb + ')')
This sets #some-element's CSS color property to rgb(64, 62, 154).
var number = 3200;
var hexString = number.toString(16);
The 16 is the radix and there are 16 values in a hexadecimal number :-)
function dec2hex(i)
{
var result = "0000";
if (i >= 0 && i <= 15) { result = "000" + i.toString(16); }
else if (i >= 16 && i <= 255) { result = "00" + i.toString(16); }
else if (i >= 256 && i <= 4095) { result = "0" + i.toString(16); }
else if (i >= 4096 && i <= 65535) { result = i.toString(16); }
return result
}
If you want to convert a number to a hexadecimal representation of an RGBA color value, I've found this to be the most useful combination of several tips from here:
function toHexString(n) {
if(n < 0) {
n = 0xFFFFFFFF + n + 1;
}
return "0x" + ("00000000" + n.toString(16).toUpperCase()).substr(-8);
}
AFAIK comment 57807 is wrong and should be something like:
var hex = Number(d).toString(16);
instead of
var hex = parseInt(d, 16);
function decimalToHex(d, padding) {
var hex = Number(d).toString(16);
padding = typeof (padding) === "undefined" || padding === null ? padding = 2 : padding;
while (hex.length < padding) {
hex = "0" + hex;
}
return hex;
}
And if the number is negative?
Here is my version.
function hexdec (hex_string) {
hex_string=((hex_string.charAt(1)!='X' && hex_string.charAt(1)!='x')?hex_string='0X'+hex_string : hex_string);
hex_string=(hex_string.charAt(2)<8 ? hex_string =hex_string-0x00000000 : hex_string=hex_string-0xFFFFFFFF-1);
return parseInt(hex_string, 10);
}
As the accepted answer states, the easiest way to convert from decimal to hexadecimal is var hex = dec.toString(16). However, you may prefer to add a string conversion, as it ensures that string representations like "12".toString(16) work correctly.
// Avoids a hard-to-track-down bug by returning `c` instead of `12`
(+"12").toString(16);
To reverse the process you may also use the solution below, as it is even shorter.
var dec = +("0x" + hex);
It seems to be slower in Google Chrome and Firefox, but is significantly faster in Opera. See http://jsperf.com/hex-to-dec.
I'm doing conversion to hex string in a pretty large loop, so I tried several techniques in order to find the fastest one. My requirements were to have a fixed-length string as a result, and encode negative values properly (-1 => ff..f).
Simple .toString(16) didn't work for me since I needed negative values to be properly encoded. The following code is the quickest I've tested so far on 1-2 byte values (note that symbols defines the number of output symbols you want to get, that is for 4-byte integer it should be equal to 8):
var hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
function getHexRepresentation(num, symbols) {
var result = '';
while (symbols--) {
result = hex[num & 0xF] + result;
num >>= 4;
}
return result;
}
It performs faster than .toString(16) on 1-2 byte numbers and slower on larger numbers (when symbols >= 6), but still should outperform methods that encode negative values properly.
Converting hex color numbers to hex color strings:
A simple solution with toString and ES6 padStart for converting hex color numbers to hex color strings.
const string = `#${color.toString(16).padStart(6, '0')}`;
For example:
0x000000 will become #000000
0xFFFFFF will become #FFFFFF
Check this example in a fiddle here
How to convert decimal to hexadecimal in JavaScript
I wasn't able to find a brutally clean/simple decimal to hexadecimal conversion that didn't involve a mess of functions and arrays ... so I had to make this for myself.
function DecToHex(decimal) { // Data (decimal)
length = -1; // Base string length
string = ''; // Source 'string'
characters = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' ]; // character array
do { // Grab each nibble in reverse order because JavaScript has no unsigned left shift
string += characters[decimal & 0xF]; // Mask byte, get that character
++length; // Increment to length of string
} while (decimal >>>= 4); // For next character shift right 4 bits, or break on 0
decimal += 'x'; // Convert that 0 into a hex prefix string -> '0x'
do
decimal += string[length];
while (length--); // Flip string forwards, with the prefixed '0x'
return (decimal); // return (hexadecimal);
}
/* Original: */
D = 3678; // Data (decimal)
C = 0xF; // Check
A = D; // Accumulate
B = -1; // Base string length
S = ''; // Source 'string'
H = '0x'; // Destination 'string'
do {
++B;
A& = C;
switch(A) {
case 0xA: A='A'
break;
case 0xB: A='B'
break;
case 0xC: A='C'
break;
case 0xD: A='D'
break;
case 0xE: A='E'
break;
case 0xF: A='F'
break;
A = (A);
}
S += A;
D >>>= 0x04;
A = D;
} while(D)
do
H += S[B];
while (B--)
S = B = A = C = D; // Zero out variables
alert(H); // H: holds hexadecimal equivalent
You can do something like this in ECMAScript 6:
const toHex = num => (num).toString(16).toUpperCase();
If you are looking for converting Large integers i.e. Numbers greater than Number.MAX_SAFE_INTEGER -- 9007199254740991, then you can use the following code
const hugeNumber = "9007199254740991873839" // Make sure its in String
const hexOfHugeNumber = BigInt(hugeNumber).toString(16);
console.log(hexOfHugeNumber)
To sum it all up;
function toHex(i, pad) {
if (typeof(pad) === 'undefined' || pad === null) {
pad = 2;
}
var strToParse = i.toString(16);
while (strToParse.length < pad) {
strToParse = "0" + strToParse;
}
var finalVal = parseInt(strToParse, 16);
if ( finalVal < 0 ) {
finalVal = 0xFFFFFFFF + finalVal + 1;
}
return finalVal;
}
However, if you don't need to convert it back to an integer at the end (i.e. for colors), then just making sure the values aren't negative should suffice.
I haven't found a clear answer, without checks if it is negative or positive, that uses two's complement (negative numbers included). For that, I show my solution to one byte:
((0xFF + number +1) & 0x0FF).toString(16);
You can use this instruction to any number bytes, only you add FF in respective places. For example, to two bytes:
((0xFFFF + number +1) & 0x0FFFF).toString(16);
If you want cast an array integer to string hexadecimal:
s = "";
for(var i = 0; i < arrayNumber.length; ++i) {
s += ((0xFF + arrayNumber[i] +1) & 0x0FF).toString(16);
}
In case you're looking to convert to a 'full' JavaScript or CSS representation, you can use something like:
numToHex = function(num) {
var r=((0xff0000&num)>>16).toString(16),
g=((0x00ff00&num)>>8).toString(16),
b=(0x0000ff&num).toString(16);
if (r.length==1) { r = '0'+r; }
if (g.length==1) { g = '0'+g; }
if (b.length==1) { b = '0'+b; }
return '0x'+r+g+b; // ('#' instead of'0x' for CSS)
};
var dec = 5974678;
console.log( numToHex(dec) ); // 0x5b2a96
This is based on Prestaul and Tod's solutions. However, this is a generalisation that accounts for varying size of a variable (e.g. Parsing signed value from a microcontroller serial log).
function decimalToPaddedHexString(number, bitsize)
{
let byteCount = Math.ceil(bitsize/8);
let maxBinValue = Math.pow(2, bitsize)-1;
/* In node.js this function fails for bitsize above 32bits */
if (bitsize > 32)
throw "number above maximum value";
/* Conversion to unsigned form based on */
if (number < 0)
number = maxBinValue + number + 1;
return "0x"+(number >>> 0).toString(16).toUpperCase().padStart(byteCount*2, '0');
}
Test script:
for (let n = 0 ; n < 64 ; n++ ) {
let s=decimalToPaddedHexString(-1, n);
console.log(`decimalToPaddedHexString(-1,${(n+"").padStart(2)}) = ${s.padStart(10)} = ${("0b"+parseInt(s).toString(2)).padStart(34)}`);
}
Test results:
decimalToPaddedHexString(-1, 0) = 0x0 = 0b0
decimalToPaddedHexString(-1, 1) = 0x01 = 0b1
decimalToPaddedHexString(-1, 2) = 0x03 = 0b11
decimalToPaddedHexString(-1, 3) = 0x07 = 0b111
decimalToPaddedHexString(-1, 4) = 0x0F = 0b1111
decimalToPaddedHexString(-1, 5) = 0x1F = 0b11111
decimalToPaddedHexString(-1, 6) = 0x3F = 0b111111
decimalToPaddedHexString(-1, 7) = 0x7F = 0b1111111
decimalToPaddedHexString(-1, 8) = 0xFF = 0b11111111
decimalToPaddedHexString(-1, 9) = 0x01FF = 0b111111111
decimalToPaddedHexString(-1,10) = 0x03FF = 0b1111111111
decimalToPaddedHexString(-1,11) = 0x07FF = 0b11111111111
decimalToPaddedHexString(-1,12) = 0x0FFF = 0b111111111111
decimalToPaddedHexString(-1,13) = 0x1FFF = 0b1111111111111
decimalToPaddedHexString(-1,14) = 0x3FFF = 0b11111111111111
decimalToPaddedHexString(-1,15) = 0x7FFF = 0b111111111111111
decimalToPaddedHexString(-1,16) = 0xFFFF = 0b1111111111111111
decimalToPaddedHexString(-1,17) = 0x01FFFF = 0b11111111111111111
decimalToPaddedHexString(-1,18) = 0x03FFFF = 0b111111111111111111
decimalToPaddedHexString(-1,19) = 0x07FFFF = 0b1111111111111111111
decimalToPaddedHexString(-1,20) = 0x0FFFFF = 0b11111111111111111111
decimalToPaddedHexString(-1,21) = 0x1FFFFF = 0b111111111111111111111
decimalToPaddedHexString(-1,22) = 0x3FFFFF = 0b1111111111111111111111
decimalToPaddedHexString(-1,23) = 0x7FFFFF = 0b11111111111111111111111
decimalToPaddedHexString(-1,24) = 0xFFFFFF = 0b111111111111111111111111
decimalToPaddedHexString(-1,25) = 0x01FFFFFF = 0b1111111111111111111111111
decimalToPaddedHexString(-1,26) = 0x03FFFFFF = 0b11111111111111111111111111
decimalToPaddedHexString(-1,27) = 0x07FFFFFF = 0b111111111111111111111111111
decimalToPaddedHexString(-1,28) = 0x0FFFFFFF = 0b1111111111111111111111111111
decimalToPaddedHexString(-1,29) = 0x1FFFFFFF = 0b11111111111111111111111111111
decimalToPaddedHexString(-1,30) = 0x3FFFFFFF = 0b111111111111111111111111111111
decimalToPaddedHexString(-1,31) = 0x7FFFFFFF = 0b1111111111111111111111111111111
decimalToPaddedHexString(-1,32) = 0xFFFFFFFF = 0b11111111111111111111111111111111
Thrown: 'number above maximum value'
Note: Not too sure why it fails above 32 bitsize
rgb(255, 255, 255) // returns FFFFFF
rgb(255, 255, 300) // returns FFFFFF
rgb(0,0,0) // returns 000000
rgb(148, 0, 211) // returns 9400D3
function rgb(...values){
return values.reduce((acc, cur) => {
let val = cur >= 255 ? 'ff' : cur <= 0 ? '00' : Number(cur).toString(16);
return acc + (val.length === 1 ? '0'+val : val);
}, '').toUpperCase();
}
Arbitrary precision
This solution take on input decimal string, and return hex string. A decimal fractions are supported. Algorithm
split number to sign (s), integer part (i) and fractional part (f) e.g for -123.75 we have s=true, i=123, f=75
integer part to hex:
if i='0' stop
get modulo: m=i%16 (in arbitrary precision)
convert m to hex digit and put to result string
for next step calc integer part i=i/16 (in arbitrary precision)
fractional part
count fractional digits n
multiply k=f*16 (in arbitrary precision)
split k to right part with n digits and put them to f, and left part with rest of digits and put them to d
convert d to hex and add to result.
finish when number of result fractional digits is enough
// #param decStr - string with non-negative integer
// #param divisor - positive integer
function dec2HexArbitrary(decStr, fracDigits=0) {
// Helper: divide arbitrary precision number by js number
// #param decStr - string with non-negative integer
// #param divisor - positive integer
function arbDivision(decStr, divisor)
{
// algorithm https://www.geeksforgeeks.org/divide-large-number-represented-string/
let ans='';
let idx = 0;
let temp = +decStr[idx];
while (temp < divisor) temp = temp * 10 + +decStr[++idx];
while (decStr.length > idx) {
ans += (temp / divisor)|0 ;
temp = (temp % divisor) * 10 + +decStr[++idx];
}
if (ans.length == 0) return "0";
return ans;
}
// Helper: calc module of arbitrary precision number
// #param decStr - string with non-negative integer
// #param mod - positive integer
function arbMod(decStr, mod) {
// algorithm https://www.geeksforgeeks.org/how-to-compute-mod-of-a-big-number/
let res = 0;
for (let i = 0; i < decStr.length; i++)
res = (res * 10 + +decStr[i]) % mod;
return res;
}
// Helper: multiply arbitrary precision integer by js number
// #param decStr - string with non-negative integer
// #param mult - positive integer
function arbMultiply(decStr, mult) {
let r='';
let m=0;
for (let i = decStr.length-1; i >=0 ; i--) {
let n = m+mult*(+decStr[i]);
r= (i ? n%10 : n) + r
m= n/10|0;
}
return r;
}
// dec2hex algorithm starts here
let h= '0123456789abcdef'; // hex 'alphabet'
let m= decStr.match(/-?(.*?)\.(.*)?/) || decStr.match(/-?(.*)/); // separate sign,integer,ractional
let i= m[1].replace(/^0+/,'').replace(/^$/,'0'); // integer part (without sign and leading zeros)
let f= (m[2]||'0').replace(/0+$/,'').replace(/^$/,'0'); // fractional part (without last zeros)
let s= decStr[0]=='-'; // sign
let r=''; // result
if(i=='0') r='0';
while(i!='0') { // integer part
r=h[arbMod(i,16)]+r;
i=arbDivision(i,16);
}
if(fracDigits) r+=".";
let n = f.length;
for(let j=0; j<fracDigits; j++) { // frac part
let k= arbMultiply(f,16);
f = k.slice(-n);
let d= k.slice(0,k.length-n);
r+= d.length ? h[+d] : '0';
}
return (s?'-':'')+r;
}
// -----------
// TESTS
// -----------
let tests = [
["0",2],
["000",2],
["123",0],
["-123",0],
["00.000",2],
["255.75",5],
["-255.75",5],
["127.999",32],
];
console.log('Input Standard Abitrary');
tests.forEach(t=> {
let nonArb = (+t[0]).toString(16).padEnd(17,' ');
let arb = dec2HexArbitrary(t[0],t[1]);
console.log(t[0].padEnd(10,' '), nonArb, arb);
});
// Long Example (40 digits after dot)
let example = "123456789012345678901234567890.09876543210987654321"
console.log(`\nLong Example:`);
console.log('dec:',example);
console.log('hex: ',dec2HexArbitrary(example,40));
The problem basically how many padding zeros to expect.
If you expect string 01 and 11 from Number 1 and 17. it's better to use Buffer as a bridge, with which number is turn into bytes, and then the hex is just an output format of it. And the bytes organization is well controlled by Buffer functions, like writeUInt32BE, writeInt16LE, etc.
import { Buffer } from 'buffer';
function toHex(n) { // 4byte
const buff = Buffer.alloc(4);
buff.writeInt32BE(n);
return buff.toString('hex');
}
> toHex(1)
'00000001'
> toHex(17)
'00000011'
> toHex(-1)
'ffffffff'
> toHex(-1212)
'fffffb44'
> toHex(1212)
'000004bc'
Here's my solution:
hex = function(number) {
return '0x' + Math.abs(number).toString(16);
}
The question says: "How to convert decimal to hexadecimal in JavaScript". While, the question does not specify that the hexadecimal string should begin with a 0x prefix, anybody who writes code should know that 0x is added to hexadecimal codes to distinguish hexadecimal codes from programmatic identifiers and other numbers (1234 could be hexadecimal, decimal, or even octal).
Therefore, to correctly answer this question, for the purpose of script-writing, you must add the 0x prefix.
The Math.abs(N) function converts negatives to positives, and as a bonus, it doesn't look like somebody ran it through a wood-chipper.
The answer I wanted, would have had a field-width specifier, so we could for example show 8/16/32/64-bit values the way you would see them listed in a hexadecimal editing application. That, is the actual, correct answer.

Categories