Convert color values from RGB to CMYK with ICC profile
Convert color values from RGB to CMYK with ICC profile
Hi everybody,
I've been working with Imagemagick for a while now (using it in a web project, thus using PHP to work with it), and I've ran into a problem. I hope a smart mind here can help me.
I have to implement a color picker in my project (again, web based), which is no hassle at all. Done that with some fancy vanilla css and javascript. But I also have to display the CMYK values of a color, which the user selects. And that is where my problem starts. All the rough calculations on the web convert from RGB to CMYK without respecting any ICC profile at all. So they come up with e.g. rgb(0,255,255) = cmyk(100,0,0,0). I need this conversion to be more accurate with respect to the gamut of a specific ICC profile (CoatedFogra39 to be precise). I have the profile, since it is openly available. But I do not know how to calculate single color values with respect to this profile (and then back to RGB with respect to AdobeRGB1998).
All that is necessary, in order to give the user visual feedback, like in Photoshop, when a selected RGB color is out of gamut of the active ICC profile, and give him the nearest suggested color which lies inside the given gamut. In the attached image you can see that 1) Photoshop converts rgb(0,255,255) to cmyk(84,0,21,0), which lies inside the gamut range of CoatedFogra39, and 2) suggests to change the color to the nearest rgb value inside the cmyk gamut, which corresponds to cmyk(84,0,21,0), thus, if one clicks on the suggested color, the rgb changes to rgb(86,169,198).
Is there a way I can achieve this sort of single color value calculation with Imagemagick?
I need to retrieve values as a string, array or whatever format, so I can return it to the script which displays the numbers in the color picker.
Thanks a huge-ton for reading my wall of text.
Tricon
I've been working with Imagemagick for a while now (using it in a web project, thus using PHP to work with it), and I've ran into a problem. I hope a smart mind here can help me.
I have to implement a color picker in my project (again, web based), which is no hassle at all. Done that with some fancy vanilla css and javascript. But I also have to display the CMYK values of a color, which the user selects. And that is where my problem starts. All the rough calculations on the web convert from RGB to CMYK without respecting any ICC profile at all. So they come up with e.g. rgb(0,255,255) = cmyk(100,0,0,0). I need this conversion to be more accurate with respect to the gamut of a specific ICC profile (CoatedFogra39 to be precise). I have the profile, since it is openly available. But I do not know how to calculate single color values with respect to this profile (and then back to RGB with respect to AdobeRGB1998).
All that is necessary, in order to give the user visual feedback, like in Photoshop, when a selected RGB color is out of gamut of the active ICC profile, and give him the nearest suggested color which lies inside the given gamut. In the attached image you can see that 1) Photoshop converts rgb(0,255,255) to cmyk(84,0,21,0), which lies inside the gamut range of CoatedFogra39, and 2) suggests to change the color to the nearest rgb value inside the cmyk gamut, which corresponds to cmyk(84,0,21,0), thus, if one clicks on the suggested color, the rgb changes to rgb(86,169,198).
Is there a way I can achieve this sort of single color value calculation with Imagemagick?
I need to retrieve values as a string, array or whatever format, so I can return it to the script which displays the numbers in the color picker.
Thanks a huge-ton for reading my wall of text.
Tricon
-
- Posts: 12159
- Joined: 2010-01-23T23:01:33-07:00
- Authentication code: 1151
- Location: England, UK
Re: Convert color values from RGB to CMYK with ICC profile
It sounds as if you want an image with a single pixel to undergo a round-trip from sRGB to CMYK and back, such as:
The output is:
The first "-write txt:" and output isn't needed. It just proves we get out what we put in, and shows we should ignore the last item on the output lines.
We are listing the pixels in the image. "0,0" is the coordinate of the only pixel.
Then we get the percentages, of the channels given at the end of the previous "#" line.
Then, if we prefer, we get the hex number.
If you try in-gamut numbers, eg rgb(100,110,120), the round-trip gives a final output number very close to the input.
Code: Select all
convert xc:rgb(0,255,255) -profile sRGB.icc -write txt: -profile CoatedFOGRA39.icc -write txt: -profile sRGB.icc txt:
Code: Select all
# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (0%,100%,100%) #0000FFFFFFFF cyan
# ImageMagick pixel enumeration: 1,1,65535,cmyk
0,0: (99.8795%,0%,21.9852%,0%) #FFB0000038480000 cmyk(99.8795%,0%,21.9852%,0%)
# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (11.3725%,75.0423%,77.4777%) #1D1DC01BC657 srgb(11.3725%,75.0423%,77.4777%)
We are listing the pixels in the image. "0,0" is the coordinate of the only pixel.
Then we get the percentages, of the channels given at the end of the previous "#" line.
Then, if we prefer, we get the hex number.
If you try in-gamut numbers, eg rgb(100,110,120), the round-trip gives a final output number very close to the input.
snibgo's IM pages: im.snibgo.com
Re: Convert color values from RGB to CMYK with ICC profile
Hello snibgo,
thanks a lot for your reply.
I thought of a similar process already, but the one thing that keeps me back is the workload necessary for this procedure.
Currently I am extracting the color values in this way:
1) create the 1x1 image with the respective color profiles
2) extract the cmyk color values to be used later
result: 80, 24, 0, 0
3) convert image back to rgb, again with the correct color profile
4) extract the new rgb color values to be used later
result 80, 172, 195
One thing I've noticed is that the first file (color_cmyk.jpg) is 639kb in size, while the second image (color_rgb.jpg) is only 864b. The CoatedFOGRA39 profile file is 545kb and the AdobeRGB1998 file is just 1kb. So it seems the profiles (at least the cmyk one) are embedded somewhat uncompressed. That might also be a reason, why the calculation takes so "long". In my tests the waiting time for the server reply is about 4-5sec. This is a bit problematic if I want to update the color picker in near-realtime.
Do you maybe have any suggestion for me, or an idea in which direction I could do more research?
Thanks a lot again
Tricon
thanks a lot for your reply.
I thought of a similar process already, but the one thing that keeps me back is the workload necessary for this procedure.
Currently I am extracting the color values in this way:
1) create the 1x1 image with the respective color profiles
Code: Select all
exec("convert xc:'rgb(0,255,255)' -profile AdobeRGB1998.icc -profile CoatedFOGRA39.icc color_cmyk.jpg");
Code: Select all
$cmyk = exec("convert color_cmyk.jpg -format '%[fx:int(100*c)], %[fx:int(100*m)], %[fx:int(100*y)], %[fx:int(100*k)]' info:- ");
3) convert image back to rgb, again with the correct color profile
Code: Select all
exec("convert color_cmyk.jpg -profile AdobeRGB1998.icc color_rgb.jpg");
Code: Select all
$rgb = exec("convert color_rgb.jpg -format '%[fx:(255*r)], %[fx:(255*g)], %[fx:(255*b)]' info:- ");
One thing I've noticed is that the first file (color_cmyk.jpg) is 639kb in size, while the second image (color_rgb.jpg) is only 864b. The CoatedFOGRA39 profile file is 545kb and the AdobeRGB1998 file is just 1kb. So it seems the profiles (at least the cmyk one) are embedded somewhat uncompressed. That might also be a reason, why the calculation takes so "long". In my tests the waiting time for the server reply is about 4-5sec. This is a bit problematic if I want to update the color picker in near-realtime.
Do you maybe have any suggestion for me, or an idea in which direction I could do more research?
Thanks a lot again
Tricon
-
- Posts: 12159
- Joined: 2010-01-23T23:01:33-07:00
- Authentication code: 1151
- Location: England, UK
Re: Convert color values from RGB to CMYK with ICC profile
Do you need those intermediate files? It would be far quicker without. You can "-write info:" then carry on with the rest of the command. I don't know how to read the output with PHP.
snibgo's IM pages: im.snibgo.com
Re: Convert color values from RGB to CMYK with ICC profile
I would not need the files, no.
I've tried what you suggested and used this:
Echoing the variable gives me this:
Could you tell me, how I can continue to work with this string? The command I use next, to extract the pixel colors, does not work, if i store the info of the cmyk jpg in a variable this way.
This (2nd step) gives no output what so ever.
Any idea?
Thank you
Tricon
I've tried what you suggested and used this:
Code: Select all
$img_cmyk = exec("convert xc:'rgb(0,255,255)' -profile AdobeRGB1998.icc -profile CoatedFOGRA39.icc info:- ");
Code: Select all
xc:rgb(0,255,255) XC 1x1 1x1+0+0 16-bit ColorSeparation DirectClass 7.850u 0:02.079
Code: Select all
$col_cmyk = exec("convert " . $img_cmyk . " -format '%[fx:int(100*c)], %[fx:int(100*m)], %[fx:int(100*y)], %[fx:int(100*k)]' info:- ");
Any idea?
Thank you
Tricon
- fmw42
- Posts: 25562
- Joined: 2007-07-02T17:14:51-07:00
- Authentication code: 1152
- Location: Sunnyvale, California, USA
Re: Convert color values from RGB to CMYK with ICC profile
try sending std error to stdout
Code: Select all
$col_cmyk = exec("convert " . $img_cmyk . " -format '%[fx:int(100*c)], %[fx:int(100*m)], %[fx:int(100*y)], %[fx:int(100*k)]' info:- 2>&1");
-
- Posts: 12159
- Joined: 2010-01-23T23:01:33-07:00
- Authentication code: 1151
- Location: England, UK
Re: Convert color values from RGB to CMYK with ICC profile
Sorry, I don't know PHP.
If you use a single "convert" command, you won't need intermediate files. But if you keep it as separate "convert" commands, you do need intermediate files.
You set $img_cmyk to be useless text output. You can't then give that to "convert".
If you use a single "convert" command, you won't need intermediate files. But if you keep it as separate "convert" commands, you do need intermediate files.
You set $img_cmyk to be useless text output. You can't then give that to "convert".
snibgo's IM pages: im.snibgo.com
Re: Convert color values from RGB to CMYK with ICC profile
Hello again and thanks for the suggestions.
I've gone your way, snibgo, and used a single convert command without saving intermediate files.
This is what I'm currently doing:
cmyk.txt:
rgb.txt
Extracting the cmyk and rgb values from that would not be a problem, but this method still takes roughly 4-5sec to produce the text files.
If I do not apply the color profile calculations, everything is a lot faster, evidently. Do you believe there could be a faster method to get these values?
I have not tried it yet, but do you think parsing a nosql db with all rgb color entries as strings to get the corresponsing cmyk value, also as a string, would yield faster results (near real-time)?
Thank you
Tricon
I've gone your way, snibgo, and used a single convert command without saving intermediate files.
This is what I'm currently doing:
Code: Select all
exec("convert xc:'rgb(0,255,255)' -profile AdobeRGB1998.icc -profile CoatedFOGRA39.icc -write txt:cmyk.txt -profile AdobeRGB1998.icc txt:rgb.txt");
Code: Select all
# ImageMagick pixel enumeration: 1,1,65535,cmyk
0,0: (52631, 0,15802, 0) #CD9700003DBA0000 cmyk(80.3098%,0%,24.1123%,0%)
Code: Select all
# ImageMagick pixel enumeration: 1,1,65535,rgb
0,0: (20608,44283,49824) #5080ACFBC2A0 rgb(31.4458%,67.5715%,76.0266%)
If I do not apply the color profile calculations, everything is a lot faster, evidently. Do you believe there could be a faster method to get these values?
I have not tried it yet, but do you think parsing a nosql db with all rgb color entries as strings to get the corresponsing cmyk value, also as a string, would yield faster results (near real-time)?
Thank you
Tricon
-
- Posts: 12159
- Joined: 2010-01-23T23:01:33-07:00
- Authentication code: 1151
- Location: England, UK
Re: Convert color values from RGB to CMYK with ICC profile
Perhaps some other tool is available for converting single colours, and it might be faster than IM for this.
If you only want 8-bit resolution, a look-up table would be much quicker. The table wouldn't be huge: 256*256*256 = 17 m entries.
If you only want 8-bit resolution, a look-up table would be much quicker. The table wouldn't be huge: 256*256*256 = 17 m entries.
snibgo's IM pages: im.snibgo.com
Re: Convert color values from RGB to CMYK with ICC profile
Hi again - sorry to rewake this post, but I'd have another question, if anyone could assist me.
Is it possible to use the -write command in conjunction with the -format command, to store only the cmyk color values in a txt file, and then repeatedly adding new values to the same file?
If at all possible, I imagined the first txt file to consist, for example, only of:
and then adding to this text file another value, so it looks, e.g., like this:
Is this possible with the imagemagick cli tools?
Thanks again
Tricon
Is it possible to use the -write command in conjunction with the -format command, to store only the cmyk color values in a txt file, and then repeatedly adding new values to the same file?
If at all possible, I imagined the first txt file to consist, for example, only of:
Code: Select all
80.3098%,0%,24.1123%,0%
Code: Select all
80.3098%,0%,24.1123%,0%
61.2169%,0%,28.9175%,0%
Thanks again
Tricon
- fmw42
- Posts: 25562
- Joined: 2007-07-02T17:14:51-07:00
- Authentication code: 1152
- Location: Sunnyvale, California, USA
Re: Convert color values from RGB to CMYK with ICC profile
IM in combination with your OS. For unix, just redirect the result to the file using
convert ..... txt >> textfile.txt
If using PHP, then the exec command can simple get the data output from txt without the redirect and you can then write it to your textfile.
convert ..... txt >> textfile.txt
If using PHP, then the exec command can simple get the data output from txt without the redirect and you can then write it to your textfile.
-
- Posts: 12159
- Joined: 2010-01-23T23:01:33-07:00
- Authentication code: 1151
- Location: England, UK
Re: Convert color values from RGB to CMYK with ICC profile
As Fred says, your shell can append new lines to existing text files.
You can get the format you want directly, eg:
This is Windows BAT syntax. Other shells need variations, eg turn "%%" and "\%%" to "%", etc.
You can get the format you want directly, eg:
Code: Select all
convert ^
xc:khaki -colorspace CMYK ^
-precision 9 ^
-format "%%[fx:100*p{0,0}.c]\%%,%%[fx:100*p{0,0}.m]\%%,%%[fx:100*p{0,0}.y]\%%,%%[fx:100*p{0,0}.k]\%%" ^
info:
snibgo's IM pages: im.snibgo.com
- fmw42
- Posts: 25562
- Joined: 2007-07-02T17:14:51-07:00
- Authentication code: 1152
- Location: Sunnyvale, California, USA
Re: Convert color values from RGB to CMYK with ICC profile
This might be simpler (in unix syntax) as long as the colorspace is not rgb/srgb which would return khaki. Otherwise, snibgo's command will need to be modified for colorspaces with different numbers of channels. But if you just want cmyk, then either is fine. My way works automatically with other colorspaces such as HSL, etc.
cmyk(0%,4.167%,41.67%,5.882%)
see
http://www.imagemagick.org/script/fx.php
http://www.imagemagick.org/Usage/transform/#fx_escapes
To put it into a file
The >> means to add to the file, so that each time you run the command (e.g with different colors), it will add the result to your txtfile. If you want to overwrite, then use just one >.
This should work in PHP exec, but you can access the text results from exec without the >> and write them via PHP to a text file if you want.
P.S. snibgo's command can be simplified as just
Code: Select all
convert xc:khaki -precision 4 -colorspace cmyk -format "%[pixel:p{0,0}]" info:
see
http://www.imagemagick.org/script/fx.php
http://www.imagemagick.org/Usage/transform/#fx_escapes
To put it into a file
Code: Select all
convert xc:khaki -precision 4 -colorspace cmyk -format "%[pixel:p{0,0}]" info: >> txtfile.txt
This should work in PHP exec, but you can access the text results from exec without the >> and write them via PHP to a text file if you want.
P.S. snibgo's command can be simplified as just
Code: Select all
convert ^
xc:khaki -colorspace CMYK ^
-precision 9 ^
-format "%%[fx:100*c]\%%,%%[fx:100*m]\%%,%%[fx:100*y]\%%,%%[fx:100*k]\%%" ^
info:
Re: Convert color values from RGB to CMYK with ICC profile
You guys are amazing, thanks a ton.
I'll have to give this a try immediately when I get the chance
I'll have to give this a try immediately when I get the chance
Re: Convert color values from RGB to CMYK with ICC profile
Could there be a bug with the variables used inside an -fx function?
If I use this format notation:
the results are for example this:
RGB(0,255,255) -> "80, 24, 0, 0"
RGB(255,0,0) -> "0, 82, 90, 0"
RGB(255,0,255) -> "27, 0, 75, 0"
RGB(0,255,0) -> "89, 100, 0, 0"
All of these cmyk values are absolutely fine, except that the M and Y values seem to be swapped (compared to Photoshop). The numbers are fine, it's just the places of those two colors which switched positions apparently. Is this a bug or am I missing something? Any Idea?
Thanks
Tricon
If I use this format notation:
Code: Select all
-format '%[fx:int(100*c)], %[fx:int(100*m)], %[fx:int(100*y)], %[fx:int(100*k)]'
RGB(0,255,255) -> "80, 24, 0, 0"
RGB(255,0,0) -> "0, 82, 90, 0"
RGB(255,0,255) -> "27, 0, 75, 0"
RGB(0,255,0) -> "89, 100, 0, 0"
All of these cmyk values are absolutely fine, except that the M and Y values seem to be swapped (compared to Photoshop). The numbers are fine, it's just the places of those two colors which switched positions apparently. Is this a bug or am I missing something? Any Idea?
Thanks
Tricon