Проблема экспорта данных пикселей NSOpenGLView в некоторые форматы файлов изображений с использованием ImageKit & CGImageDestination - PullRequest
2 голосов
/ 21 мая 2010

Резюме: экспорт данных пикселей из 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.

Изображение экспортировано в формате JPEG с правильными цветами http://walkytalky.net/extern/ionx-jpg.jpg Изображение экспортировано в формате PDF с красной полосой на пипетке http://walkytalky.net/extern/ionx-pdf.jpg

Копировать в буфер обмена не показывает эту красную полосу с текущей реализацией image, но сделал с оригинальной реализацией, которая сгенерировала imageRep с использованием NSCalibratedRGBColorSpace вместо NSDeviceRGBColorSpace , Так что я предполагаю, что есть некоторая проблема с представлением цвета в пикселях, которое я получаю от OpenGL, который не проходит через последующие преобразования должным образом, но я не знаю, что с этим делать.

Итак, кто-нибудь может сказать мне: (i) что вызвало это, и (ii) как я могу заставить его уйти? Меня не волнует всех форматов, но я бы действительно хотел, чтобы хотя бы PDF работал.

1 Ответ

3 голосов
/ 27 мая 2010

OK. Как свидетельствует оглушительное молчание, которое встретило этот вопрос, проблема оказывается немного неясной. Но обходной путь приятен и прост, поэтому я опишу его здесь на случай, если кто-нибудь захочет узнать.

Резюме: некоторые форматы экспорта файлов плохо справляются с прозрачностью в визуализированных пикселях.

Я не понимаю точных причин этого, хотя, возможно, это как-то связано с наличием или отсутствием предварительного умножения альфа. Все форматы выглядят хорошо с полностью прозрачными пикселями, делая их прозрачными или белыми, если формат не поддерживает прозрачность. Но пиксели, которые имеют частичную альфа, плюс что-то в цветовых каналах, могут искажаться.

Как это случилось, я даже не хотел, чтобы какие-либо части изображения были полупрозрачными, и действительно установил glDisable(GL_BLEND) перед соответствующим кодом рендеринга. Однако объекты были визуализированы с использованием материалов этой, казалось бы, канонической коллекции на домашнем сайте OpenGL , некоторые из которых содержат альфа-значения, отличные от 1,0 , в их зеркальном, диффузном и окружающем цветах. Я рабски скопировал это, не обращая внимания на тот факт, что это может привести к некоторой нежелательной прозрачности.

Тогда для моих целей решение простое: измените определения материала так, чтобы альфа-компонент всегда составлял 1,0 .

Обратите внимание, что некоторые форматы изображений, такие как PNG и TIFF, do полностью поддерживают полупрозрачность, поэтому, если вам это нужно, то это те, которые нужно использовать.

На самом деле это и подтолкнуло меня к ответу. Однако вначале это было неочевидно, потому что я использовал OS X Preview для просмотра файлов, а прозрачность не очевидна при настройках вида по умолчанию:

полупрозрачная пипетка при экспорте в BMP http://walkytalky.net/extern/wbmp.jpg полупрозрачная пипетка, экспортируемая в PNG, а затем в JPG в Preview http://walkytalky.net/extern/without-alpha.jpg

полупрозрачная пипетка, экспортируемая в PNG, в предварительном просмотре http://walkytalky.net/extern/wpreview.jpg полупрозрачная пипетка, экспортированная в PNG, при просмотре в Photoshop http://walkytalky.net/extern/with-alpha.jpg

Итак, второй урок из всего этого эпизода: enable View | Отобразите фоновый рисунок в режиме предварительного просмотра, чтобы получить шахматную доску и отобразить любую прозрачную прозрачность.

...