Оба они слишком сложны. LockBits
может конвертировать данные в 1bpp. Просто откройте исходный код как 1bpp, скопируйте его данные в новый образ 1bpp, и все готово.
Я также весьма озадачен комбинацией GetPixel
и LockBits
. Обычно использование LockBits
означает, что вы поняли, что GetPixel
- это ужасно медленная трата времени, которая выполняет LockBits
внутренне для каждый вызов .
public static Bitmap BitmapTo1Bpp(Bitmap source)
{
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
Bitmap dest = new Bitmap(rect.Width, rect.Height, PixelFormat.Format1bppIndexed);
dest.SetResolution(source.HorizontalResolution, source.VerticalResolution);
BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
BitmapData targetData = dest.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
Int32 actualDataWidth = (rect.Width + 7) / 8;
Int32 h = source.Height;
Int32 origStride = sourceData.Stride;
Int32 targetStride = targetData.Stride;
// buffer for one line of image data.
Byte[] imageData = new Byte[actualDataWidth];
Int64 sourcePos = sourceData.Scan0.ToInt64();
Int64 destPos = targetData.Scan0.ToInt64();
// Copy line by line, skipping by stride but copying actual data width
for (Int32 y = 0; y < h; y++)
{
Marshal.Copy(new IntPtr(sourcePos), imageData, 0, actualDataWidth);
Marshal.Copy(imageData, 0, new IntPtr(destPos), actualDataWidth);
sourcePos += origStride;
destPos += targetStride;
}
dest.UnlockBits(targetData);
source.UnlockBits(sourceData);
return dest;
}
Обратите внимание, что преобразования данных в индексированные форматы следует избегать в тех случаях, когда ваш результат не равен 1 bpp для чисто черного и белого цветов. Индексированные форматы имеют палитру, и это не приведет ни к какому уменьшению до оптимизированной палитры, приближающейся к цветам изображения; он просто изменит цвета на изображении до их наиболее близкого соответствия на стандартной палитре для этой битовой глубины. Для 1bpp это просто черно-белый, что идеально, но для 4bpp и 8bpp это даст довольно плохие результаты.
Также обратите внимание, что по некоторым причинам вы не можете конвертировать из более высокого в более низкий индексированный формат пикселей; это бросит исключение. Поскольку вы можете преобразовать растровое изображение в 32-разрядное с помощью конструктора new Bitmap(Bitmap)
, эту проблему легко избежать, вызвав такой код:
public static Bitmap ConvertTo1Bpp(Bitmap source)
{
PixelFormat sourcePf = source.PixelFormat;
if ((sourcePf & PixelFormat.Indexed) == 0 || Image.GetPixelFormatSize(sourcePf) == 1)
return BitmapTo1Bpp(source);
using (Bitmap bm32 = new Bitmap(source))
return BitmapTo1Bpp(bm32);
}