What is a "valid IM color"? - graphics

I found the following documentation in a bash script written for use with some software named, "imagemagick"
# USAGE: multicrop2 [-c coords] [-b bcolor] [more options, blah blah,...]
# [... snip ...]
# -b bcolor background color to use instead of option -c;
# any valid IM color; default is to use option -c
I cannot fathom what the code author considered to be a "valid IM color." I am guessing that "IM" is simply an abbreviation of "image," but perhaps "instant messaging," or something else was meant. What do you think?
A hex code for RGB would have blue in the lower byte, green in the middle byte, and red in the upper byte, but I am not sure whether they use standard RGB encoding for colors or not.

Multicrop2 is my script. A valid ImageMagick color is any color scheme that ImageMagick recognizes, such as rgb, hex, cmyk, hsl, and even color names in the format specified in its documentation and especially at http://www.imagemagick.org/script/color.php. There are too many to list in my script. Often I refer to this link, but apparently in this case I did not. But most ImageMagick users are aware of its typical color schemes. ImageMagick users mostly know that IM is an abbreviation for ImageMagick. Colors follow the CSS stye guide for the most part. Colors with #, spaces or parentheses, need to be quoted, at least on Unix-like systems. Color names do not need quoting. Apologies to newbies to my scripts and ImageMagick.
Examples:
rgb(255, 0, 0) range 0 - 255
rgba(255, 0, 0, 1.0) the same, with an explicit alpha value
rgb(100%, 0%, 0%) range 0.0% - 100.0%
rgba(100%, 0%, 0%, 1.0) the same, with an explicit alpha value
#ff0000 #rrggbb
#ff0000ff #rrggbbaa
gray50 near mid gray
gray(127) near mid gray
gray(50%) mid gray
graya(50%, 0.5) semi-transparent mid gray
hsb(120, 100%, 100%) full green in hsb
hsba(120, 100%, 100%, 1.0) the same, with an alpha value of 1.0
hsb(120, 255, 255) full green in hsb
hsba(120, 255, 255, 1.0) the same, with an alpha value of 1.0
hsl(120, 100%, 50%) full green in hsl
hsla(120, 100%, 50%, 1.0) the same, with an alpha value of 1.0
hsl(120, 255, 127.5) full green in hsl
hsla(120, 255, 127.5, 1.0) the same, with an alpha value of 1.0
cielab(62.253188, 23.950124, 48.410653)
icc-color(cmyk, 0.11, 0.48, 0.83, 0.00) cymk
icc-color(rgb, 1, 0, 0) linear rgb
icc-color(rgb, red) linear rgb
icc-color(lineargray, 0.5) linear gray
icc-color(srgb, 1, 0, 0) non-linear rgb
icc-color(srgb, red) non-linear rgb
icc-color(gray, 0.5) non-linear gray

Related

Is widely used porter-duff formula for source-over on non-premultiplied (straight) alpha wrong?

I am looking for a formula to draw rgba color over rgba background, and it seems to me, that widely used formula for non-premultiplied alpha has an unexpected side-effect when both the underlying (background) and source (foreground) is non-opaque.
The formula, as cited eg. in Win2D for WinUI3 is
To perform a source-over blend between two colors that use straight alpha format:
result = (source.RGB * source.A) + (dest.RGB * (1 - source.A))
However, if we are blending eg. partially transparent blue over a red color with zero alpha, the red color will show up in the result.
destination = rgba(1, 0, 0, 0)
source = rgba(0, 0, 1, 0.5)
resultRed = (source.R * source.A) + (dest.R * (1 - source.A)) = (0 * 0.5) + (1 * (1 - 0.5)) = 0 + 0.5 = 0.5 - the result has a strong red component, even though we are blending blue over 'empty' image.
I haven't found any source that would discuss this or offer alternative formula, short of premultiplying the source colors, doing the porter-duff src-over, and then trying to convert back from premultiplied space, which is a lossy and slow operation.
Do you have a solution for a more natural blend (eg. that would produce partially transparent blue in the above case) operation in non-premultiplied space?

Don't understand hsv color palette

i test a lot converters hex to hsv rgb to hsv and other options. But don't understand situation i have paint program which i see use HSV palette. i use TinyColor converter. I don't know why i sometimes get good color, sometimes not good.
This return good result red color:
var color = tinycolor("#FF0000"); //red
color.toHsv(); // return { h: 0, s: 1, v: 1 }
This return bad result not yellow color:
var color = tinycolor("#FFFF00"); //yellow
color.toHsv(); // return { h: 60, s: 1, v: 1 } and i get not yellow color
If i write in my hsv input like this:
h: 0.16
s: 1
v: 1
i get yellow collor WTF?
I see in my HSV palette i can write only one digit numbers like this:
1, 0.1, 0.99, max is 1 min is 0.00
Hue, the h in hsv, is traditionally expressed in degrees around a circle — the color wheel, which means it can have a value from 0º - 360º. See: http://en.wikipedia.org/wiki/Hue
It is sometimes convenient to express this as a percentage instead where 0= 0º, 0.5 = 180º, 1.0 = 360º, etc. The documentation for TinyColor explains that it will accept either input, but it is not clear what its default output is (at least from my quick scan).
It seem to be returning degrees, but your other application is expecting a percentage. A 60º hue is yellow, but you may need need to convert to a percentage for whatever application you're using with the hsv palette.
In this particular case, 60º/360º = 0.1667

RGBA Alpha Value

So with RGBA, you set the alpha with the last attribute. However, I have seen people set the alpha as 255 to get it at 100% when I always thought the correct way was to set it to 1?
What I'm trying to say is this:
rgba(0, 0, 0, 120) // What they did
rgba(0, 0, 0, 0.47) // What I would do.
From what I can see, they do the same thing. Is there a "correct" way of doing it?
The type we usually use to represent the RGBA information should be an 4 bytes integer. 0x00000000 these four bytes represent red green blue alpha (or red blue green alpha) respectively.
So the "Correct" way is to set the last byte to be 255, if you want the alpha to be 1.
However, in some libraries or languages there are 2 interfaces to set the last byte to be 255:
rgba(int,int,int,int)
and
rgba(int,int,int,float)
So, that depends!
You should find out the interface in the documentation!
Hope this can help you!

Given an RGB value, how do I create a tint (or shade)?

Given an RGB value, like 168, 0, 255, how do I create tints (make it lighter) and shades (make it darker) of the color?
Among several options for shading and tinting:
For shades, multiply each component by 1/4, 1/2, 3/4, etc., of its
previous value. The smaller the factor, the darker the shade.
For tints, calculate (255 - previous value), multiply that by 1/4,
1/2, 3/4, etc. (the greater the factor, the lighter the tint), and add that to the previous value (assuming each.component is a 8-bit integer).
Note that color manipulations (such as tints and other shading) should be done in linear RGB. However, RGB colors specified in documents or encoded in images and video are not likely to be in linear RGB, in which case a so-called inverse transfer function needs to be applied to each of the RGB color's components. This function varies with the RGB color space. For example, in the sRGB color space (which can be assumed if the RGB color space is unknown), this function is roughly equivalent to raising each sRGB color component (ranging from 0 through 1) to a power of 2.2. (Note that "linear RGB" is not an RGB color space.)
See also Violet Giraffe's comment about "gamma correction".
Some definitions
A shade is produced by "darkening" a hue or "adding black"
A tint is produced by "ligthening" a hue or "adding white"
Creating a tint or a shade
Depending on your Color Model, there are different methods to create a darker (shaded) or lighter (tinted) color:
RGB:
To shade:
newR = currentR * (1 - shade_factor)
newG = currentG * (1 - shade_factor)
newB = currentB * (1 - shade_factor)
To tint:
newR = currentR + (255 - currentR) * tint_factor
newG = currentG + (255 - currentG) * tint_factor
newB = currentB + (255 - currentB) * tint_factor
More generally, the color resulting in layering a color RGB(currentR,currentG,currentB) with a color RGBA(aR,aG,aB,alpha) is:
newR = currentR + (aR - currentR) * alpha
newG = currentG + (aG - currentG) * alpha
newB = currentB + (aB - currentB) * alpha
where (aR,aG,aB) = black = (0,0,0) for shading, and (aR,aG,aB) = white = (255,255,255) for tinting
HSV or HSB:
To shade: lower the Value / Brightness or increase the Saturation
To tint: lower the Saturation or increase the Value / Brightness
HSL:
To shade: lower the Lightness
To tint: increase the Lightness
There exists formulas to convert from one color model to another. As per your initial question, if you are in RGB and want to use the HSV model to shade for example, you can just convert to HSV, do the shading and convert back to RGB. Formula to convert are not trivial but can be found on the internet. Depending on your language, it might also be available as a core function :
RGB to HSV color in javascript?
Convert RGB value to HSV
Comparing the models
RGB has the advantage of being really simple to implement, but:
you can only shade or tint your color relatively
you have no idea if your color is already tinted or shaded
HSV or HSB is kind of complex because you need to play with two parameters to get what you want (Saturation & Value / Brightness)
HSL is the best from my point of view:
supported by CSS3 (for webapp)
simple and accurate:
50% means an unaltered Hue
>50% means the Hue is lighter (tint)
<50% means the Hue is darker (shade)
given a color you can determine if it is already tinted or shaded
you can tint or shade a color relatively or absolutely (by just replacing the Lightness part)
If you want to learn more about this subject: Wiki: Colors Model
For more information on what those models are: Wikipedia: HSL and HSV
I'm currently experimenting with canvas and pixels... I'm finding this logic works out for me better.
Use this to calculate the grey-ness ( luma ? )
but with both the existing value and the new 'tint' value
calculate the difference ( I found I did not need to multiply )
add to offset the 'tint' value
var grey = (r + g + b) / 3;
var grey2 = (new_r + new_g + new_b) / 3;
var dr = grey - grey2 * 1;
var dg = grey - grey2 * 1
var db = grey - grey2 * 1;
tint_r = new_r + dr;
tint_g = new_g + dg;
tint_b = new_b _ db;
or something like that...

Why doesn't the alpha pixel in html canvas blend in with the background color?

http://jsfiddle.net/jBgqW/
I've painted the background with fillRect and fillStyle set to rgb(255,0,0) but when I iterate through the pixels and set some random color and value of the alpha pixel to 0 everything becomes white. I've assumed that when the pixel is transparent it should blend with the previously painted background color or does it always default to white.
I hope that it's just my wrong way of using the canvas.
Can anyone explain why the background isn't red in this case and how do i use the alpha pixel properly? I would like to know if this has something to do with the alpha premultiplication.
When using globalAlpha, the pixel colors are calculated with the current rgba values and the new values.
However, in this case you're setting the values manually and therefore doing no calculations. You're just setting the rgba values yourself, which means that the alpha channel is not used for calculating but is just altered without further use. The previous color (red) is basically overwritten in a 'brute force' way - instead of rgba(255, 0, 0, 255), it's now just rgba(128, 53, 82, 0). The original red color has simply been thrown away.
As a result, an alpha of 0 represents complete transparency, so you see the colors of the parent element.
This can be confirmed if you change the body background color: http://jsfiddle.net/jBgqW/2/.
This is somewhat thread necromancy, but I've just faced this problem and have a solution to it, if not for the original poster then for people like me coming from google.
As noted, putImageData directly replaces pixels rather than alpha blends, but that also means it preserves your alpha data. You can then redraw that image with alpha blending using drawImage.
To give an example, lets says we have a canvas that is 200 by 100 pixels and a 100 by 100 imageData object.
// our canvas
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
// our imageData, created in whatever fashion, with alpha as appropriate...
var data = /* ... */
// lets make the right half of our canvas blue
ctx.fillStyle="blue";
ctx.rect(100, 0, 100, 100);
ctx.fill();
// now draw our image data to the left (white) half, pixels are replaced
ctx.putImageData(data, 0, 0, 100, 100);
// now the magic, draw the canvas to itself with clipping
ctx.drawImage(canvas, 100, 0, 100, 100, 100, 0, 100, 100);
Voila. The right half of the image is now your image data blended with the blue background, rendered with hardware assistance.

Resources