2

概要:NSOpenGLViewから一部のファイル形式にピクセルデータをエクスポートすると、誤った色になります

私はいくつかの実験データを視覚化するためのアプリケーションを開発しています。その機能の1つは、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];
}

ファイルの書き込みには、ImageKitIKSaveOptionsアクセサリパネルを使用して出力ファイルの種類と関連するオプションを設定し、次のコードを使用して書き込みを行います。

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としてエクスポートされ、2番目の画像はPDFとしてエクスポートされます。

正しい色でJPEGとしてエクスポートされた画像
(出典:walkytalky.net

PDFとしてエクスポートされた画像、ピペットに赤いバンディング
(出典:walkytalky.net

クリップボードへのコピーでは、の現在の実装ではこの赤いストライプは表示されませんがimage。ではなくusingを生成した元の実装では表示されました。したがって、OpenGLから取得したピクセルの色表現に問題があり、その後の変換が適切に行われないと推測していますが、どうすればよいか迷っています。imageRepNSCalibratedRGBColorSpaceNSDeviceRGBColorSpace

それで、誰かが私に(i)これを引き起こしているもの、そして(ii)どうすればそれをなくすことができるか教えてもらえますか?私はすべてのフォーマットについてはあまり気にしませんが、少なくともPDFが機能することを本当に望んでいます。

4

1 に答える 1

3

わかった。この質問に出会った耳をつんざくような沈黙によって証明されるように、問題は少しあいまいであることが判明しました。ただし、回避策は素晴らしく単純なので、誰かが知りたい場合に備えて、ここで説明します。

概要:一部のファイルエクスポート形式は、レンダリングされたピクセルの半透明性にうまく対応していません。

これの正確な理由はわかりませんが、アルファの事前乗算の有無に関係している可能性があります。すべてのフォーマットは完全に透明なピクセルで問題ないように見え、フォーマットが透明性をサポートしていない場合は、それらを透明または白としてレンダリングします。ただし、部分的なアルファとカラーチャネルに何かがあるピクセルは、壊れることがあります。

たまたま、画像のどの部分も半透明にしたくglDisable(GL_BLEND)なかったので、実際に関連するレンダリングコードの前に設定しました。ただし、オブジェクトは、OpenGLホームサイトにあるこの一見標準的なコレクションのマテリアルを使用してレンダリングされました。その一部には、鏡面反射、拡散反射、および周囲色の1.0以外のアルファ値が含まれています。不必要な半透明性につながる可能性があるという事実に注意を払わずに、これを惜しみなくコピーしました。

私の目的では、解決策は簡単です。アルファコンポーネントが常に1.0になるようにマテリアル定義を変更します

PNGやTIFFなどの一部の画像形式は半透明性を完全にサポートているため、必要な場合はそれらが最適です。

実際、これが私を答えに導いたものでした。ただし、OS Xプレビューを使用してファイルを表示していたため、最初は明確ではありませんでした。また、デフォルトの表示設定では半透明性は明確ではありません。

BMPにエクスポートされた半透明のピペット
(出典:walkytalky.net

PNGにエクスポートされ、プレビューでJPGにエクスポートされた半透明のピペット
(出典:walkytalky.net

PNGにエクスポートされた半透明のピペット、プレビューで表示
(出典:walkytalky.net

Photoshopで表示されたPNGにエクスポートされた半透明のピペット
(出典:walkytalky.net

したがって、このエピソード全体からの2番目のレッスンは次のとおりです。プレビューで画像の背景を表示して、チェッカーボードを取得し、迷いの透明度を表示します。

于 2010-05-26T23:23:11.670 に答える