Home > OS >  How do I open a bitmap without C# changing the PixelFormat?
How do I open a bitmap without C# changing the PixelFormat?

Time:11-13

I have a bitmap image, myImage.png say. The png has been saved with pixel format Format8bppIndexed, which is something I specifically chose to do. But when I open it in C# using new Bitmap("myImage.png"), I find that it is provided to me as a bitmap in format Format32bppRgb. This isn't what I want, which is why I didn't save it in that format.

I've written code specifically to do turtle-graphics manipulation of a 256-colour indexed raster image; I don't want to rewrite that code to do it with a 32bpp image; I don't see why I should have to. How do I force C# to open my image and just give it to me as it comes, without converting it to a different pixel format? I need an overload of the Bitmap constructor that tells it, "don't try to be helpful, I know what I'm doing". But I can't see one.

If I load an image that's in Format1bppIndexed, C# doesn't do this - I get the binary PNG just as it is, not converted at all.

CodePudding user response:

Under .NET Framework 4.8 and .NET 6.0 for Windows, all four alternatives work for me.
Resulting format is Format8bppIndexed

var imagePath = "image1.png";

using (var bm1 = new Bitmap(imagePath))
{
    Console.WriteLine(bm1.PixelFormat.ToString());
}

using (Stream stream = new FileStream(imagePath, FileMode.Open))
{
    var bm2 = new Bitmap(stream);

    Console.WriteLine(bm2.PixelFormat.ToString());
}

using (Stream stream = new FileStream(imagePath, FileMode.Open))
{
    var bm3 = new Bitmap(stream, useIcm: true);

    Console.WriteLine(bm3.PixelFormat.ToString());
}

using (var bm4 = new Bitmap(imagePath, useIcm: true))
{
    Console.WriteLine(bm4.PixelFormat.ToString());
}

CodePudding user response:

The question and answer linked by Axel substantially answers the question. Here are some details of how I solved my problem.

The problem occurs when you try to open an 8bpp (256-colour indexed) PNG that has palette entries that specify transparency (alpha values less than 255). It does not matter whether the palette entry is actually used for any pixels in the image; the fact that the palette entry exists is enough to cause the problem. When an 8bpp bitmap is created using the System.Drawing library, it is given a default palette, and this default palette may contain colours with transparency, so it may cause this problem if you do not overwrite those palette entries.

There is no easy fix for the issue if you already have the PNG file or if you need to support transparency. In my case I do not actually need transparency in the images I am working with. It was easy enough for me to change the code that creates the PNG files so that it overwrites all the palette entries with dummy entries that are opaque (alpha values of 255).

public static void SetPalette(Bitmap bmp, int numEntriesExcludingBackground)
{
    // Ref. https://stackoverflow.com/a/51111141
    var palette = bmp.Palette;

    int index = 1;
    foreach (var entry in GeneratePaletteEntries(numEntriesExcludingBackground))
    {
        palette.Entries[index] = entry;
          index;
    }

    for (; index < palette.Entries.Length;   index)                // *
    {                                                              // *
        palette.Entries[index] = GenerateDummyPaletteEntry(index); // *
    }                                                              // *

    bmp.Palette = palette;
}

(the "//*" decorates lines that were added to address this problem)

  • Related