Редактирование 8bpp индексированных растровых изображений

Я пытаюсь редактировать пиксели 8bpp. Поскольку этот PixelFormat проиндексирован, я знаю, что он использует таблицу цветов для сопоставления значений пикселей. Несмотря на то, что я могу редактировать растровое изображение, преобразовав его в 24bpp, редактирование 8bpp происходит намного быстрее (13мс против 3мс). Но изменение каждого значения при доступе к битовой карте 8bpp приводит к некоторым случайным цветам RGB, даже если PixelFormat остается 8bpp.

В настоящее время я разрабатываю на C# и алгоритм выглядит следующим образом:

(С #)

1 - загрузить оригинальный растровое изображение в 8bpp

2- Создайте пустое временное растровое изображение с 8bpp того же размера, что и оригинал.

3-LockBits обоих растровых изображений и, используя P/Invoke, вызов метода C++, где я передаю Scan0 каждого объекта BitmapData. (Я использовал метод C++, так как он предлагает лучшую производительность при итерации по пикселям растрового изображения)

(C++)

4. Создайте палитру int[256] в соответствии с некоторыми параметрами и отредактируйте байты временного растрового изображения, передавая значения пикселей оригинала через палитру.

(С #)

5- Разблокировать биты.

Мой вопрос: как я могу редактировать значения пикселей, не имея странных цветов RGB, или, что еще лучше, редактировать таблицу цветов растрового изображения 8bpp?

3 ответа

Нет необходимости переходить в C++ или использовать P/Invoke вообще; C# прекрасно поддерживает указатели и небезопасный код; Я могу даже рискнуть предположить, что это вызывает ваши проблемы.

Цвета, вероятно, приходят из палитры по умолчанию. Вы обнаружите, что изменение палитры не должно быть медленным. Вот что я делаю, чтобы создать палитру оттенков серого:

image = new Bitmap( _size.Width, _size.Height, PixelFormat.Format8bppIndexed);
ColorPalette pal = image.Palette;
for(int i=0;i<=255;i++) {
    // create greyscale color table
    pal.Entries[i] = Color.FromArgb(i, i, i);
}
image.Palette = pal; // you need to re-set this property to force the new ColorPalette

Представьте, что ваш индексированный серый цвет 8ppp хранится в линейном массиве dataB (для скорости)

Попробуйте этот код:

//Create 8bpp bitmap and look bitmap data
bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
bmp.SetResolution(horizontalResolution, verticalResolution);
bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), System.Drawing.Imaging.ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

//Create grayscale color table
ColorPalette palette = bmp.Palette;
for (int i = 0; i < 256; i++)
    palette.Entries[i] = Color.FromArgb(i, i, i);
bmp.Palette = palette;

//write data to bitmap
int dataCount = 0;
int stride = bmpData.Stride < 0 ? -bmpData.Stride : bmpData.Stride;
unsafe
{
    byte* row = (byte*)bmpData.Scan0;
    for (int f = 0; f < height; f++)
    {
        for (int w = 0; w < width; w++)
        {
            row[w] = (byte)Math.Min(255, Math.Max(0, dataB[dataCount]));
            dataCount++;
        }
        row += stride;
    }
}

//Unlock bitmap data
bmp.UnlockBits(bmpData);

Вы пытались загрузить System.Drawing.Image вместо? Этот класс дает вам доступ к цветовой палитре. Вы можете обернуть System.Drawing.Image как System.Drawing.Bitmap как только палитра установлена.

Я не уверен как System.Drawing.BitMap.SetPixel() работает с индексированными цветными изображениями. Возможно, он пытается сопоставить его с ближайшим цветом в палитре.

У меня недостаточно репутации, чтобы комментировать пост Пола Руэйна, но мне пришлось сказать, что он подходил к загрузке файла в System.Drawing.Image изменив палитру и отправив полученное изображение в System.Drawing.Bitmap сохранить на самом деле работает.

> Если я сохраню напрямую через Image , изменения будут отменены.

> Если я сохраню через Bitmap изменения сохраняются.

Другие вопросы по тегам