Почему я получаю исключение при использовании SetPixel: SetPixel не поддерживается для изображений с индексированными пиксельными форматами?

3

В верхней части класса, который я делаю:

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

Затем внутри метода, который я делаю:

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");
   }

Как только он попадает внутрь цикла, он делает исключение в строке:

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

Если я изменю экземпляр bmp2 на:

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

Для

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

Затем он будет работать, но я хочу, чтобы SetPixel пиксели поверх исходного радара001486.GIF, а не на новом пустом Bitmap.

  • 0
    Проблема, с которой сталкивается SetPixel, заключается в том, что указанный вами цвет может отсутствовать в текущей палитре.
  • 0
    Вы можете проверить этот пост, где это та же тема [ссылка] [1] [1]: stackoverflow.com/questions/2840138/…
Теги:
winforms

3 ответа

5
Лучший ответ

Проблема в том, что вы используете GIF, поскольку он имеет индексированные пиксели. Попробуйте преобразовать его в png, если сможете; или если вы не можете, превратите его в неиндексированное изображение, используя:

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;
}

Примечание. Если у вас есть возможность сделать это (например, незагруженные изображения или у вас есть доступ к серверу), определите их преобразование в PNG.

  • 0
    Дракор это работает. Файлы на веб-сайте, который я загружаю, имеют формат GIF. Должен ли я сохранить их как PNG? Или они делают это сейчас, используя ваше решение? Потерял ли новый биткарт newBmp некоторые данные (пиксели)?
  • 0
    Нет, вы просто используете графический процессор телефона для рендеринга изображения в другое изображение. Я сказал не использовать его, если вам не нужно, потому что это несколько ресурсоемко, но для нескольких изображений это рабочее решение.
Показать ещё 3 комментария
2

Изображение, которое вы пытаетесь изменить, - это индексированный GIF. Это означает, что изображение не содержит серию пикселей с соответствующими значениями цвета (как это делает ваш новый Bitmap); скорее, он содержит цветовую палитру в сочетании с серией пикселей со значениями индекса в палитре. Формат пикселя вашего изображения, загруженного с диска, вероятно, похож на Format8bppIndexed.

Вы не можете использовать SetPixel для этого типа изображения, потому что SetPixel хочет напрямую установить значения R, G и B для пикселя. Это не то, как работает индексированное изображение.

Чтобы изменить этот вид изображения, у вас есть несколько вариантов:

  • Лучше всего использовать WPF, который имеет GifBitmapEncoder и GifBitmapDecoder. Это позволяет вам декодировать данные GIF во что-то, что WPF может нарисовать, а затем преобразовать обратно. Поскольку это использует DirectX, а не GDI +, у него нет ограничений таких вещей, как SetPixel. Я действительно хотел бы предложить вам пойти по этому маршруту, если это возможно, но если нет:

  • Используйте GDI + для Преобразовать изображение в неиндексированный тип изображения, измените его и convert он вернулся. Это, как правило, ужасная идея: GDI + и индексированные форматы не ладят друг с другом, и это включает кодирование растрового изображения в качестве индексированного GIF. Качество изображения, вероятно, будет ужасным.

  • Отредактируйте данные байта напрямую. Для этого вам нужно извлечь данные GIF в массив и установить пиксели в правильные индексированные значения. Фокус здесь заключается в определении правильного значения индекса; или, если в палитре окажется пустой, вы можете просто добавить еще один. Вам нужно углубиться в формат GIF, чтобы понять это, хотя он, вероятно, будет наиболее эффективным с точки зрения как пространства, так и скорости без снижения качества изображения. Когда вы знаете, какое значение индекса для записи, вы делаете что-то вроде этого:

    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);
    
0

Проблема заключается в вашем типе изображения, так как он отлично работает с .jpeg. Вы можете получить Bitmap из Image

Попробуйте изменить на это:

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

Вот мой полный тестовый код:

    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();
    }

Ещё вопросы

Сообщество Overcoder
Наверх
Меню