Problem exporting NSOpenGLView pixel data to some image file formats using ImageKit & CGImageDestina

Posted by walkytalky on Stack Overflow See other posts from Stack Overflow or by walkytalky
Published on 2010-05-20T23:02:45Z Indexed on 2010/05/21 21:10 UTC
Read the original article Hit count: 330

Filed under:
|
|
|

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.

Image exported as JPEG, with colours correct Image exported as PDF, with red banding on pipette

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.

© Stack Overflow or respective owner

Related posts about cocoa

Related posts about mac