Summary: exporting pixel data from NSOpenGLView to some file formats gives incorrect colours
I am developing an application to visualise some experimental data. One of its functions is to render the data in an NSOpenGLView
subclass, and allow the resulting image to be exported to a file or copied to the clipboard.
The view exports the data as an NSImage
, generated like this:
- (NSImage*) image
{
NSBitmapImageRep* imageRep;
NSImage* image;
NSSize viewSize = [self bounds].size;
int width = viewSize.width;
int height = viewSize.height;
[self lockFocus];
[self drawRect:[self bounds]];
[self unlockFocus];
imageRep=[[[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:width
pixelsHigh:height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:width*4
bitsPerPixel:32] autorelease];
[[self openGLContext] makeCurrentContext];
glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,[imageRep bitmapData]);
image=[[[NSImage alloc] initWithSize:NSMakeSize(width,height)] autorelease];
[image addRepresentation:imageRep];
[image setFlipped:YES]; // this is deprecated in 10.6
[image lockFocusOnRepresentation:imageRep]; // this will flip the rep
[image unlockFocus];
return image;
}
Copying uses this image very simply, like this:
- (IBAction) copy:(id) sender
{
NSImage* img = [self image];
NSPasteboard* pb = [NSPasteboard generalPasteboard];
[pb clearContents];
NSArray* copied = [NSArray arrayWithObject:img];
[pb writeObjects:copied];
}
For file writing, I use the ImageKit IKSaveOptions
accessory panel to set the output file type and associated options, then use the following code to do the writing:
NSImage* glImage = [glView image];
NSRect rect = [glView bounds];
rect.origin.x = rect.origin.y = 0;
img = [glImage CGImageForProposedRect:&rect
context:[NSGraphicsContext currentContext]
hints:nil];
if (img)
{
NSURL* url = [NSURL fileURLWithPath: path];
CGImageDestinationRef dest = CGImageDestinationCreateWithURL((CFURLRef)url,
(CFStringRef)newUTType,
1,
NULL);
if (dest)
{
CGImageDestinationAddImage(dest,
img,
(CFDictionaryRef)[imgSaveOptions imageProperties]);
CGImageDestinationFinalize(dest);
CFRelease(dest);
}
}
(I've trimmed a bit of extraneous code here, but nothing that would affect the outcome as far as I can see. The newUTType
comes from the IKSaveOptions
panel.)
This works fine when the file is exported as GIF, JPEG, PNG, PSD or TIFF, but exporting to PDF, BMP, TGA, ICNS and JPEG-2000 produces a red colour artefact on part of the image. Example images are below, the first exported as JPG, the second as PDF.
Copy to clipboard does not exhibit this red stripe with the current implementation of image
, but it did with the original implementation, which generated the imageRep
using NSCalibratedRGBColorSpace
rather than NSDeviceRGBColorSpace
. So I'm guessing there's some issue with the colour representation in the pixels I get from OpenGL that doesn't get through the subsequent conversions properly, but I'm at a loss as to what to do about it.
So, can anyone tell me (i) what is causing this, and (ii) how can I make it go away? I don't care so much about all of the formats but I'd really like at least PDF to work.