Missing black channel using Magick++, C++

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
John.Green

Missing black channel using Magick++, C++

Post by John.Green »

I working with a program that has images in its own internal format. I needed to use some of ImageMagick's processing power so I created an image with Magick++ and I find that Black channel is always empty. Here's my code:

Code: Select all

#include <iostream>
#include <Magick++.h>

unsigned char imageData[] = {
0xff, 0xff, 0xff, 0xff,		// super black
0x00, 0x00, 0x00, 0x00,		// white
0xff, 0x00, 0x00, 0x00,		// cyan
0x00, 0xff, 0x00, 0x00,		// magenta
0x00, 0x00, 0xff, 0x00,		// yellow
0x00, 0x00, 0x00, 0xff,		// black
0x00, 0xff, 0xff, 0x00,		// red
0xff, 0x00, 0xff, 0x00,		// green
0xff, 0xff, 0x00, 0x00,		// blue
0x00, 0x00, 0x00, 0x00,		// white
0xff, 0xff, 0xff, 0xff		// super black
};

#define IMAGE_WIDTH 11
#define IMAGE_HEIGHT 1

unsigned char outputImage[IMAGE_WIDTH * IMAGE_HEIGHT * 4];


int main (int argc, char * const argv[]) {
	std::cout << "Hello, World!\n"; 

	Magick::Image image( IMAGE_WIDTH, IMAGE_HEIGHT, "CMYK", Magick::CharPixel, imageData ); 	
	//image.type(Magick::TrueColorType);
	image.write("/tmp/test.png");
	
	image.modifyImage();
	//image.blur(30, 10);
	image.syncPixels();
	
	Magick::Pixels view(image); 
	Magick::PixelPacket *pixels = view.get(0,0,IMAGE_WIDTH,IMAGE_HEIGHT); 
	
	FILE *f = fopen("/tmp/test.txt",  "w");
	
	for ( int row = 0; row < IMAGE_HEIGHT ; ++row )
		for ( int column = 0; column < IMAGE_WIDTH ; ++column ) {
			fprintf(f, "%8d\t%8d\t%8d\t%8d\n", 
					pixels->red, pixels->green, pixels->blue, pixels->opacity);
			pixels++;
		}
	fprintf(f, "\n");
	fclose(f);
	return 0;
}
When I run it, I find that a proper tif is created in /tmp/test.png as expected, but the output text file is incorrect. Here's what I get:

Code: Select all

       0	       0	       0	       0
   65535	   65535	   65535	       0
       0	   65535	   65535	       0
   65535	       0	   65535	       0
   65535	   65535	       0	       0
       0	       0	       0	       0
   65535	       0	       0	       0
       0	   65535	       0	       0
       0	       0	   65535	       0
   65535	   65535	   65535	       0
       0	       0	       0	       0
The output should show C, M, Y and K (black) channels but the black channel is always 0. Notice how the image is inverted. This makes sense since CMYK is a subtractive image space. Is that my error? Should I be inverting the image back? I'm not sure I'm going to lose date. In the printing world, C=100%, M=100%, Y=100%, K=0% is different color than C=M=Y=K=100%. That distinction seems to be lost here. The 1st line is a "super black" and the 6th line is just a plain old black, yet the PixelPacket has converted them to the exact same color.

I appreciate any advice. Thank you. (Oh, I'm running ImageMagick-6.5.6-5 under Mac OS X 10.5.7 if that matters)

John
John.Green

Re: Missing black channel using Magick++, C++

Post by John.Green »

magick wrote:PNG does not support CMYK so it converts your image back to RGB. Here is a fix to your code:
I'm sorry, that looks identical to my existing code. I tried commenting out where I wrote out the png (which was for debugging anyway) and it still behaves the same.

How can I prevent the conversion to RGB?

Thank you.
User avatar
magick
Site Admin
Posts: 11064
Joined: 2003-05-31T11:32:55-07:00

Re: Missing black channel using Magick++, C++

Post by magick »

We posted the wrong code. Try writing the image to TIFF which supports CMYK. You also need to call view().indexes to return the black channel.
John.Green

Re: Missing black channel using Magick++, C++

Post by John.Green »

I actually don't need to write the image all. I really just need to keep it in my own buffers to later write it out to my own internal structures.

But I'll look into the indexes, see what that gets me. Thanks!
John.Green

Re: Missing black channel using Magick++, C++

Post by John.Green »

Ok, I'm getting close. When I make this call:

Code: Select all

	Magick::IndexPacket *indPak2 = view.indexes();
which I what I think you wanted me to call I'm just getting a NULL back. So I poked around some and thought I could make this call instead:

Code: Select all

	Magick::IndexPacket *indPak = NULL;
	indPak = image.getIndexes(); 
This does give me the 1st black pixel in the image (I made it 0xf0 so I could be sure that that was the correct one.) That seems to have my black channel. (Curiously, it is doubled, I see 0xf0 0xf0, not just 0xf0, but I can deal with that.)

So I'll walk my "pixels" array to get CMY and also walk my "indPak" array to get black. Seems odd but I can do that.

Thank you! (I'll keep you posted my real task is to sharpen each channel with separate parameters, so we'll see how that goes.)
John.Green

Re: Missing black channel using Magick++, C++

Post by John.Green »

Here's the corrected code:

Code: Select all

#include <iostream>
#include <Magick++.h>

unsigned char imageData[] = {
0xff, 0xff, 0xff, 0xf0,		// super black
0x00, 0x00, 0x00, 0x01,		// white
0xff, 0x00, 0x00, 0x02,		// cyan
0x00, 0xff, 0x00, 0x03,		// magenta
0x00, 0x00, 0xff, 0x04,		// yellow
0x00, 0x00, 0x00, 0xff,		// black
0x00, 0xff, 0xff, 0x00,		// red
0xff, 0x00, 0xff, 0x00,		// green
0xff, 0xff, 0x00, 0x00,		// blue
0x00, 0x00, 0x00, 0x00,		// white
0xff, 0xff, 0xff, 0xff		// super black
};

#define IMAGE_WIDTH 11
#define IMAGE_HEIGHT 1

int main (int argc, char * const argv[]) {
	std::cout << "Hello, World!\n"; 

	Magick::Image image( IMAGE_WIDTH, IMAGE_HEIGHT, "CMYK", Magick::CharPixel, imageData ); 	
	//image.type(Magick::TrueColorType);
	//image.write("/tmp/test.png");
	
	image.modifyImage();
	//image.blur(30, 10);
	image.syncPixels();
	
	
	Magick::Pixels view(image); 
	Magick::PixelPacket *pixels = view.get(0,0,IMAGE_WIDTH,IMAGE_HEIGHT); 	
	Magick::IndexPacket *indPak = NULL;
	indPak = image.getIndexes(); 
	
	FILE *f = fopen("/tmp/test.txt",  "w");
	
	int index = 0;
	
	for ( int row = 0; row < IMAGE_HEIGHT ; ++row )
		for ( int column = 0; column < IMAGE_WIDTH ; ++column ) {
			fprintf(f, "%8d\t%8d\t%8d\t%8d\n", 
					pixels->red, pixels->green, pixels->blue, indPak[index]);
			pixels++;
			indPak++;
		}
	fprintf(f, "\n");
	fclose(f);

	return 0;
}
John.Green

Re: Missing black channel using Magick++, C++

Post by John.Green »

of course when I take what I learned and put it back into my real application it no longer works. The data returned by getIndexes just isn't correct.

Is there any sample code out there showing pixel manipulation of CMYK images using Magick++?

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

Re: Missing black channel using Magick++, C++

Post by magick »

Try this program:

Code: Select all

#include <iostream>
#include <Magick++.h>

unsigned char imageData[] = {
0xff, 0xff, 0xff, 0xff,      // super black
0x00, 0x00, 0x00, 0x00,      // white
0xff, 0x00, 0x00, 0x00,      // cyan
0x00, 0xff, 0x00, 0x00,      // magenta
0x00, 0x00, 0xff, 0x00,      // yellow
0x00, 0x00, 0x00, 0xff,      // black
0x00, 0xff, 0xff, 0x00,      // red
0xff, 0x00, 0xff, 0x00,      // green
0xff, 0xff, 0x00, 0x00,      // blue
0x00, 0x00, 0x00, 0x00,      // white
0xff, 0xff, 0xff, 0xff      // super black
};

#define IMAGE_WIDTH 11
#define IMAGE_HEIGHT 1

unsigned char outputImage[IMAGE_WIDTH * IMAGE_HEIGHT * 4];


int main (int argc, char * const argv[]) {
   std::cout << "Hello, World!\n";

   Magick::Image image( IMAGE_WIDTH, IMAGE_HEIGHT, "CMYK", Magick::CharPixel, imageData );    
   //image.type(Magick::TrueColorType);
   image.write("/tmp/test.tif");
   
   image.modifyImage();
   //image.blur(30, 10);
   image.syncPixels();
   
   Magick::Pixels view(image);
   
   FILE *f = fopen("/tmp/test.txt",  "w");
   
   for ( int row = 0; row < IMAGE_HEIGHT ; ++row )
   {
     Magick::PixelPacket *pixels = view.get(0,row,IMAGE_WIDTH,1);
     Magick::IndexPacket *indexes = view.indexes();
      for ( int column = 0; column < IMAGE_WIDTH ; ++column ) {
         fprintf(f, "%8d\t%8d\t%8d\t%8d\n",
               pixels->red, pixels->green, pixels->blue, *indexes);
         pixels++;
         indexes++;
      }
   }
   fprintf(f, "\n");
   fclose(f);
   return 0;
}
John.Green

Re: Missing black channel using Magick++, C++

Post by John.Green »

Thanks, that almost did the trick. When I used indexs() instead of getIndexes() I still had bad data, except that then all I had to do was shift it right by 8 bits and I was fine. (If the image had, for example, 0xa9 in the black channel, the index array had 0xa9a9. Since my original image was 8 bits I just shifted.)

Thank you very very much for your help!
Post Reply