View Full Version : 16-bit to 8-bit image conversion

Nov 3, 2009, 11:04 AM
I'm trying to make a scientific program that works with 16-bit tiff directories (of images) but displays the images as 8-bit. I also want to allow for the adjusting of the white and black levels. As of now, I'm reading in the 16-bit tiff, getting out the data, editing it, and then loading it into a new image. However, I can't figure out how to set the IKImageView settings correctly. It displays my 16-bit tiff as two (almost) duplicate versions in the top left quadrant and top right quadrant with black in the bottom quadrants. I suspect this is a problem with the number of bytes per row and bits per component in my ikimageview output, but I can't figure out how to edit the NSDictionary metadata.

if ([[(NSDictionary *)imageProperties valueForKey:(NSString *)kCGImagePropertyDepth] intValue] == 16) {
CGImageRef imR = CGImageSourceCreateImageAtIndex(imageSource, index, NULL);
CFDataRef pixData = CGDataProviderCopyData(CGImageGetDataProvider(imR));
UInt16 * pixels = (UInt16 *) CFDataGetBytePtr(pixData);
UInt8 * eightPix = (UInt8 *) CFDataGetBytePtr(pixData);
int plen = CFDataGetLength(pixData);
int i;
for (i = 0; i < heightInPixels*widthInPixels; i++) {
eightPix[i] = (UInt8) pixels[i];
CGContextRef imcont = CGBitmapContextCreate(pixels, CGImageGetWidth(imR), CGImageGetHeight(imR), CGImageGetBitsPerComponent(imR), CGImageGetBytesPerRow(imR), CGImageGetColorSpace(imR), CGImageGetBitmapInfo(imR));
CGImageRef outR = CGBitmapContextCreateImage(imcont);

CFMutableDictionaryRef outProperties = CFDictionaryCreateMutableCopy(NULL, 0, imageProperties);
// const UInt8 * outVal;
// outVal = 8;
// NSString * outVal = (NSString *) 8;
// CFDictionarySetValue(outProperties, kCGImagePropertyDepth, outVal);
// outVal = (NSString *) CGImageGetWidth(imR);
// CFDictionarySetValue(outProperties, kCGImagePropertyDepth, outVal);
[imageView setImage: outR imageProperties: (NSDictionary *)outProperties];

Nov 10, 2009, 08:29 PM
I don't know about what you're doing (over my head :p). The simplest way I can think of to load and convert images is through SDL/SDL_image. Load the image using Load_IMG() into an SDL surface, then convert it to the format you want. There are tutorials around the interwebs for converting an SDL_surface into something OpenGL can read, for instance.

Nov 11, 2009, 04:46 AM
Use CGContextDrawImage() to draw your 16-bit-per-channel image into an 8-bit-per-channel CGBitmapContext. It should handle the conversion automatically.

Core Image might help as well.

Don't go mucking about with SDL. The functionality you need is in the OS.

Nov 11, 2009, 03:15 PM
Wait, your "pixels" and "eightPix" are pointing to the same memory - you are trying to convert the image data in-place. That won't work. Also, converting 16-bit images to 8-bit images can't be done with a simple cast for each pixel. Instead, you divide each 16-bit pixel value by 257. (Someone will try to correct me here and say it should be 256, but it's not a typo.)

But perhaps you don't really need to do this conversion at all (like autorelease said), since I believe you can display 16-bit TIFF images just fine on MacOS X. Why exactly do you want to convert it to 8-bit yourself?