У меня есть 32-разрядное NSBitmapImageRep
который имеет альфа-канал с чрезвычайно 1-разрядными значениями (пиксели или включены или выключены).
Я хочу сохранить этот битовый массив в 8-разрядный файл PNG с прозрачностью. Если я использую -representationUsingType:properties:
метод NSBitmapImageRep
и передача в NSPNGFileType
, 32-разрядный PNG создается, который не является тем, что я хочу.
Я знаю, что 8-разрядный PNGs может быть считан, они открываются в Предварительном просмотре без проблем, но действительно ли возможно записать этот тип файла PNG с помощью каких-либо встроенных API Mac OS X? Я счастлив к выпадающему к Базовому Изображению или даже QuickTime при необходимости. Поверхностное исследование CGImage
документы не показали ничего очевидного.
Править: Я запустил щедрость по этому вопросу, если кто-то может обеспечить рабочий исходный код, который берет 32-разрядное NSBitmapImageRep
и пишет PNG с 256 цветами с 1-разрядной прозрачностью, это Ваше.
pngnq (и новый pngquant , который обеспечивает более высокое качество) имеет лицензию в стиле BSD, поэтому вы можете просто включить его в свою программу. Не нужно создавать отдельную задачу.
Отличным пособием по работе с 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];
Один нужно попробовать создать NSBitmapImageRep с 8 битами, а затем скопировать в него данные.
На самом деле это потребует много работы, так как вам придется вычислять таблицу цветовых индексов самостоятельно.
CGImageDestination
ваш человек для низкоуровневого написания изображений, но я не знаю, поддерживает ли он эту особую способность.
Как насчет pnglib
? Он действительно легкий и простой в использовании.