Question

If this function does what I think it does, it seems that on my machine at least in CMYK, C=0, M=0, Y=0 and K=0 does not correspond to white! What is the problem?

float *arr is a float array with size elements. I want to save this array as a JPEG with IJG's libjpeg in two color spaces upon demand: g: Gray scale and c: CMYK. I follow their example and make the input JSAMPLE *jsr array with the number of JSAMPLE elements depending on the color space: size elements for gray scale and 4*size elements for CMYK. JSAMPLE is just another name for unsigned char on my machine at least. The full program can be seen on Github. This is how I fill jsr:

void
floatfilljsarr(JSAMPLE *jsr, float *arr, size_t size, char color)
{
  size_t i;
  double m;
  float min, max;

  /* Find the minimum and maximum of the array:*/
  fminmax(arr, size, &min, &max);
  m=(double)UCHAR_MAX/((double)max-(double)min);

  if(color=='g')
    {
      for(i=0;i<size;i++)
        jsr[i]=(arr[i]-min)*m;
    }
  else
    for(i=0;i<size;i++)
      {
        jsr[i*4+3]=(arr[i]-min)*m;
        jsr[i*4]=jsr[i*4+1]=jsr[i*4+2]=0;
      }
}

I should note that color has been checked before this function to be either c or g. I then write the JPEG image exactly as the example.c program in libjpeg's source.

Here is the output after printing both images in a TeX document. Grayscale is on the left and CMYK is on the right. Both images are made from the same ordered array, so the bottom left element (the first in the array as I have defined it and displayed it here) has JSAMPLE value 0 and the top right element has JSAMPLE value 255.

grayscale (left) and CMYK (right) comparison.

Why aren't the two images similar? Because of the different nature, I would expect the CMYK image to be reversed with its bottom being bright and its top being black. Their displaying JSAMPLE values (the only value in grayscale and the K channel in CMYK) are identical, but this output I get is not what I expected! The CMYK image is also brighter to the top, but very faintly!

It seems that C=0, M=0, Y=0 and K=0 does not correspond to white at least with this algorithm and on my machine!?! How can I set white when I only what to change the K channel and keep the rest zero?

Was it helpful?

Solution 2

I think I found the answer my self. First I tried setting all four colors to the same value. It did produce a reasonable result but the output was not inverted as I expected. Such that the pixel with the largest value in all four colors was white, not black!

It was then that it suddenly occurred to me that somewhere in the process, either in IJG's libjpeg or in general in the JPEG standard I have no idea which, CMYK colors are reversed. Such that for example a Cyan value of 0 is actually interpreted as UCHAR_MAX on the display or printing device and vice versa. If this was the solution, the fact that the image in the question was so dark and that its grey shade was the same as the greyscale image could easily be explained (since I set all three other colors to zero which was actually interpreted as the maximum intensity!).

So I set the first three CMYK colors to the full range (=UCHAR_MAX):

jsr[i*4]=jsr[i*4+1]=jsr[i*4+2]=UCHAR_MAX /* Was 0 before! */;

Then to my surprise the image worked. The greyscale (left) shades of grey are darker, but atleast generally everything can be explained and is reasonably similar. I have checked separately and the absolute black color is identical in both, but the shades of grey in grey scale are darker for the same pixel value.

On monitor

After I checked them on print (below) the results seemed to differ less, although the shades of grey in greys-scale are darker! Image taken with my smartphone!

On paper

Also, until I made this change, on a normal image viewer (I am using Scientific Linux), the image would be completely black, that is why I thought I can't see a CMYK image! But after this correction, I could see the CMYK image just as an ordinary image. Infact using Eye of GNOME (the default image viewer in GNOME), the two nearly appear identical.

OTHER TIPS

Try inverting your K channel:

       jsr[i*4+3]= (m - ((arr[i]-min)*m);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top