用GDI+生成的BMP图片颜色位数一般都是24位,我要怎样生成1位的BMP图片呢? 思路2及问题:先生成普通24位色的BMP图片,然后将它转换成1位色的BMP,我在网上找了这么一段代码来转换,但是转换的效率很低。 Image img = Image.FromFile("r.bmp"); ImageAttributes ta = new ImageAttributes(); /* 下面用Graphics类改变像点颜色,是靠ImageAttributes来把 * 彩色变成灰度,或者颠倒黑白,发现用矩阵处理还是很方便的 */ //如实际发现几个简单又好用的矩阵: float[][] mm = new float[][]{ //彩色变灰度的矩阵 new float[]{0.4f, 0.4f, 0.4f, 0, 0}, new float[]{0.3f, 0.3f, 0.3f, 0, 0}, new float[]{0.3f, 0.3f, 0.3f, 0, 0}, new float[]{0, 0, 0, 1, 0}, new float[]{0, 0, 0, 0, 1} }; /* float[][] mm1=new float[][]{ //彩色反相的矩阵 new float[]{0, 0.3f, 0.5f, 0, 0}, new float[]{0.5f, 0.3f, 0.5f, 0, 0}, new float[]{0.5f, 0.4f, 0, 0, 0}, new float[]{0, 0, 0, 1, 0}, new float[]{0, 0, 0, 0, 1} }; float[][] mm2=new float[][]{ //彩色变反相灰度的矩阵 new float[]{-0.4f, -0.4f, -0.4f, 0, 0}, new float[]{-0.3f, -0.3f, -0.3f, 0, 0}, new float[]{-0.3f, -0.3f, -0.3f, 0, 0}, new float[]{1, 1, 1, 1, 0}, new float[]{0, 0, 0, 0, 1} }; */ ColorMatrix cmt = new ColorMatrix(mm); ta.SetColorMatrix(cmt); /* //如果确知图像里仅有纯黑白二色,也可用ColorMap来反相,它可逐色改变 ColorMap map1=new ColorMap(); map1.OldColor=Color.Black; map1.NewColor=Color.White; ColorMap map2=new ColorMap(); map2.OldColor=Color.White; map2.NewColor=Color.Black; ta.SetRemapTable(new ColorMap[]{map1,map2},ColorAdjustType.Bitmap); */ /* 有的图像比如索引格式的位图或GIF是无法创建Graphics的, * 需要新建一非索引色位图取得Graphics对象以便做画或改变像点颜色。 */ Bitmap bmp = new Bitmap(img.Width, img.Height); Graphics g = Graphics.FromImage(bmp); g.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, ta); //g.DrawString("Foxit PDF Reader",new Font("宋体",8),new SolidBrush(Color.White),0,0); g.Dispose(); /* 在如下构造图像数据之前,也可以先创建一单色位图并锁定数据, * 利用它现成的Stride简单计算出实际每行有效数据之后的填充字节数,而且可 * 在下面循环里直接写点Marshal.WriteByte(dt.Scan0,k,val);而不用数组拷贝 */ //以下,把反相或者涂画后的像点数据每一行的每8点简单合并成1byte存储 int midrgb = Color.FromArgb(128, 128, 128).ToArgb(); int stride;//简单公式((width/8)+3)&(~3) stride = (bmp.Width % 8) == 0 ? (bmp.Width / 8) : (bmp.Width / 8) + 1; stride = (stride % 4) == 0 ? stride : ((stride / 4) + 1) * 4; int k = bmp.Height * stride; byte[] buf = new byte[k]; for (int j = 0; j < bmp.Height; j++) { k = j * stride;//因图像宽度不同、有的可能有填充字节需要跳越 int x = 0, ab = 0; for (int i = 0; i < bmp.Width; i++) { //从灰度变单色(下法如果直接从彩色变单色效果不太好,不过反相也可以在这里控制) if ((bmp.GetPixel(i, j)).ToArgb() > midrgb) ab = ab * 2 + 1; else ab = ab * 2; x++; if (x == 8) { buf[k++] = (byte)ab; ab = 0; x = 0; } } if (x > 0) { //循环实现:剩余有效数据不满1字节的情况下须把它们移往字节的高位部分 for (int t = x; t < 8; t++) ab = ab * 2; buf[k++] = (byte)ab; } } Bitmap bb = new Bitmap(img.Width, img.Height, PixelFormat.Format1bppIndexed); BitmapData dt = bb.LockBits(new Rectangle(0, 0, bb.Width, bb.Height), ImageLockMode.ReadWrite, bb.PixelFormat); Marshal.Copy(buf, 0, dt.Scan0, buf.Length); bb.UnlockBits(dt); bb.Save("w.bmp", ImageFormat.Bmp); bb.Dispose(); bmp.Dispose(); img.Dispose(); |
|
你要对1位图像做什么处理啊,1位图像是不能绘制直线圆之类的。
那个转换效率低是因为GetPixel慢,要用lockbits的,苏都都是能达到毫秒级别的。 并且24位转换为1位如果不抖动的话, 效果很差。 |
|
楼上说的对,参考一下这个, http://blog.csdn.net/hemmingway/article/details/8909662
|
|
/// <summary>
/// 转换灰度的算法 /// </summary> /// <param name=”sourcebm”></param> private void SetLuma(Bitmap sourcebm) { int critical_value = 80; for (int x = 0; x < sourcebm.Width; x++) { for (int y = 0; y < sourcebm.Height; y++) { Color c = sourcebm.GetPixel(x, y); int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);//转换灰度的算法 Color c2 = Color.FromArgb(luma, luma, luma); if (c2.R >= critical_value) { sourcebm.SetPixel(x, y, Color.FromArgb(255, 255, 255)); } else { sourcebm.SetPixel(x, y, Color.FromArgb(0, 0, 0)); } } } |
|
难道你们都不懂1位色是什么意思吗,非要贴一些灰度有关的的代码误导吗。其实楼上的也不叫灰度图像,还是彩色图像吗,只是彩色的各分量相同而已。
|
|
请问该如何解决呢? |
|
对于你以上的文字,我不清楚你要干什么。
你现在手上有什么,目的是什么。 |
|
呵呵,他想要你给他写一个完整的快速的生成1位单色图的程序啊 |
|
我现在用程序生成了一个里面都是黑点的图片,然后要发给印刷厂的喷码设备去喷码,但是他们的设置只支持1位色的bmp图片,所以我用C#生成的普通bmp图片需要转到1位色给他们,现在遇到的问题就是转换的速度太慢了。 |
|
我现在慢就慢在这两个循环中,但是好像必须要有这两个循环来转换颜色
for (int j = 0; j < bmp.Height; j++) { k = j * stride;//因图像宽度不同、有的可能有填充字节需要跳越 int x = 0, ab = 0; for (int i = 0; i < bmp.Width; i++) { //从灰度变单色(下法如果直接从彩色变单色效果不太好,不过反相也可以在这里控制) if ((bmp.GetPixel(i, j)).ToArgb() > midrgb) ab = ab * 2 + 1; else ab = ab * 2; x++; if (x == 8) { buf[k++] = (byte)ab; ab = 0; x = 0; } } if (x > 0) { //循环实现:剩余有效数据不满1字节的情况下须把它们移往字节的高位部分 for (int t = x; t < 8; t++) ab = ab * 2; buf[k++] = (byte)ab; } } |
|
大家看下图,我要将32位颜色转成1位颜色,也就是只有黑白两色
|
|
98分 |
不多说。在项目的属性里要勾选 容许不安全代码。
public Bitmap ConvertTo24bppTo1bpp(Bitmap SrcImg) { unsafe { byte* SrcPointer, DestPointer; int Width, Height, SrcStride, DestStride; int X, Y, Index, Sum; ; Bitmap DestImg = new Bitmap(SrcImg.Width, SrcImg.Height, PixelFormat.Format1bppIndexed); BitmapData SrcData = new BitmapData(); SrcImg.LockBits(new Rectangle(0, 0, SrcImg.Width, SrcImg.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb, SrcData); BitmapData DestData = new BitmapData(); DestImg.LockBits(new Rectangle(0, 0, SrcImg.Width, SrcImg.Height), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed, DestData); Width = SrcImg.Width; Height = SrcImg.Height; SrcStride = SrcData.Stride; DestStride = DestData.Stride; for (Y = 0; Y < Height; Y++) { SrcPointer = (byte *)SrcData.Scan0 + Y * SrcStride; DestPointer = (byte*)DestData.Scan0 + Y * DestStride; Index = 7; Sum = 0; for (X = 0; X < Width; X++) { if (*SrcPointer + (*(SrcPointer + 1) << 1) + *(SrcPointer + 2)>= 512) Sum += (1 << Index); if (Index == 0) { *DestPointer = (byte)Sum; Sum = 0; Index = 7; DestPointer++; } else Index--; SrcPointer+=3; } if (Index != 7) *DestPointer = (byte)Sum; } SrcImg.UnlockBits(SrcData); DestImg.UnlockBits(DestData); return DestImg; } } |
这样改就OK了:
System.Drawing.Imaging.BitmapData srcData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = srcData.Scan0; int strideBmp=srcData.Stride; int bytes = bmp.Height * strideBmp; byte[] srcValues = new byte[bytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, srcValues, 0, bytes); bmp.UnlockBits(srcData); Color temp; int midrgb = Color.FromArgb(128, 128, 128).ToArgb(); |
|
非常感谢,太牛了,这段代码速度很快
|
|
楼主,你说的速度很快的代码,是哪个啊?
|