2010-03-03 15 views
6

Tengo un NSBitmapImageRep de 32 bits que tiene un canal alfa con valores esencialmente de 1 bit (los píxeles están activados o desactivados).¿Cómo creo un PNG de 8 bits con transparencia desde un NSBitmapImageRep?

Quiero guardar este mapa de bits en un archivo PNG de 8 bits con transparencia. Si utilizo el método -representationUsingType:properties: de NSBitmapImageRep y paso el NSPNGFileType, se crea un archivo PNG de 32 bits, que no es lo que quiero.

Sé que los PNG de 8 bits se pueden leer, se abren en Vista previa sin problemas, pero ¿es posible escribir este tipo de archivo PNG utilizando cualquier API de Mac OS X incorporada? Me complace bajar a Core Image o incluso QuickTime si es necesario. Un examen superficial de los documentos CGImage no reveló nada obvio.

EDIT: he comenzado una recompensa por esta pregunta, si alguien puede proporcionar el código fuente de trabajo que tiene una de 32 bits NSBitmapImageRep y escribe una de 256 colores PNG con transparencia de 1 bit, es suyo.

+0

8 bits como en 256 colores? Espero que no tengas más de 256 colores en la imagen. Si puede tener más de 256 colores, puede usar pngnq (empaquetarlo en su aplicación y ejecutarlo con NSTask) en su lugar: http://pngnq.sourceforge.net/ –

+0

Sí, 256 colores. Estoy buscando algo así como la salida usando '-representationUsingType: properties' con' NSGIFFileType' excepto con un PNG de 8 bits como salida. pngnq es una opción (gracias) pero espero manejarlo sin tareas de desove si es posible. –

Respuesta

1

pngnq (y new pngquant que logra una mayor calidad) tiene licencia de estilo BSD, por lo que puede simplemente incluirlo en usted r programa. No es necesario generar como una tarea separada.

+0

Esto realmente funciona, y corrige mi problema, gracias. –

0

Una cosa para intentar sería crear un NSBitmapImageRep con 8 bits y luego copiar los datos en él.

Esto realmente sería un montón de trabajo, ya que tendría que calcular la tabla de índice de color usted mismo.

+0

Correcto. La sugerencia de Peter Hosey de utilizar ** pngnq ** resuelve bastante bien este problema de creación de paletas, aunque con la necesidad de engendrar una tarea. –

2

¿Qué tal pnglib? Es realmente liviano y fácil de usar.

+0

Esta es definitivamente una opción, pero dado que no he trabajado con 'pnglib' antes de que haya mucho aprendizaje involucrado, realmente estaba esperando algo de más alto nivel. –

+0

@Rob, no hay mucho aprendizaje para pnglib, es bastante sencillo en lo que respecta a las bibliotecas C. Es posible que esté atrapado por algo más, la mayoría de las API de nivel superior asume casos más generales, lo que generalmente significa 24 o 32 imágenes de bpp. –

0

CGImageDestination es su hombre para la escritura de imágenes de bajo nivel, pero no sé si es compatible con esa capacidad específica.

+0

Sí, parece que debería ser la respuesta, pero hasta ahora no he podido encontrar la manera de especificar el tipo de PNG para crear, todo lo que intento escribe un PNG de 32 bits. –

1

una gran referencia para trabajar con las API de nivel inferior es Programming With Quartz

Parte del código a continuación se basa en ejemplos de ese libro.

Nota: Esta es la prueba del código de la ONU destinado a ser un punto de partida ....

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

Contexto Creación Función:

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

uso sería:

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

Gracias, esto funcionará muy bien para crear el mapa de bits, pero en realidad no resuelve el problema de escribir un archivo PNG de 8 colores de 256 colores. –

+0

Lo siento, dejé ese paso. Editaré mi respuesta para incluir las dos llamadas necesarias. –

+0

He investigado esto, y de acuerdo con los "Formatos de píxeles admitidos" en la Guía de programación 2D de Quartz, no es posible crear un contexto RGB de 8 bits, por lo que este código no puede funcionar. Si intenta ejecutarlo, no puede crear el contexto debido a una "combinación de parámetros inválida". http://developer.apple.com/mac/library/DOCUMENTATION/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_context/dq_context.html#//apple_ref/doc/uid/TP30001066-CH203-BCIBHHBB –

Cuestiones relacionadas