I have a CGImage (core graphics, C/C++). It's grayscale. Well, originally it was B/W, but the CGImage may be RGB. That shouldn't matter. I want to create a CCITT-Group 4 TIFF.
I can create an LZW TIFF (grayscale or color) via creating a destination with the correct dictionary and adding the image in. No problem.
However, there doesn't seem to be an equivalent kCGImagePropertyTIFFCompression value to represent CCITT-4. It should be 4, but that produces uncompressed.
I have a manual CCITT compression routine, so if I can get the binary (1 bit per pixel) data, I'm set. But I can't seem to get 1 BPP data out of a CGImage. I have code that is supposed to put the CGImage into a CGBitmapContext and then give me the data, but it seems to be giving me all black.
I've asked a couple of questions today trying to get at this, but I just figured, lets ask the question I REALLY want answered and see if someone can answer it.
There's GOT to be a way to do this. I've got to be missing something dumb. What is it?
This seems to work and produce not-all-black output. There may be a way to do it that doesn't involve a manual conversion to grayscale first, but at least it works!
static void WriteCCITTTiffWithCGImage_URL_(CGImageRef im, CFURLRef url) {
// produce grayscale image
CGImageRef grayscaleImage;
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
CGContextRef bitmapCtx = CGBitmapContextCreate(NULL, CGImageGetWidth(im), CGImageGetHeight(im), 8, 0, colorSpace, kCGImageAlphaNone);
CGContextDrawImage(bitmapCtx, CGRectMake(0,0,CGImageGetWidth(im), CGImageGetHeight(im)), im);
grayscaleImage = CGBitmapContextCreateImage(bitmapCtx);
CFRelease(bitmapCtx);
CFRelease(colorSpace);
}
// generate options for ImageIO. Man this sucks in C.
CFMutableDictionaryRef options = CFDictionaryCreateMutable(kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
{
{
CFMutableDictionaryRef tiffOptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
int fourInt = 4;
CFNumberRef fourNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &fourInt);
CFDictionarySetValue(tiffOptions, kCGImagePropertyTIFFCompression, fourNumber);
CFRelease(fourNumber);
CFDictionarySetValue(options, kCGImagePropertyTIFFDictionary, tiffOptions);
CFRelease(tiffOptions);
}
{
int oneInt = 1;
CFNumberRef oneNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &oneInt);
CFDictionarySetValue(options, kCGImagePropertyDepth, oneNumber);
CFRelease(oneNumber);
}
}
// write file
CGImageDestinationRef idst = CGImageDestinationCreateWithURL(url, kUTTypeTIFF, 1, NULL);
CGImageDestinationAddImage(idst, grayscaleImage, options);
CGImageDestinationFinalize(idst);
// clean up
CFRelease(idst);
CFRelease(options);
CFRelease(grayscaleImage);
}
Nepheli:tmp ken$ tiffutil -info /tmp/output.tiff
Directory at 0x1200
Image Width: 842 Image Length: 562
Bits/Sample: 1
Sample Format: unsigned integer
Compression Scheme: CCITT Group 4 facsimile encoding
Photometric Interpretation: "min-is-black"
Orientation: row 0 top, col 0 lhs
Samples/Pixel: 1
Number of Strips: 1
Planar Configuration: Not planar
ImageMagick can convert from and to almost any image format. As it is open source you can go and read the source code to find the answer to your question.
You can even use the ImageMagick API in you app if you use C++.
Edit:
If you can get the data from CGImage in any format (and it sounded like you can) you can use ImageMagick to convert it from whatever the format is that you get from CGImage to any other format supported by ImageMagick (your desired TIFF format).
Edit:
Technical Q&A QA1509
Getting the pixel data from a CGImage object states:
On Mac OS X 10.5 or later, a new call has been added that allows you to obtain the actual pixel data from a CGImage object. This call, CGDataProviderCopyData, returns a CFData object that contains the pixel data from the image in question.
Once you have the pixel data you can use ImageMagick to convert it.
NSBitmapImageRep claims to be able to generate a CCITT FAX Group 4 compressed TIFF. So something like this might do the trick (untested):
CFDataRef tiffFaxG4DataForCGImage(CGImageRef cgImage) {
NSBitmapImageRep *imageRep =
[[[NSBitmapImageRep alloc] initWithCGImage:cgImage] autorelease];
NSData *tiffData =
[imageRep TIFFRepresentationUsingCompression:NSTIFFCompressionCCITTFAX4
factor:0.0f];
return (CFDataRef) tiffData;
}
This function should return the data you seek.