如果将普通图片转成单色位图bmp,例如画图工具转换成单色位图。

天才李白 2016-06-01 11:07:06
请教大神们怎么用C#存储单色位图,和画板生成的单色为图一样。用于打印机打印单色位图(热敏打印机只支持单色位图)求完整的代码。
...全文
2506 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
xuzuning 2016-06-03
  • 打赏
  • 举报
回复
另外,对微软的色彩转黑白的抖动算法不甚了解 转出的图片和 画图 转的不太一样
xuzuning 2016-06-03
  • 打赏
  • 举报
回复
代码是套改8位灰度图的,注释不准确,请原谅
xuzuning 2016-06-03
  • 打赏
  • 举报
回复
你要的是这个效果吧?把左边的 24位真彩,转成右边的单色位图

        private static Bitmap BuiltBlackWhiteBitmap(byte[] rawValues, int width, int height)
{
// 新建一个8位灰度位图,并锁定内存区域操作
Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

// 计算图像参数
int offset = bmpData.Stride - bmpData.Width/8; // 计算每行未用空间字节数
IntPtr ptr = bmpData.Scan0; // 获取首地址
int scanBytes = bmpData.Stride * bmpData.Height; // 图像字节数 = 扫描字节数 * 高度
byte[] grayValues = new byte[scanBytes]; // 为图像数据分配内存

// 为图像数据赋值
int posSrc = 0, posScan = 0; // rawValues和grayValues的索引
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width/8; j++)
{
byte b = 0;
for (int k = 0; k < 8; k++) b = (byte)((b << 1) | (byte)(rawValues[posSrc++] < 96 ? 0 : 1));
grayValues[posScan++] = b;
}
// 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel
posScan += offset;
}

// 内存解锁
Marshal.Copy(grayValues, 0, ptr, scanBytes);
bitmap.UnlockBits(bmpData); // 解锁内存区域
//return bitmap;

// 修改生成位图的索引表
ColorPalette palette;
// 获取一个Format8bppIndexed格式图像的Palette对象
using (Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format1bppIndexed))
{
palette = bmp.Palette;
}
for (int i = 0; i < 2; i++)
{
palette.Entries[i] = Color.FromArgb(i*255, i*255, i*255);
}
// 修改生成位图的索引表
bitmap.Palette = palette;

return bitmap;
}
参数 rawValues 就是 #4 得到的灰度数据 byColorInfo
crystal_lz 2016-06-03
  • 打赏
  • 举报
回复
引用 4 楼 u013416462 的回复:
[quote=引用 3 楼 crystal_lz 的回复:] 单色图? 二值化?。

public Image GetBinaryImage(Image imgSrc, byte byValue) {
    Bitmap b = new Bitmap(imgSrc);
    Bitmap bmp = b.Clone(new Rectangle(0, 0, imgSrc.Width, imgSrc.Height), PixelFormat.Format24bppRgb);
    b.Dispose();
    BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
    byte[] byColorInfo = new byte[bmp.Height * bmpData.Stride];
    Marshal.Copy(bmpData.Scan0, byColorInfo, 0, byColorInfo.Length);
    byte byR, byG, byB;
    for (int x = 0, xLen = bmp.Width; x < xLen; x++) {
        for (int y = 0, yLen = bmp.Height; y < yLen; y++) {
            byB = byColorInfo[y * bmpData.Stride + x * 3];
            byG = byColorInfo[y * bmpData.Stride + x * 3 + 1];
            byR = byColorInfo[y * bmpData.Stride + x * 3 + 2];
            byte byV = GetAvg(byR, byG, byB);
            if (byV >= byValue) {
                byV = 255;
            } else {
                byV = 0;
            }
            byColorInfo[y * bmpData.Stride + x * 3] =
                byColorInfo[y * bmpData.Stride + x * 3 + 1] =
                byColorInfo[y * bmpData.Stride + x * 3 + 2] = byV;
        }
    }
    Marshal.Copy(byColorInfo, 0, bmpData.Scan0, byColorInfo.Length);
    bmp.UnlockBits(bmpData);
    return bmp;
}
单色位图啊!你的代码不完整。 [/quote] 不就是差了一个 GetAvg 么 想也想得到 这个函数是干嘛的 以及是怎么写的
天才李白 2016-06-03
  • 打赏
  • 举报
回复
希望有人帮忙解决下!
天才李白 2016-06-03
  • 打赏
  • 举报
回复
引用 5 楼 xuzuning 的回复:
那个是不行的,已然是24位位图,只是将色彩变成灰色而已 你要的是 Format1bppIndexed 格式的 bmp 待会如果我的代码能测试通过的话,就给你
麻烦你了!我的邮箱是357901986@qq.com
xuzuning 2016-06-03
  • 打赏
  • 举报
回复
那个是不行的,已然是24位位图,只是将色彩变成灰色而已 你要的是 Format1bppIndexed 格式的 bmp 待会如果我的代码能测试通过的话,就给你
天才李白 2016-06-03
  • 打赏
  • 举报
回复
引用 3 楼 crystal_lz 的回复:
单色图? 二值化?。

public Image GetBinaryImage(Image imgSrc, byte byValue) {
    Bitmap b = new Bitmap(imgSrc);
    Bitmap bmp = b.Clone(new Rectangle(0, 0, imgSrc.Width, imgSrc.Height), PixelFormat.Format24bppRgb);
    b.Dispose();
    BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
    byte[] byColorInfo = new byte[bmp.Height * bmpData.Stride];
    Marshal.Copy(bmpData.Scan0, byColorInfo, 0, byColorInfo.Length);
    byte byR, byG, byB;
    for (int x = 0, xLen = bmp.Width; x < xLen; x++) {
        for (int y = 0, yLen = bmp.Height; y < yLen; y++) {
            byB = byColorInfo[y * bmpData.Stride + x * 3];
            byG = byColorInfo[y * bmpData.Stride + x * 3 + 1];
            byR = byColorInfo[y * bmpData.Stride + x * 3 + 2];
            byte byV = GetAvg(byR, byG, byB);
            if (byV >= byValue) {
                byV = 255;
            } else {
                byV = 0;
            }
            byColorInfo[y * bmpData.Stride + x * 3] =
                byColorInfo[y * bmpData.Stride + x * 3 + 1] =
                byColorInfo[y * bmpData.Stride + x * 3 + 2] = byV;
        }
    }
    Marshal.Copy(byColorInfo, 0, bmpData.Scan0, byColorInfo.Length);
    bmp.UnlockBits(bmpData);
    return bmp;
}
单色位图啊!你的代码不完整。
  • 打赏
  • 举报
回复
单色就是 Encoder.ColorDepth == 1L,而灰度的图片那就是 Encoder.ColorDepth==8L。
  • 打赏
  • 举报
回复
引用 14 楼 u013416462 的回复:
但是和 图片用画图工具打开保存的单色位图 不一样!
你看到的不是“单色”,是“灰度”吧?
xuzuning 2016-06-03
  • 打赏
  • 举报
回复
我说的很清楚了:参数 rawValues 就是 #4 得到的灰度数据 byColorInfo 也说了产生的位图与 画图 的不一样 你可自行调整 21 行处的代码
  • 打赏
  • 举报
回复
.net 中有现成的转换方法,只要执行 Image.Save 即可。 https://msdn.microsoft.co m/zh-cn/library/system.drawing.imaging.encoder.colordepth(v=vs.90).aspx 把 24L 改为 1L,或者别的值。
天才李白 2016-06-03
  • 打赏
  • 举报
回复
引用 13 楼 crystal_lz 的回复:
最简单的两句代码就能搞定 要想要二值化自定义阈值 就用上面的代码
但是和 图片用画图工具打开保存的单色位图 不一样!
crystal_lz 2016-06-03
  • 打赏
  • 举报
回复

最简单的两句代码就能搞定
要想要二值化自定义阈值 就用上面的代码
天才李白 2016-06-03
  • 打赏
  • 举报
回复
引用 9 楼 xuzuning 的回复:
你要的是这个效果吧?把左边的 24位真彩,转成右边的单色位图
        private static Bitmap BuiltBlackWhiteBitmap(byte[] rawValues, int width, int height)
        {
            // 新建一个8位灰度位图,并锁定内存区域操作  
            Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
            BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, width, height),
                 ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);

            // 计算图像参数  
            int offset = bmpData.Stride - bmpData.Width/8;        // 计算每行未用空间字节数  
            IntPtr ptr = bmpData.Scan0;                         // 获取首地址  
            int scanBytes = bmpData.Stride * bmpData.Height;    // 图像字节数 = 扫描字节数 * 高度  
            byte[] grayValues = new byte[scanBytes];            // 为图像数据分配内存  

            // 为图像数据赋值  
            int posSrc = 0, posScan = 0;                        // rawValues和grayValues的索引  
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width/8; j++)
                {
                    byte b = 0;
                    for (int k = 0; k < 8; k++) b = (byte)((b << 1) | (byte)(rawValues[posSrc++] < 96 ? 0 : 1));
                    grayValues[posScan++] = b;
                }
                // 跳过图像数据每行未用空间的字节,length = stride - width * bytePerPixel  
                posScan += offset;
            }

            // 内存解锁  
            Marshal.Copy(grayValues, 0, ptr, scanBytes);
            bitmap.UnlockBits(bmpData);  // 解锁内存区域  
            //return bitmap;

            // 修改生成位图的索引表  
            ColorPalette palette;
            // 获取一个Format8bppIndexed格式图像的Palette对象  
            using (Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format1bppIndexed))
            {
                palette = bmp.Palette;
            }
            for (int i = 0; i < 2; i++)
            {
                palette.Entries[i] = Color.FromArgb(i*255, i*255, i*255);
            }
            // 修改生成位图的索引表  
            bitmap.Palette = palette;

            return bitmap;
        }
参数 rawValues 就是 #4 得到的灰度数据 byColorInfo
不明白rawValues是使用灰度数据还是原始数据。
crystal_lz 2016-06-02
  • 打赏
  • 举报
回复
单色图? 二值化?。

public Image GetBinaryImage(Image imgSrc, byte byValue) {
    Bitmap b = new Bitmap(imgSrc);
    Bitmap bmp = b.Clone(new Rectangle(0, 0, imgSrc.Width, imgSrc.Height), PixelFormat.Format24bppRgb);
    b.Dispose();
    BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
    byte[] byColorInfo = new byte[bmp.Height * bmpData.Stride];
    Marshal.Copy(bmpData.Scan0, byColorInfo, 0, byColorInfo.Length);
    byte byR, byG, byB;
    for (int x = 0, xLen = bmp.Width; x < xLen; x++) {
        for (int y = 0, yLen = bmp.Height; y < yLen; y++) {
            byB = byColorInfo[y * bmpData.Stride + x * 3];
            byG = byColorInfo[y * bmpData.Stride + x * 3 + 1];
            byR = byColorInfo[y * bmpData.Stride + x * 3 + 2];
            byte byV = GetAvg(byR, byG, byB);
            if (byV >= byValue) {
                byV = 255;
            } else {
                byV = 0;
            }
            byColorInfo[y * bmpData.Stride + x * 3] =
                byColorInfo[y * bmpData.Stride + x * 3 + 1] =
                byColorInfo[y * bmpData.Stride + x * 3 + 2] = byV;
        }
    }
    Marshal.Copy(byColorInfo, 0, bmpData.Scan0, byColorInfo.Length);
    bmp.UnlockBits(bmpData);
    return bmp;
}
天才李白 2016-06-02
  • 打赏
  • 举报
回复
引用 1 楼 starfd 的回复:
http://www.doc88.com/p-9751909852742.html
没有尝试过?这个代码要下载才可用使用。

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧