Converting a bitmap to monochrome(将位图转换为单色)
问题描述
我正在尝试将图像保存为单色(黑白,1 位深度),但我不知道该怎么做.
I am trying to save an image as monochrome (black&white, 1 bit-depth) but I'm coming up lost how to do it.
我从 png 开始并转换为位图进行打印(它是热敏打印机,无论如何只支持黑色 - 如果我尝试将它们作为彩色/灰度发送,它对于大图像的速度会很慢).
I am starting with a png and converting to a bitmap for printing (it's a thermal printer and only supports black anyway - plus its slow as hell for large images if I try to send them as color/grayscale).
到目前为止,我的代码将其转换为位图非常简单,但它保留了原始颜色深度.
My code so far is dead simple to convert it to a bitmap, but it is retaining the original colour depth.
Image image = Image.FromFile("C:\test.png");
byte[] bitmapFileData = null;
int bitsPerPixel = 1;
int bitmapDataLength;
using (MemoryStream str = new MemoryStream())
{
image.Save(str, ImageFormat.Bmp);
bitmapFileData = str.ToArray();
}
推荐答案
这是我放在一起的一些代码,它采用全彩色(24 位/像素)图像,并将其转换为 1 位/像素输出位图,应用标准 RGB 到灰度转换,然后使用 Floyd-Steinberg 将灰度转换为 1 位/像素输出.
Here's some code I put together that takes a full colour (24 bits/pixel) image, and converts it to a 1 bit/pixel output bitmap, applying a standard RGB to greyscale conversion, and then using Floyd-Steinberg to convert greyscale to the 1 bit/pixel output.
请注意,这绝不应该被视为理想"的实现,但它确实有效.如果您愿意,可以应用许多改进.例如,它将整个输入图像复制到 data
数组中,而我们实际上只需要在内存中保留两行(当前"和下一个"行)来累积错误数据.尽管如此,性能似乎还可以接受.
Note that this should by no means be considered an "ideal" implementation, but it does work. There are a number of improvements that could be applied if you wanted. For example, it copies the entire input image into the data
array, whereas we really only need to keep two lines in memory (the "current" and "next" lines) for accumulating the error data. Despite this, performance seems acceptable.
public static Bitmap ConvertTo1Bit(Bitmap input)
{
var masks = new byte[] { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
var output = new Bitmap(input.Width, input.Height, PixelFormat.Format1bppIndexed);
var data = new sbyte[input.Width, input.Height];
var inputData = input.LockBits(new Rectangle(0, 0, input.Width, input.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
try
{
var scanLine = inputData.Scan0;
var line = new byte[inputData.Stride];
for (var y = 0; y < inputData.Height; y++, scanLine += inputData.Stride)
{
Marshal.Copy(scanLine, line, 0, line.Length);
for (var x = 0; x < input.Width; x++)
{
data[x, y] = (sbyte)(64 * (GetGreyLevel(line[x * 3 + 2], line[x * 3 + 1], line[x * 3 + 0]) - 0.5));
}
}
}
finally
{
input.UnlockBits(inputData);
}
var outputData = output.LockBits(new Rectangle(0, 0, output.Width, output.Height), ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
try
{
var scanLine = outputData.Scan0;
for (var y = 0; y < outputData.Height; y++, scanLine += outputData.Stride)
{
var line = new byte[outputData.Stride];
for (var x = 0; x < input.Width; x++)
{
var j = data[x, y] > 0;
if (j) line[x / 8] |= masks[x % 8];
var error = (sbyte)(data[x, y] - (j ? 32 : -32));
if (x < input.Width - 1) data[x + 1, y] += (sbyte)(7 * error / 16);
if (y < input.Height - 1)
{
if (x > 0) data[x - 1, y + 1] += (sbyte)(3 * error / 16);
data[x, y + 1] += (sbyte)(5 * error / 16);
if (x < input.Width - 1) data[x + 1, y + 1] += (sbyte)(1 * error / 16);
}
}
Marshal.Copy(line, 0, scanLine, outputData.Stride);
}
}
finally
{
output.UnlockBits(outputData);
}
return output;
}
public static double GetGreyLevel(byte r, byte g, byte b)
{
return (r * 0.299 + g * 0.587 + b * 0.114) / 255;
}
这篇关于将位图转换为单色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:将位图转换为单色
基础教程推荐
- C# - 将浮点数转换为整数...并根据余数更改整数 2022-01-01
- 我什么时候应该使用 GC.SuppressFinalize()? 2022-01-01
- 如何使用OpenXML SDK将Excel转换为CSV? 2022-01-01
- Page.OnAppearing 中的 Xamarin.Forms Page.DisplayAlert 2022-01-01
- 当键值未知时反序列化 JSON 2022-01-01
- 从 VB6 迁移到 .NET/.NET Core 的最佳策略或工具 2022-01-01
- 覆盖 Json.Net 中的默认原始类型处理 2022-01-01
- 创建属性设置器委托 2022-01-01
- 使用 SED 在 XML 标签之间提取值 2022-01-01
- C# - 如何列出发布到 ASPX 页面的变量名称和值 2022-01-01