Pregunta

Tengo un NSBitmapImageRep de 32 bits que tiene un canal alfa con esencialmente los valores de 1 bit (los píxeles son encendido o apagado).

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

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

EDIT: He empezado una recompensa por esta pregunta, si alguien puede proporcionar el código fuente de trabajo que toma un NSBitmapImageRep de 32 bits y escribe un archivo PNG de 256 colores con la transparencia de 1 bit, es suyo.

¿Fue útil?

Solución

pngnq (y nueva pngquant que logra una mayor calidad) tiene licencia BSD, por lo que sólo puede incluirlo en su programa. No hay necesidad de desove como tarea independiente.

Otros consejos

¿Qué hay de pnglib ? Es muy ligero y fácil de usar.

Una gran referencia para trabajar con las API de nivel inferior es de programación con cuarzo

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

Nota: Este es el código de un-probado destinado a ser un punto de partida solamente ....

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

Creación Contexto 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;
}

El 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];

Una cosa a tratar sería la creación de un NSBitmapImageRep con 8 bits, a continuación, copiar los datos en él.

En realidad, esto sería mucho trabajo, ya que tendría que calcular la tabla de índice de color usted mismo.

CGImageDestination es su hombre para la escritura de la imagen de bajo nivel, pero no sé si es compatible con esa habilidad específica.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top