使用ImageKit& amp;将NSOpenGLView像素数据导出为某些图像文件格式时出现问题CGImageDestination

时间:2010-05-20 23:02:46

标签: cocoa macos opengl nsopenglview

摘要:将像素数据从NSOpenGLView导出到某些文件格式会产生错误的颜色

我正在开发一个可视化一些实验数据的应用程序。它的一个功能是在NSOpenGLView子类中呈现数据,并允许将生成的图像导出到文件或复制到剪贴板。

视图将数据导出为NSImage,生成如下:

- (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;
}

复制非常简单地使用此图像,如下所示:

- (IBAction) copy:(id) sender
{
    NSImage* img = [self image];
    NSPasteboard* pb = [NSPasteboard generalPasteboard];
    [pb clearContents];
    NSArray* copied = [NSArray arrayWithObject:img];
    [pb writeObjects:copied];
}

对于文件编写,我使用ImageKit IKSaveOptions附件面板设置输出文件类型和相关选项,然后使用以下代码进行编写:

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);
    }
}

(我在这里修剪了一些无关的代码,但是就我所见,没有什么会影响结果。newUTType来自IKSaveOptions小组。)

当文件导出为GIF,JPEG,PNG,PSD或TIFF时,此工作正常,但导出为PDF,BMP,TGA,ICNS和JPEG-2000会在图像的一部分上产生红色伪影。示例图像如下,第一个导出为JPG,第二个导出为PDF。

Image exported as JPEG, with colours correct http://walkytalky.net/extern/ionx-jpg.jpg Image exported as PDF, with red banding on pipette http://walkytalky.net/extern/ionx-pdf.jpg

复制到剪贴板时,image的当前实现没有显示此红色条带,但 与原始实现,后者使用{{1}生成imageRep而不是NSCalibratedRGBColorSpace。所以我猜测我从OpenGL获得的像素中的颜色表示存在一些问题,这些问题没有得到正确的后续转换,但是我不知道如何处理它。

那么,任何人都可以告诉我(i)造成这种情况的原因,以及(ii)我怎样才能让它消失?我并不在乎所有格式,但我真的至少像PDF一样工作。

1 个答案:

答案 0 :(得分:3)

行。正如震耳欲聋的沉默所证明的那样,这个问题变得有点模糊。但是解决方法很简单,所以我在这里描述它以防万一有人想知道。

摘要:某些文件导出格式无法很好地处理渲染像素中的半透明效果。

我不明白这个的确切原因,尽管它可能与alpha预乘的存在与否有关。对于完全透明的像素,所有格式似乎都很好,如果格式不支持透明度,则将它们渲染为透明或白色。但是,具有部分alpha的像素加上颜色通道中的某些内容可能会受到损坏。

碰巧的是,我甚至没有希望图像的任何部分都是半透明的,并且确实在相关的渲染代码之前设置了glDisable(GL_BLEND)。但是,使用来自this seemingly-canonical collection at the OpenGL home site的材质渲染对象,其中一些在其镜面反射,漫反射和环境颜色中包含除<1.0>以外的Alpha值。我曾盲目地复制了这个,却没有注意到这可能导致一些不必要的半透明的事实。

就我的目的而言,解决方案很简单:更改材质定义,使alpha组件始终为1.0

请注意,某些图片格式(例如PNG和TIFF, )完全支持半透明效果,因此如果您需要,则可以使用这些格式。

事实上,这让我想到了答案。然而,起初并不明显,因为我使用OS X Preview来查看文件,并且使用默认视图设置时半透明度不明显:

translucent pipette as exported to BMP http://walkytalky.net/extern/wbmp.jpg translucent pipette as exported to PNG and thence JPG in Preview http://walkytalky.net/extern/without-alpha.jpg

translucent pipette as exported to PNG, viewed in Preview http://walkytalky.net/extern/wpreview.jpg translucent pipette as exported to PNG, viewed in Photoshop http://walkytalky.net/extern/with-alpha.jpg

因此,整集的第二个教训是:启用查看|在预览中显示图像背景以获取棋盘并显示任何杂散透明度。