Please excuse my delayed answer, I was lost in colorspace...
I'll try to break my problem down, and be more precise.
The user can design a printing template and upload the following formats (for the beginning):
- JPEG, PNG, PDF, SVG
If a CMYK-JPEG or CMYK-PDF is uploaded, the server checks whether the correct CMYK profile exists, otherwise the CMYK profile is assigned.
If an image is not in CMYK colorspace then sRGB is assumed.
The images are stored online just as they were uploaded, with the exception, that a JPEG is extracted from every PDF (only 1 Page PDFs allowed for now).
There are the following color-management use-cases:
1. The user selects an uploaded file and places it on a browser canvas.
The view simulates the CMYK appearance (relative rendering intent, but the intent could be a user's choice later on). I'm aware that this is not going to be perfect, unless only calibrated screens are used. However, the goal is to simulate the appearance as close as possible. For an exact preview, the user can download a PDF which is precise (ISO coated V2 profile included, and exact color values).
For simulating the image-appearance to look like CMYK in the browser I do the following:
case A: CMYK-files get converted to sRGB (ISOcoated_v2_eci.icc to sRGB2014.icc).
case B: SRGB-files make a roundtrip and are converted to CMYK (relative rendering intent), and the go throuh the handler of case A.
So now the appearance of specific colors gets close to CMYK and (most important) matches across all shown images/graphic elements. The user can now add layers, rearrange the graphics, add text, set a background and so on.
Once the design is finished, the user wants to download a PDF
2. Now all the information from the online designer gets passed to the server.
The server now does all the merging of layers into one image and a final print master is generated.
Actually I found out, that ImageMagick's composite is capable of quiet a few crazy things, and that the merging can be done in CMYK as well
![Wink ;)](./images/smilies/icon_wink.gif)
All sRGB-files can be processed after being converted (relative rendering intent) to CMYK and the merging with already existing CMYK images works very well. This is awesome!
Maybe the anti-aliasing around text elements (transparent background PNG) generated in the frontend could be improved. I'll look into that, there are some good filters (but this part is also a question of perforamance)...after all the professional designer can always design the whole template in Photoshop and the web-to-print-solution is supposed to help non-professionals customize items (templates must be curved, the designer is actually in 3d, and the canvas(es) where the user places his graphics are only used internally).
3. User-picked color values
I came across a problem, which I tried to tackle with different approaches:
How to softproof (in a web browser) background or text color that is being selected in CMYK, even though the frontend is not capable of handling CMYK?
A. For background colors I do the following:
- Take the CMYK value as the user entered it, and generate an image (Imagick PHP wrapper):
$image = new Imagick();
$image->newImage($print_width, $print_height, new ImagickPixel($cmyk_string));
$image->setImageColorspace(Imagick::COLORSPACE_CMYK);
I do not use a profile, since the CMYK values must be exactly the ones, the user entered, and will be part of the print master, to which the profile ISO coated V2 will be assigned anyways.
This works great so far.
B. For text elements the problem is different:
- The text elements are passed to the server as base64-encoded PNG-files, so they are in sRGB. Since the graphic is not created by the server, I need to make sure, that after converting to CMYK, the color value is the same, that the usered entered. So it's kind of like CMYK being transmitted via sRGB.
After quiet a few approaches I found a pretty good way (once again Imagick PHP wrapper):
$this->data['imagick']->setImageColorspace(Imagick::COLORSPACE_RGB);
$this->data['imagick']->transformImageColorspace(Imagick::COLORSPACE_CMYK);
$this->data['imagick']->writeImage($this->export_buffer);
This was the only way that worked for me so far. I need a conversion like:
Code: Select all
var $c,$m,$y,$k;
$r = $r/255;
$g = $g/255;
$b = $b/255;
$max = Math.max($r,$g,$b);
$k = 1 - $max;
if ($k == 1) {
$c = 0;
$m = 0;
$y = 0;
}
else {
$c = (1 - $r - $k) / (1 - $k);
$m = (1 - $g - $k) / (1 - $k);
$y = (1 - $b - $k) / (1 - $k);
}
transformImageColorspace is exactly what I was looking for. I also tried stuff with GraphicsMagick (partly used on the server for security reasons):
gm convert /input.tiff -colorspace RGB -colorspace CMYK /output.tiff
However, this only works well when the expected BLACK is at 0% (user input).
For example, if I get RGB(0, 153, 153), transformImageColorspace (see above) will convert this to the expected CMYK(100%,0%,0%,40%)
gm convert on the other hand converts to CMYK(100%,40%,40%,40%), it always adds the BLACK channels percentage as a min value somehow...I don't know if it is a bug, or if don't understand it well enough yet.
How would transformImageColorspace (from Imagick) be written on the command line?
C. Softproofing the user-picked values:
For this problem I created a lookup table with a reduced number of colours (to keep it small), so each time the user picks (in a colorpicker) or enters a CMYK value, another RGB value can be found to simulate the CMYK appearance. This works well so far, but especially for darks colors my lookup table shows its limitations. Here is how I created it:
I converted a png with a subset of all colors (for each pixel one RGB combination) to a CMYK tiff as described in 3.B, and then I opened the tiff in Photoshop, converted it back to sRGB-PNG (with black point compensation activated).
For each CMYK value the user picks the corresponding RGB-Value can be found in the table (since I use a subset of all colors, I round a little bit).
Calculating those values server-side would not be an option (a request for each color conversion is not acceptable
![Wink ;)](./images/smilies/icon_wink.gif)
), at the sime time I did not find a way of interpreting profiles via Javascript yet, so I guess the conversion can't be done without a lookup table.
I'm sure my workflow can be improved, so maybe somebody knows, if things can be done more accurate or straight-forward?
![Smile :)](./images/smilies/icon_smile.gif)