1

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.

Hammerite
  • 21,755
  • 6
  • 70
  • 91
  • What are you targeting: Winforms, WPF, ASP..? YOU should __always__ TAG your questions correctly so one can see it on the questions page! - In case you want to use GDI+ note that its support for indexed files is rather limited. You can create a bitmap (`Bitmap bmp = new Bitmap(500, 500, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);`) but you can't get a Graphics object to draw onto it.. – TaW Nov 12 '22 at 23:17
  • @TaW sorry what tag is missing? I'm able to replicate the issue just fine with what has been provided. This seems to be correctly tagged as a question regarding the framework itself. Granted I'm testing with `.Net7` and OP may be using a different one but considering 7 is the latest and behaves the same... Seem good enough to me anyway. – Joe_DM Nov 12 '22 at 23:20
  • I'm manipulating image files from a console application. I'm not interested in displaying graphics to the user at all. – Hammerite Nov 12 '22 at 23:31
  • I draw on the 1 BPP and 8 BPP images I create just fine from unsafe code. – Hammerite Nov 12 '22 at 23:32
  • Have you seen [this](https://stackoverflow.com/a/45100442/1911064) very elaborate answer? – Axel Kemper Nov 13 '22 at 00:09
  • I had not, Axel. Thank you for linking it. I am going to bed now but I will be reading it tomorrow or on Monday. – Hammerite Nov 13 '22 at 00:13

2 Answers2

0

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());
}
Axel Kemper
  • 10,544
  • 2
  • 31
  • 54
0

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)

Hammerite
  • 21,755
  • 6
  • 70
  • 91