2010-03-03 4 views
6

У меня есть 32-разрядный NSBitmapImageRep, который имеет альфа-канал с существенно 1-битовыми значениями (пиксели включены или выключены).Как создать 8-битный PNG с прозрачностью из NSBitmapImageRep?

Я хочу сохранить это растровое изображение в 8-битный PNG-файл с прозрачностью. Если я использую метод -representationUsingType:properties:NSBitmapImageRep и передаю его в NSPNGFileType, создается 32-разрядный PNG, что не то, что я хочу.

Я знаю, что 8-битные PNG могут быть прочитаны, они открыты в Preview без проблем, но возможно ли записать этот тип PNG-файла с помощью любых встроенных API Mac OS X? Я рад, если это необходимо, спуститься к Core Image или даже QuickTime. Беглый осмотр документов CGImage не показал ничего очевидного.

EDIT: Я начал баунтите по этому вопросу, если кто-то может предоставить рабочий исходный код, который занимает 32-разрядную NSBitmapImageRep и записывает в 256-цветный PNG с 1-битной прозрачностью, она твоя.

+0

8-бит, как в 256-цветном? Надеюсь, у вас на изображении не более 256 цветов. Если у вас может быть более 256 цветов, вы можете использовать pngnq (добавив его в приложение и запуская его с помощью NSTask): http://pngnq.sourceforge.net/ –

+0

Да, 256 цветов. Я ищу что-то вроде вывода с использованием '-representationUsingType: properties' с' NSGIFFileType', за исключением 8-битного PNG в качестве вывода. pngnq - это вариант (спасибо), но я надеюсь обработать его без нереста задач, если это вообще возможно. –

ответ

1

pngnq (и new pngquant, который достигает более высокого качества) имеет лицензию BSD-стиля, поэтому вы можете просто включить ее в себя r. Не нужно создавать отдельную задачу.

+0

Это действительно работает и исправляет мои проблема, спасибо. –

0

Одна вещь, которую нужно попробовать, - создать NSBitmapImageRep с 8 битами, а затем скопировать данные на него.

На самом деле это будет очень много работы, так как вам придется самому вычислить таблицу цветовых индексов.

+0

Исправить. Предложение Peter Hosey об использовании ** pngnq ** решает эту проблему с созданием палитры довольно хорошо, хотя и требует появления задачи. –

2

Как насчет pnglib? Это очень легкий и простой в использовании.

+0

Это определенно вариант, но поскольку я не работал с 'pnglib', прежде чем учатся многие учащиеся, я действительно надеялся на что-то более высокоуровневое. –

+0

@Rob, для pnglib не так много обучения, это действительно довольно просто, поскольку библиотеки C идут. Возможно, вы застряли в чем-то другом, большинство API более высокого уровня предполагают более общие случаи, что обычно означает 24 или 32 bpp изображения. –

0

CGImageDestination Ваш человек для написания низкоуровневого изображения, но я не знаю, поддерживает ли он эту конкретную способность.

+0

Да, похоже, это должен быть ответ, но до сих пор мне не удалось найти способ указать тип PNG для создания, все, что я пытаюсь записать 32-разрядный PNG. –

1

Большой справочник для работы с API, более низкого уровня является Programming With Quartz

Некоторые из кода ниже основано на примерах из этой книги.

Примечание: Это не-тестирование кода предназначается, чтобы быть всего лишь отправная точка ....

- (NSBitmapImageRep*)convertImageRep:(NSBitmapImageRep*)startingImage{ 

    CGImageRef anImage = [startingImage CGImage]; 

    CGContextRef bitmapContext; 
    CGRect ctxRect; 
    size_t bytesPerRow, width, height; 

    width = CGImageGetWidth(anImage); 
    height = CGImageGetHeight(anImage); 
    ctxRect = CGRectMake(0.0, 0.0, width, height); 
    bytesPerRow = (width * 4 + 63) & ~63; 
    bitmapData = calloc(bytesPerRow * height, 1); 
    bitmapContext = createRGBBitmapContext(width, height, TRUE); 
    CGContextDrawImage (bitmapContext, ctxRect, anImage); 

    //Now extract the image from the context 
    CGImageRef  bitmapImage = nil; 
    bitmapImage = CGBitmapContextCreateImage(bitmapContext); 
    if(!bitmapImage){ 
     fprintf(stderr, "Couldn't create the image!\n"); 
     return nil; 
    } 

    NSBitmapImageRep *newImage = [[NSBitmapImageRep alloc] initWithCGImage:bitmapImage]; 
    return newImage; 
} 

Контекст Создание функции:

CGContextRef createRGBBitmapContext(size_t width, size_t height, Boolean needsTransparentBitmap) 
{ 
    CGContextRef context; 
    size_t bytesPerRow; 
    unsigned char *rasterData; 

    //minimum bytes per row is 4 bytes per sample * number of samples 
    bytesPerRow = width*4; 
    //round up to nearest multiple of 16. 
    bytesPerRow = COMPUTE_BEST_BYTES_PER_ROW(bytesPerRow); 

    int bitsPerComponent = 2; // to get 256 colors (2xRGBA) 

    //use function 'calloc' so memory is initialized to 0. 
    rasterData = calloc(1, bytesPerRow * height); 
    if(rasterData == NULL){ 
     fprintf(stderr, "Couldn't allocate the needed amount of memory!\n"); 
     return NULL; 
    } 

    // uses the generic calibrated RGB color space. 
    context = CGBitmapContextCreate(rasterData, width, height, bitsPerComponent, bytesPerRow, 
            CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), 
            (needsTransparentBitmap ? kCGImageAlphaPremultipliedFirst : 
            kCGImageAlphaNoneSkipFirst) 
            ); 
    if(context == NULL){ 
     free(rasterData); 
     fprintf(stderr, "Couldn't create the context!\n"); 
     return NULL; 
    } 

    //Either clear the rect or paint with opaque white, 
    if(needsTransparentBitmap){ 
     CGContextClearRect(context, CGRectMake(0, 0, width, height)); 
    }else{ 
     CGContextSaveGState(context); 
     CGContextSetFillColorWithColor(context, getRGBOpaqueWhiteColor()); 
     CGContextFillRect(context, CGRectMake(0, 0, width, height)); 
     CGContextRestoreGState(context); 
    } 
    return context; 
} 

Использование будет:

NSBitmapImageRep *startingImage; // assumed to be previously set. 
NSBitmapImageRep *endingImageRep = [self convertImageRep:startingImage]; 
// Write out as data 
NSData *outputData = [endingImageRep representationUsingType:NSPNGFileType properties:nil]; 
// somePath is set elsewhere 
[outputData writeToFile:somePath atomically:YES]; 
+0

Спасибо, это будет хорошо работать для создания растрового изображения, но на самом деле оно не решает проблему записи 256-цветного 8-битного PNG-файла. –

+0

Извините, я оставил этот шаг. Я отредактирую свой ответ, чтобы включить эти два вызова. –

+0

Я рассмотрел это, и в соответствии с «Поддерживаемые пиксельные форматы» в двумерном программировании кварца невозможно создать 8-битный контекст RGB, поэтому этот код не может работать. Если вы попытаетесь запустить его, он не сможет создать контекст из-за «недопустимой комбинации параметров». http://developer.apple.com/mac/library/DOCUMENTATION/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB –