转换位图以单色 [英] Converting a bitmap to monochrome

查看:410
本文介绍了转换位图以单色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想保存图像为单色(黑白与白,1位深),但我来了丢了怎么办呢

我开始用一个PNG,并转换为用于打印的位图(这是一个热敏打印机,仅支持黑色无论如何 - 加上其作为地狱的大图像慢,如果我试图把它们发送的彩色/灰度)。

我的code,到目前为止已经死了简单的将其转换为位图,但它保留原来的颜色深度。

 形象画像= Image.FromFile(C:\\\\ test.png);字节[] bitmapFileData = NULL;
INT bitsPerPixel = 1;
INT bitmapDataLength;使用(MemoryStream的海峡=新的MemoryStream())
{
    image.Save(STR,ImageFormat.Bmp);
    bitmapFileData = str.ToArray();
}


解决方案

下面是一些code我放在一起,需要一个全彩色(24位/像素)图像,并将其转换为1位/像素输出的位图,施加标准RGB为灰度转换,然后使用弗洛伊德-斯坦伯格到灰度转换为1比特/象素输出

请注意,这决不被认为是一个理想的实施中,但它的工作。有许多的,如果你想能够应用于改进。例如,它会将整个输入图像到数据阵列,而我们只需要保持两行存储器(当前和下一个线数)累积误差数据。尽管这样,表现似乎可以接受的。

 公共静态位图ConvertTo1Bit(位图输入)
{
    VAR口罩=新的字节[] {0x80的,0X40,为0x20,为0x10,0x08的,0x04的0X02,0×01};
    无功输出=新位图(input.Width,input.Height,PixelFormat.Format1bppIndexed);
    VAR数据=新为sbyte [input.Width,input.Height]
    VAR inputData = input.LockBits(新的Rectangle(0,0,input.Width,input.Height),ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb);
    尝试
    {
        VAR扫描线= inputData.Scan0;
        VAR行=新的字节[inputData.Stride]
        对于(VAR Y = 0; Y< inputData.Height; Y ++,扫描+ = inputData.Stride)
        {
            Marshal.Copy(扫描线,线,0,line.Length);
            为(变量X = 0; X&下; input.Width; X ++)
            {
                数据[X,Y] =(为sbyte)(64 *(GetGreyLevel(行[X * 3 + 2],线[X * 3 + 1],线[X * 3 + 0]) - 0.5));
            }
        }
    }
    最后
    {
        input.UnlockBits(inputData);
    }
    VAR outputData = output.LockBits(新的Rectangle(0,0,output.Width,output.Height),ImageLockMode.WriteOnly,PixelFormat.Format1bppIndexed);
    尝试
    {
        VAR扫描线= outputData.Scan0;
        对于(VAR Y = 0; Y< outputData.Height; Y ++,扫描+ = outputData.Stride)
        {
            VAR行=新的字节[outputData.Stride]
            为(变量X = 0; X&下; input.Width; X ++)
            {
                变种J =数据[X,Y]> 0;
                如果(J)线[X / 8] | =口罩[X%8]。
                变种误差=(为sbyte)(数据[X,Y] - (J 32:-32));
                如果(X LT; input.Width - 1)数据[X + 1,Y] + =(为sbyte)(7 *错误/ 16);
                如果(Y< input.Height - 1)
                {
                    如果(X 0)的数据[X - 1,Y + 1] + =(为sbyte)(3 *错误/ 16);
                    数据[X,Y + 1] + =(为sbyte)(5 *误差/ 16);
                    如果(X LT; input.Width - 1)数据[X + 1,Y + 1] + =(为sbyte)(1 *错误/ 16);
                }
            }
            Marshal.Copy(线,0,扫描,outputData.Stride);
        }
    }
    最后
    {
        output.UnlockBits(outputData);
    }
    返回输出;
}公共静态双GetGreyLevel(字节R,字节克,BYTE B)
{
    收益率(R * 0.299 + G * 0.587 + B * 0.114)/ 255;
}

I am trying to save an image as monochrome (black&white, 1 bit-depth) but I'm coming up lost how to do it.

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

解决方案

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.

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

这篇关于转换位图以单色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆