I have been writing a PCX decoder and, so far, the PCX image itself parses fine, but I can't work out how to set the palette of a bitmap.
I have created a bitmap like so:
Bitmap bmp = new Bitmap(width,
height,
stride2,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed,
pixels);
But I can't seem to set the palette using the following method:
for (int i = 0; i < 256; i += 3)
{
Color b = new Color();
b = Color.FromArgb(palette[i], palette[i + 1], palette[i + 2]);
bmp.Palette.Entries.SetValue(b, i);
}
In this example, I have read through each byte in the palette of the pcx file and stored them in palette[]. from there, I have used this to set the entries in the palette of the bitmap. How do I set the colours?
This had me confused too. It seems bitmap.Palette returns a clone of the bitmap's palette. Once you've modified your copy, you need to reset the bitmap's pallete by using bitmap.Palette = palette
, e.g.
ColorPalette palette = bitmap.Palette;
Color entries = palette.Entries;
....
entries[i] = new Color(...);
....
bitmap.Palette = palette; // The crucial statement
See http://www.charlespetzold.com/pwcs/PaletteChange.html
According to Microsoft Reference Source, Palette
property of Image
class in .net, internally uses GDI+ Flat APIs for handling palettes. GdipGetImagePalette
used for initializing ColorPalette
object in get
method and GdipSetImagePalette
used for writing ColorPalette
object data back to device is set
method.
Each time in your for
loop the line bmp.Palette.Entries.SetValue(b, i);
forces the Image to call GdipGetImagePalette
and data of bmp.Palette
reinitialized and therefore you can see no change has been made to bmp.Palette
after the loop.
To solve this problem you must do the following:
- Assign new alias to
bmp.Palette
by assigning it to a variable,
- Modify it by new alias (this prevents reloading),
- And put it back to the
bmp.Palette
.
Code:
var newAliasForPalette = bmp.Palette; // Palette loaded from graphic device
for (int i = 0; i < 256; i++)
{
newAliasForPalette.Entries[i] = myColor[i];
}
bmp.Palette = newAliasForPalette; // Palette data wrote back to the graphic device
In my opinion, replacement of definition of Palette
as a property with GetPalette()
and SetPalette()
methods by Microsoft, will be a great help in avoiding confusion.