Why am I getting an exception when using SetPixel: SetPixel is not supported for images with indexed pixel formats?

At the top of the class I am doing:

private static Bitmap bmp2 = new Bitmap(@"C:\Temp\New folder (17)\radar001486.GIF");

      

Then, inside the method I am doing:

private void test()
   {
    int current_list_length = pointtocolor.Count;
                for (int kk=0;kk<current_list_length;kk++)
                {

                    PointF pt = pointtocolor[kk];
                    e.FillEllipse(cloudColors[cloudColorIndex], pt.X * (float)currentFactor, pt.Y * (float)currentFactor, radius, radius);
                    bmp2.SetPixel((int)pt.X * (int)currentFactor, (int)pt.Y * (int)currentFactor, Color.Yellow);

                }
                bmp2.Save(@"c:\temp\yellowbmpcolor.bmp");
   }

      

As soon as it gets inside the loop, it throws an exception at the line:

bmp2.SetPixel((int)pt.X * (int)currentFactor, (int)pt.Y * (int)currentFactor, Color.Yellow);

      

If I change the bmp2 instance to:

private static Bitmap bmp2 = new Bitmap(@"C:\Temp\New folder (17)\radar001486.GIF");

      

For

private static Bitmap bmp2 = new Bitmap(512,512);

      

Then it will work, but I want the SetPixel pixels on top of the original radar001486.GIF, not on a new blank Bitmap.

+3


source to share


3 answers


The problem is you are using GIF as it has indexed pixels. Try converting it to png if you can; or if you can't, turn it into a non-indexed image using:

public Bitmap CreateNonIndexedImage(Image src)
{
    Bitmap newBmp = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

    using (Graphics gfx = Graphics.FromImage(newBmp)) {
        gfx.DrawImage(src, 0, 0);
    }

    return newBmp;
}

      



Note. If you have the ability to do this (for example, unloaded images, or you have access to the server), define their conversion to PNG.

+5


source


The image you are trying to modify is an indexed GIF. This means that the image does not contain a series of pixels with the corresponding color values ​​(as your new one does Bitmap

); rather, it contains a color palette combined with a series of pixels with index values ​​in the palette. The pixel format of your image loaded from disk is probably similar to Format8bppIndexed

.

You cannot use SetPixel

for this type of image because you SetPixel

want to directly set the R, G and B values ​​for the pixel. This is not how an indexed image works.



To change this kind of image, you have several options:

  • Your best bet is WPF, which has GifBitmapEncoder and GifBitmapDecoder . This allows you to decode GIF data into something WPF can draw and then convert back. Since this uses DirectX and not GDI +, it has no limitation on things like SetPixel

    . I would really like to suggest that you go this route if possible, but if not:

  • Use GDI + to Convert image to non-indexed image type, change it and convert it back . This is usually a terrible idea: GDI + and indexed formats don't get along well, and that involves encoding the bitmap as an indexed GIF. The image quality is likely to be terrible.

  • Edit the byte data directly. To do this, you need to extract the GIF data into an array and set the pixels to the correct indexed values. The trick here is determining the correct index value; or, if the palette appears to be empty, you can simply add another one. You need to dig deeper into GIF to understand this, although it will probably be the most efficient in terms of both space and speed without compromising image quality. When you know what the index value to write is, you do something like this:

    var data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), 
        ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
    
    var bytes = new byte[data.Height * data.Stride];
    Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);
    
    bytes[5 * data.Stride + 5] = 1; // Set the pixel at (5, 5) to the color #1
    
    Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
    
    image.UnlockBits(data);
    
          

+2


source


The problem is with your image type as it works fine with .jpeg. You can get Bitmap from Image

Try changing to this:

private static Bitmap bmp2 = new Bitmap(Image.FromFile(@"C:\Temp\New folder (17)\radar001486.GIF"));

      

Here is my complete test code:

    private Bitmap bmp2 = new Bitmap(Image.FromFile(@"e:\temp\temp\yourGIF.gif"));
    public Form1()
    {
        InitializeComponent();
        pictureBox1.Image = bmp2;
    }

    private void button2_Click(object sender, EventArgs e)
    {
        var sz = bmp2.Size;
        for(int x= 0; x<sz.Width; x++)
        {
            for(int y=0; y<sz.Height; y++)
            {
                bmp2.SetPixel(x, y, Color.Yellow);
            }
        }
        pictureBox1.Refresh();
    }

      

0


source







All Articles