С# Преобразование 32bpp изображения в 8bpp
Я пытаюсь преобразовать изображение скриншота 32bpp в формат 8bpp (или 4bpp или 1bpp) с помощью С#. Я уже рассмотрел несколько ответов stackoverflow на похожие темы, и большинство из них предлагает варианты с использованием следующего кода:
public static Bitmap Convert(Bitmap oldbmp)
{
Bitmap newbmp = new Bitmap(oldbmp.Width, oldbmp.Height, PixelFormat.Format8bppIndexed);
Graphics gr = Graphics.FromImage(newbmp);
gr.PageUnit = GraphicsUnit.Pixel;
gr.DrawImageUnscaled(oldbmp, 0, 0);
return newbmp;
}
Однако, когда это выполняется, я получаю исключение: A graphics object cannot be created from an image that has an indexed pixel format
. Я понимаю, что изображения 8, 4 и 1bpp имеют сопоставления таблиц цветов, а не сами пиксели изображения (как в 32 или 16bpp-изображениях), поэтому я предполагаю, что я где-то пропускаю какой-то шаг преобразования, но я довольно новичок в С# с фона на С++) и предпочли бы, чтобы это можно было использовать с использованием собственных вызовов С#, а не прибегать к PInvoking BitBlt
и GetDIBits
и т.д. Кто-нибудь может помочь мне решить эту проблему? Спасибо.
EDIT: я должен указать, что мне нужно, чтобы это было обратно совместимо с .NET framework 2.0
Ответы
Ответ 1
GDI + в целом имеет очень плохую поддержку индексированных форматов пикселей. Нет простого способа конвертировать изображение с 65536 или 16 миллионами цветов в один, который имеет только 2, 16 или 256. Цвета должны быть удалены из исходного изображения, и это преобразование с потерями, которое может иметь очень плохие результаты. Для этого есть несколько алгоритмов, ни одна из них не идеальна для каждого изображения. Это задание для графического редактора.
Есть один трюк, который я нашел. GDI + имеет кодировщик изображений для файлов GIF. Что графический формат, который имеет только 256 цветов, кодировщик должен ограничивать количество цветов. Он использует алгоритм сглаживания, подходящий для фотографий. У этого есть умение генерировать сетку, вы будете менее чем взволнованы, когда это произойдет. Используйте его так:
public static Image Convert(Bitmap oldbmp) {
using (var ms = new MemoryStream()) {
oldbmp.Save(ms, ImageFormat.Gif);
ms.Position = 0;
return Image.FromStream(ms);
}
}
Возвращаемое изображение имеет формат пикселя 8bpp с позициями палитры, вычисленными кодером. При необходимости вы можете использовать его для растрового изображения. Безусловно, лучше всего просто не беспокоиться об индексированных форматах. Они относятся к каменному возрасту вычислений, когда память сильно ограничена. Или используйте профессиональный графический редактор.
Ответ 2
AForge библиотека отлично справляется с использованием Оттенки серого.
var bmp8bpp = Grayscale.CommonAlgorithms.BT709.Apply(bmp);
Этот класс является базовым классом для масштабирования изображений [...] Фильтр принимает цветные изображения 24, 32, 48 и 64 bpp и производит 8 (если источником является 24 или 32 bpp изображения) или 16 (если источник 48 или 64 bpp image) Изображение в черно-белом режиме bpp.
Ответ 3
Отрицательный шаг означает, что изображение снизу вверх (инвертировано). Просто используйте абсолют шага, если вы не заботитесь. Я знаю, что работает для 24bpp-изображений, не подозревая, работает ли он для других.
Ответ 4
Вы можете использовать System.Windows.Media.Imaging в AssemblyCore Assembly, чтобы посмотреть здесь для получения дополнительной информации