Search code examples
objective-ccore-graphicspng-8

Create Paletted CGImageRef


I'm trying to create a paletted (indexed) PNG using CoreGraphics.

The best I've found is that I can use:

CGColorSpaceRef colorSpace = CGColorSpaceCreateIndexed(CGImageGetColorSpace(maskedImage), 255, <#const unsigned char *colorTable#>);

Then:

CGImageRef palettedImage = CGImageCreateCopyWithColorSpace(maskedImage, colorSpace)

However I'm not sure what to put as the colorTable. I'd like to leverage some pre-made (fast) quantization algorithm - such as the one that is already built in to ImageIO when calling CGImageDestinationCreateWithURL(url, kUTTypeGIF , 1, NULL);

How do I create a palette for the PNG?


Solution

  • So the final solution was to do something like this:

    // Create an 8-bit palette for the bitmap via libimagequant (http://pngquant.org/lib)
    liq_attr *liqAttr = liq_attr_create();
    liq_image *liqImage = liq_image_create_rgba(liqAttr, bitmap, (int)width, (int)height, 0);
    liq_result *liqRes = liq_quantize_image(liqAttr, liqImage);
    
    liq_write_remapped_image(liqRes, liqImage, bitmap, bytesPerRow * height);
    const liq_palette *liqPal = liq_get_palette(liqRes);
    
    // Transpose the result into an rgba array
    unsigned char colorTable[1024];
    for (NSInteger n = 0; n < liqPal->count; n++) {
        colorTable[4 * n] = liqPal->entries[n].r;
        colorTable[4 * n + 1] = liqPal->entries[n].g;
        colorTable[4 * n + 2] = liqPal->entries[n].b;
        colorTable[4 * n + 3] = liqPal->entries[n].a;
    }
    
    // Release
    liq_attr_destroy(liqAttr);
    liq_image_destroy(liqImage);
    liq_result_destroy(liqRes);
    

    My hope was to use the color table to create a CGContextRef. However, according to this article: http://developer.apple.com/library/mac/#qa/qa1037/_index.html that isn't possible in any case.