Can you check how similar a code is to another colour, If e.g. 0xFFFFFF is similar to 0xFBFBFB then change colour.
im not sure how the colour code works, so if you know a tip on the code, can you please share
A simple method to determinate proximity between colors, is to do so for each color component.
In AS3, a color is a number containing 3 components : red, green and blue (There's sometimes a fourth component for transparency - alpha)
Each component is contained in 1 byte, for a value of 0 to 255. (0x00 to 0xFF)
Here is a way to get each color component from the color itself :
var red:int = (color & 0xFF0000) >>> 16;
var green:int = (color & 0xFF00) >>> 8;
var blue:int = color & 0xFF;
Once you have the color components of each color, you can compare them 2 by 2, and combine the results:
var red_proximity = Math.abs(red1 - red2);
var green_proximity = Math.abs(green1 - green2);
var blue_proximity = Math.abs(blue1 - blue2);
var color_proximity = red_proximity + green_proximity + blue_proximity;
The result will be a number between 0 and 765; 0 meaning the color are exactly the same, and 765 meaning that they are completely differents.
(Note that I am using Math.abs() to ensure that the proximity values are always positive.)
The last step now is to choose a threshold value to determine if the colors are "too close". The chosen value is usually arbitrary, so test a few and take your pick. For the example, I'm using the value '84'.
if (color_proximity < 84) {
// color is too close : change it
} else {
// color is okay : do nothing ?
}
This is only one method, and if you have to play a lot with colors, search a bit on the web for other algorithm; It's always usefull.
Related
I'm wondering how to inverse the font color of a cell's value based on the background color automatically to make it readable.
I've used the following script to get the background color automatically set upon pasting hex color codes into given cells How do I change a cell to the color of the hexadecimal value of a cell in Google Spreadsheets?, with sample sheet here
function onEdit(e) {
r = e.range;
if(r.getSheet().getSheetName() == "colors"){ //the sheet I want to apply this to is called colors
var rows = r.getNumRows();
var columns = r.getNumColumns();
var colors = [] //this is our 2 dimensional array of colors in case you copy and paste a large amount of colors
for (var i = 1; i <= rows; i++) { //go down each row
var row = [] //create a new row array to clear the old one when we go down a row
for (var j = 1; j <= columns; j++) { //then go across each column
row.push(r.getCell(i,j).getValue()) //put together the row of colors
}
colors.push(row); //insert our row of colors so we can go down the next row
}
r.setBackgrounds(colors) //batch update in case you update many colors in one copy and paste otherwise it will be very slow
}
}
but the remaining issue is the font is not showing on the dark background cells.
I've also found this related question How to decide font color in white or black depending on background color?.
And those Javascript specific answers with functions, but I've not been able to make them work with the above script in GAS.
JavaScript code 1
JavaScript code 2
JavaScript code 3
JavaScript code 4
JavaScript code 5
JavaScript code 6
I've also looked into the documentation for setFontColors(colors) and saw we could use the method r.setFontColors(colors) in the script above.
I tried calling the JavaScript codes 1 to 6 above, but I'm not succeeding.
For example, I've tried this way based on JavaScript code 3 ):
function onEdit(e) {
r = e.range;
if(r.getSheet().getSheetName() == "colors"){ //the sheet I want to apply this to is called colors
var rows = r.getNumRows();
var columns = r.getNumColumns();
var colors = [] //this is our 2 dimensional array of colors in case you copy and paste a large amount of colors
for (var i = 1; i <= rows; i++) { //go down each row
var row = [] //create a new row array to clear the old one when we go down a row
for (var j = 1; j <= columns; j++) { //then go across each column
row.push(r.getCell(i,j).getValue()) //put together the row of colors
}
colors.push(row); //insert our row of colors so we can go down the next row
}
r.setBackgrounds(colors) //batch update in case you update many colors in one copy and paste otherwise it will be very slow
r.setFontColors(lum([111, 22, 255]));
}
}
function lum(rgb) {
var lrgb = [];
rgb.forEach(function(c) {
c = c / 255.0;
if (c <= 0.03928) {
c = c / 12.92;
} else {
c = Math.pow((c + 0.055) / 1.055, 2.4);
}
lrgb.push(c);
});
var lum = 0.2126 * lrgb[0] + 0.7152 * lrgb[1] + 0.0722 * lrgb[2];
return (lum > 0.179) ? '#000000' : '#ffffff';
}
What am I missing?
Thanks for your insights!
I believe your goal is as follows.
When the hex values are put to the cells, you want to set the background color using the inputted hex values. At that time, you want to set the font colors for each cell depending on the background colors.
Modification points:
In your script, I think that the value of colors can be retrieved by r.getValues(). In this case, the for loop is not required to be used.
From r.setFontColors(lum([111, 22, 255]));, When you want to set the same font colors to the range, you can modify as follows.
From
r.setFontColors(lum([111, 22, 255]));
To
r.setFontColor(lum([111, 22, 255]));
But, from your script, I thought that you might want to set the font colors by each background color. If my understanding is correct, how about the following modification?
Modified script:
// I modified this function.
function onEdit(e) {
var r = e.range;
if (r.getSheet().getSheetName() == "colors") {
var colors = r.getValues();
r.setBackgrounds(colors);
var fonrColors = r.getBackgroundObjects().map(r => r.map(c => {
var obj = c.asRgbColor();
return lum([obj.getRed(), obj.getGreen(), obj.getBlue()]);
}))
r.setFontColors(fonrColors);
}
}
// This is from your script.
function lum(rgb) {
var lrgb = [];
rgb.forEach(function (c) {
c = c / 255.0;
if (c <= 0.03928) {
c = c / 12.92;
} else {
c = Math.pow((c + 0.055) / 1.055, 2.4);
}
lrgb.push(c);
});
var lum = 0.2126 * lrgb[0] + 0.7152 * lrgb[1] + 0.0722 * lrgb[2];
return (lum > 0.179) ? '#000000' : '#ffffff';
}
In this modification, in order to convert the hex to RGB, I used the method of getBackgroundObjects(). Of course, you can convert this using Javascript. If you don't want to use getBackgroundObjects(), please check this thread
In this modification, when you put the hex values to the cells, the background colors are set using the hex values, and the font colors are set depending on the background colors using the function lum of your script.
References:
getBackgroundObjects()
Related thread.
RGB to hex and hex to RGB
Required parameter of setFontColors is a 2d array
Try to change r.setFontColors(lum([111, 22, 255])); into the following codes:
const fontColor = lum([111, 22, 255]);
const fontColorsRow = new Array(columns).fill(fontColor);
const fontColors = new Array(rows).fill(fontColorsRow);
r.setFontColors(fontColors);
Reference:
setFontColors(colors)
Short Answer
To flip the text color between black or white based on the background color, You need to convert the background color to the luminance, and choose a specific luminance value to flip, typically about 0.37 Y works well.
Longer Answer
The reality is there are a number of psychophysical factors that affect the best point to flip from black or white text, and they are not all about the specific color. Font size and weight, and the surrounding colors, and the ambient lighting in the room all affect the "ideal flip point."
I discuss this in another answer on overflow with simple code snippets. After that answer, I also created a CodePen with live examples you can play with.
The "super simple down and dirty" is:
// First convert your sRGB values to luminance:
let sY = Math.pow(sR/255.0,2.2) * 0.2126 +
Math.pow(sG/255.0,2.2) * 0.7152 +
Math.pow(sB/255.0,2.2) * 0.0722; // Andy's Easy Luminance for sRGB. For Rec709 HDTV change the 2.2 to 2.4
// AND THEN SET THE TEXT COLOR PER:
let textColor = (sY < 0.37) ? "#fff" : "#000"; // Low budget down and dirty text flipper.
That's the minimum, simplest bit of code that should be easy to port. I'm not familiar with Google script, but basically you just need to divide each 8 bit color by 255.0, then apply 2.2 exponent, then multiply by the coefficient (0.2126 for red, 0.7152 for green, 0.0722 for blue) and sum together.
Flip at about 0.4 - the flippable range is about 0.36 to 0.43 ish, depending.
And if you really want to dive into the nitty gritty world of contrast of text for readability, check out the APCA and SAPC — at the SAPC dev site click on "research mode" to play with interactive experiments that demonstrate the concepts. These are new methods for determining contrast on self illuminated displays.
i am new to Actionscript and I need help changing the colour of an object which is called with add child, i need the colour to change once the user has selected the desired colour they want from a combo box:
//MY CODE
if (e.target.value == "blue")
{
//need to change to this (0x0000FF)
//enter code here
}
Any help much appreciated!
Try using the color transform object.
var redAmount:Number = 0;
var greenAmount:Number = 0;
var blueAmount:Number = 1;
var alphaAmount:Number = 1;
var redOffset:Number = 0;
var greenOffset:Number = 0;
var blueOffset:Number = 0;
var alphaOffset:Number = 0;
yourDisplayObject.transform.colorTransform = new ColorTransform(redAmount, greenAmount, blueAmount, alphaAmount, redOffset, greeenOffset, blueOffset, alphaOffset);
The first four variables are multipliers - they will take the existing color value and adjust it as if multiplying by that number. So to reduce a color by 1/2 use 0.5. To make black set all to 0. To change nothing make all 1's.
The second four variables will increase or decrease the color amount of all pixels by that amount. So to make a color hit a specific hex value, say 0xFFCC33, you would do this:
yourDisplayObject.transform.colorTransform = new ColorTransform(0, 0, 0, 1, 0xFF, 0xCC, 0x33, 0x00);
Here is a link to the adobe documentation if you need more help:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/geom/ColorTransform.html
If you decide you want to change the color gradually instead of instantly take a look at TweenMax from greensock. The greensock tween classes are a widely used workhorse of actionscript programming.
To tint a display object with TweenMax the code would be:
TweenMax.to(yourDisplayObject, 1, {tint:0x0000FF});
This class applies a color transform to the object using that code, but it changes the values gradually over time
Here is a link to where you can get TweenMax.
http://www.greensock.com/tweenmax/
Here is the easiest to understand (as I see it anyway) way to accomplish this:
if (e.target.value == "blue")
{
var colorTransform:ColorTransform = yourObject.transform.colorTransform; //store the current color data for the object
colorTransform.color = 0x0000FF; //make it totally blue
yourObject.transform.colorTransform = colorTransform; //now assign it back to the object
}
I'm trying to replace a color and colors near it in a bitmap.
threshold() seems to work but it seems to be that you have to specify the exact color "==" or all colors before or after the exact color "<" & ">" plus "<=" and ">=". I am hoping that the mask parameter will help me find a way to find a color and a dynamic range of colors before and after it to be replaced. What is its intended usage?
Per the comment below Example 1 and 2:
bit.threshold(bit, bit.rect, point, ">", 0xff000000, 0xffff0000, 0x00FF0000);
bit.threshold(bit, bit.rect, point, ">", 0xff000000, 0xffff0000, 0x00EE0000);
If you're trying to do a flood fill, I don't think the mask parameter will help you. The mask parameter lets you ignore parts of the color in the test. In your case, you want to take into account all the channels of the color, you just want the matching to be fuzzy.
e.g. If you want to replace all pixels where the red component is 0, you can set mask to 0x00FF0000, so it will ignore the other channels.
The implementation pseudo-code probably looks something like this:
input = readPixel()
value = input & mask
if(value operation threshold)
{
writePixel(color)
}
Neither of your samples will produce anything because the mask limits the values to be between 0x00000000 and 0x00FF0000, then tests if they're greater than 0xFF000000.
I have also done this and eventually, I have found it best to create my own threshold-method. You can find it below. Everything is explained in comment.
//_snapshot is a bitmapData-object
for(var i:int = 0; i <= _snapshot.width; i++)
{
for(var j:int = 0; j <= _snapshot.height; j++)
{
//We get the color of the current pixel.
var _color:uint = _snapshot.getPixel(i, j);
//If the color of the selected pixel is between certain values set by the user,
//set the filtered pixel data to green.
//Threshold is a number (can be quite high, up to 50000) to look for adjacent colors in the colorspace.
//_colorToCompare is the color you want to look for.
if((_colorToCompare - (100 * _threshold)) <= _color && _color <= (_colorToCompare + (100 * _threshold)))
{
//This sets the pixel value.
_snapshot.setPixel(i, j, 0x00ff00);
}
else
{
//If the pixel color is not within the desired range, set it's value to black.
_snapshot.setPixel(i, j, 0x000000);
}
}
}
In Canvas/HTML5, I know you can use RGBA to set color and alpha transparency for fillStyle or strokeStyle. You can also use just RGB to set color with no alpha channel. is there a way you can change the alpha value of an item without also supplying the color.
My example would be wanting to change the fillStyle or strokeStyle above a canvas section whose color was random or no longer known. Is there a way to change the alpha through another attribute or by passing nothing to the color (e.g. ctx.fillStyle = 'rgba(,,,alphaValue)';)
There are a few ways.
First, the globalAlpha attribute of the context.
As you ask in the title, it will allow transparency to be set independently of fill or stroke.
You could then use the getImageData on a point to find out the color and save that info, clear that area with clearRect, set globalAlpha, and then redraw that area with the color you saved.
Of course, you don't need globalAlpha at all. You could also do the above and instead of setting global alpha, just modify the alpha of the color that you saved.
If you want to make a large, complex area of canvas more transparent, then you will want to change the globalAlpha and then draw the canvas onto itself using drawImage.
Here's an example of that. I draw two rectangles, then make a rectangular area between them more transparent.
You can use a function to extract the RGB values from whatever is set for the style you are interested in, and then set it with the desired alpha:
var rgb = hexToRgb(canvasCtx.fillStyle);
canvasCtx.fillStyle = "rgba(" + rgb["r"] + "," +rgb["g"] + "," + rgb["b"] + ",0.2)";
You can use an hexToRgb function like this one, taken from this other answer:
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
I have a whole bunch of jpg files that I need to use in a project, that for one reason or another cannot be altered. Each file is similar (handwriting), black pen on white BG. However I need to use these assets against a non-white background in my flash project, so I'm trying to do some client-side processing to get rid of the backgrounds using getPixel and setPixel32.
The code I am currently using currently uses a linear comparison, and while it works, the results are less than expected, as the shades of grey are getting lost in the mix. Moreso than just tweaking my parameters to get things looking proper, I get the feeling that my method for computing the RGBa value is weak.
Can anyone recommend a better solution than what I'm using below? Much appreciated!
private function transparify(data:BitmapData) : Bitmap {
// Create a new BitmapData with transparency to return
var newData:BitmapData = new BitmapData(data.width, data.height, true);
var orig_color:uint;
var alpha:Number;
var percent:Number;
// Iterate through each pixel using nested for loop
for(var x:int = 0; x < data.width; x++){
for (var y:int = 0; y < data.height; y++){
orig_color = data.getPixel(x,y);
// percent is the opacity percentage, white should be 0,
// black would be 1, greys somewhere in the middle
percent = (0xFFFFFF - orig_color)/0xFFFFFF;
// To get the alpha value, I multiply 256 possible values by
// my percentage, which gets multiplied by 0xFFFFFF to fit in the right
// value for the alpha channel
alpha = Math.round(( percent )*256)*0xFFFFFF;
// Adding the alpha value to the original color should give me the same
// color with an alpha channel added
var newCol = orig_color+alpha;
newData.setPixel32(x,y,newCol);
}
}
var newImg:Bitmap = new Bitmap(newData);
return newImg;
}
Since it's a white background, blendMode may give you a better result.