Issues with "-colorspace sRGB"

Post any defects you find in the released or beta versions of the ImageMagick software here. Include the ImageMagick version, OS, and any command-line required to reproduce the problem. Got a patch for a bug? Post it here.
Post Reply
Drarakel
Posts: 547
Joined: 2010-04-07T12:36:59-07:00
Authentication code: 8675308

Issues with "-colorspace sRGB"

Post by Drarakel » 2010-09-27T14:40:11-07:00

I think I finally have understood what "-colorspace sRGB" tries to do. :)
But I think it's more the opposite of what the name implies. The name implies that something is converted to sRGB.. But actually, one should take a sRGB image as input and (theoretically) can convert that to linear RGB space with the command. So, it's NOT sRGB anymore after that. Is that correct? Or are there other meanings with that command?
But even if there are - this option doesn't work correctly:


1) The formula from the documentation says that normalized values below 0.03928 are transformed linearly with "value/12.92". But this is not done and these values (values 10 and below - in 8bit images) are clipped to zero. Or perhaps this part of the transformation isn't done with 16bit (or more) precision. Example - the result with a current Q16 version of IM:

Code: Select all

convert -depth 8 -size 1x256 gradient: -colorspace sRGB -gravity south -crop 1x15+0+0 +repage -depth 16 txt:-
# ImageMagick pixel enumeration: 1,15,65535,srgb
0,0: ( 288, 288, 288) #012001200120 srgb(0.43946%,0.43946%,0.43946%)
0,1: ( 264, 264, 264) #010801080108 srgb(0.402838%,0.402838%,0.402838%)
0,2: ( 241, 241, 241) #00F100F100F1 srgb(0.367742%,0.367742%,0.367742%)
0,3: ( 219, 219, 219) #00DB00DB00DB srgb(0.334173%,0.334173%,0.334173%)
0,4: ( 0, 0, 0) #000000000000 black
0,5: ( 0, 0, 0) #000000000000 black
0,6: ( 0, 0, 0) #000000000000 black
0,7: ( 0, 0, 0) #000000000000 black
0,8: ( 0, 0, 0) #000000000000 black
0,9: ( 0, 0, 0) #000000000000 black
0,10: ( 0, 0, 0) #000000000000 black
0,11: ( 0, 0, 0) #000000000000 black
0,12: ( 0, 0, 0) #000000000000 black
0,13: ( 0, 0, 0) #000000000000 black
0,14: ( 0, 0, 0) #000000000000 black


The correct result with IM's formula should be:

Code: Select all

convert -depth 8 -size 1x256 gradient: -fx "(p>0.03928) ? pow((p+0.055)/1.055,2.4) : p/12.92" -gravity south -crop 1x15+0+0 +repage -depth 16 txt:-
# ImageMagick pixel enumeration: 1,15,65535,rgb
0,0: ( 288, 288, 288) #012001200120 rgb(0.43946%,0.43946%,0.43946%)
0,1: ( 264, 264, 264) #010801080108 rgb(0.402838%,0.402838%,0.402838%)
0,2: ( 241, 241, 241) #00F100F100F1 rgb(0.367742%,0.367742%,0.367742%)
0,3: ( 219, 219, 219) #00DB00DB00DB rgb(0.334173%,0.334173%,0.334173%)
0,4: ( 199, 199, 199) #00C700C700C7 rgb(0.303655%,0.303655%,0.303655%)
0,5: ( 179, 179, 179) #00B300B300B3 rgb(0.273136%,0.273136%,0.273136%)
0,6: ( 159, 159, 159) #009F009F009F rgb(0.242618%,0.242618%,0.242618%)
0,7: ( 139, 139, 139) #008B008B008B rgb(0.2121%,0.2121%,0.2121%)
0,8: ( 119, 119, 119) #007700770077 rgb(0.181582%,0.181582%,0.181582%)
0,9: ( 99, 99, 99) #006300630063 rgb(0.151064%,0.151064%,0.151064%)
0,10: ( 80, 80, 80) #005000500050 rgb(0.122072%,0.122072%,0.122072%)
0,11: ( 60, 60, 60) #003C003C003C rgb(0.0915541%,0.0915541%,0.0915541%)
0,12: ( 40, 40, 40) #002800280028 rgb(0.0610361%,0.0610361%,0.0610361%)
0,13: ( 20, 20, 20) #001400140014 rgb(0.030518%,0.030518%,0.030518%)
0,14: ( 0, 0, 0) #000000000000 black

(By the way: The inverse operation - from a linear space back to the sRGB space with "-set colorspace sRGB -colorspace RGB" hasn't such an error.)


2) The transition from the linear transformation to the power function (((value+.055)/1.055)^2.4) is done at value 0.03928 at the moment. I think, the value 0.04045 would be more correct.
The background for that: http://en.wikipedia.org/wiki/SRGB#Theor ... sformation
And 0.04045 is also the value that is used with the common "sRGB IEC61966-2.1" profile. (According to Wikipedia - but I don't think that it's wrong here.)
It doesn't make a difference with 8bit images, but with 16bit images (or a higher channel bit depth).


3) Additional thoughts: I wonder if these transformations within RGB really need to be colorspace conversions? Perhaps general options could be used for this? Something like '-srgb-to-linear' and '-linear-to-srgb'? It can be done with "-colorspace" (and maybe also with custom color profiles?), but it also complicates matters in some cases. For example, if I have a sRGB image and want to write that with values in linear space, I would try that:
convert srgb.png -colorspace sRGB -depth 16 linear.png
But besides the aforementioned issues - it wouldn't be successful, as this 'sRGB' colorspace (I can only repeat that this name is confusing here ;-)) can't be stored as PNG, so it gets automatically converted back to the 'RGB' colorspace (with sRGB gamma values). I can store the values in linear space, but only by fooling IM:
convert srgb.png -colorspace sRGB -set colorspace RGB -depth 16 linear.png
Some of this was also mentioned in here: viewtopic.php?f=1&t=15955

Drarakel
Posts: 547
Joined: 2010-04-07T12:36:59-07:00
Authentication code: 8675308

Re: Issues with "-colorspace sRGB"

Post by Drarakel » 2010-10-02T01:57:35-07:00

Looking at the source:

colorspace.c, in 'case SRGBColorspace' within RGBTransformImage (after line 833):

Code: Select all

        v=(MagickRealType) i/(MagickRealType) MaxMap;
        if (((MagickRealType) i/(MagickRealType) MaxMap) <= 0.03928f)
          v/=12.92f;
        else
          v=(MagickRealType) MaxMap*pow((((double) i/MaxMap)+0.055)/1.055,2.4);
"0.03928f" isn't completely correct here. Should be "0.04045f".
(The inverse operation in TransformRGBImage already has the correct value - "0.0031308".)

And the line "v/=12.92f;" produces wrong results. Now I don't know where i is exactly coming from and I don't know about MaxMap and MagickRealType. But I guess, "v=(MagickRealType) i/(MagickRealType) MaxMap;" stores a normalized value. Now the operation with the power function probably converts the value back to interval [0;65535] (if 16bit). But the "v/=12.92f;" line doesn't do that, so the end result will be a very low floating point number and this always gets rounded/truncated to zero. Probably should be "v=(MagickRealType) MaxMap*v/12.92f" or just "v=i/12.92f" or something like that.

And again, the names of the operations are a bit confusing.
The comment in line 837 ('case SRGBColorspace' in RGBTransformImage) says:

Code: Select all

        Linear RGB to nonlinear sRGB (http://www.w3.org/Graphics/Color/sRGB):
But it's the other way round! This method takes a regular sRGB image as input (other input images don't make sense), so it converts from nonlinear sRGB to linear (s)RGB!

User avatar
magick
Site Admin
Posts: 11095
Joined: 2003-05-31T11:32:55-07:00

Re: Issues with "-colorspace sRGB"

Post by magick » 2010-10-02T09:08:32-07:00

Good catch. Thanks for the analysis and patch. We'll get it into the next point release of ImageMagick.

Post Reply