I have a series of PNG images that use indices into a palette for color (PNG color type 3). In some cases, I need to make a copy of an image where some of the entries in the palette are modified. In this way we recolor a source PNG over and over.
In Java, this is handled by getting the RGB values from an IndexedColorModel
, modifying the values and creating a new IndexedColorModel
, and creating a new BufferedImage
with the source image's raster data and the new color model.
In Actionscript, I had to read in the PNG bytes as a bare ByteArray
, find the palette chunk, modify the values, then have the runtime load up the image from the ByteArray
.
I'm now looking to implement the same system for iOS via MonoTouch (which I'm new to), but I've hit a wall. I believe the Actionscript approach would work here as well, but it would be nice to avoid working at such a low level this time, and it looks like I can get close.
If I'm starting from a UIImage
, I can get the color space with UIImage.CGImage.ColorSpace
. I can verify that it's an indexed color model with colorSpace.Model
. What I'm not sure about is how I get the actual array of palette bytes.
And then on the other side, how do I create a new image with the new palette? CGImage.WithColorSpace
looks like it would do what I want... maybe? And then I have to be able to create a color space with my new palette: On the surface, CGColorSpace.CreateIndexed
looks like what I want, but I'm unclear on how the baseSpace
parameter is used. I want to create a CGColorSpace
with a totally new color palette that I provide, and then use the original image's indices with the new palette. Maybe I'm misunderstanding exactly what CGColorSpace
is used for.
That's a bit brute but it would work. However I'm pretty sure CoreGraphics has everything you need to avoid this.
Since you'll be using CoreGraphics (CG) anyway you can start with a
CGImage
. Sample code (objc) here: iPhone SDK: accessing indexed color PNG imagesCGColorSpaceGetColorTable
looks like the perfect candidate. However it looks like it's missing from MonoTouch bindings (I'll check that) but it would be easy (it's a p/invoke) to bind manually and use in your application.CGColorSpace.CreateIndexed
can accept anull
parameter forbaseSpace
but you might be better copying the same, base, GCColorSpace from the original PNG image.