当前位置导航:炫浪网>>网络学院>>编程开发>>Visual C#教程

编程实例 使用C#的BitmapData

       最近要转开发平台,正研究C#。C#好是好,不过处理图片时一个像素一个像素的操作像素不是一般的慢。其实Delphi也一样,但好在Delphi的Bitmap类提供了ScanLines,可以一行一行的读图,效率比较高。C#应该也有类似的东东。经过一番搜索,终于发现了BitmapData类。 

       先看个例子,这是对一张位图的每个像素按FF取补,然后输出到一个新图(代码有点啰嗦,不过应该可以说明问题了)。

int h = m_Bmp.Height;
int w = m_Bmp.Width;

Bitmap bmpOut = new Bitmap(w, h, PixelFormat.Format24bppRgb);

BitmapData dataIn = m_Bmp.LockBits(new Rectangle(0,0,w,h),ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb);
BitmapData dataOut = bmpOut.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

unsafe
{
byte* pIn = (byte*)(dataIn.Scan0.ToPointer());
byte * pOut = (byte*)(dataOut.Scan0.ToPointer());

for (int y = 0; y < dataIn.Height; y++)
{
for (int x = 0; x < dataIn.Width; x++)
{

pOut[0] = (byte)(255 - pIn[0]);
pOut[1] = (byte)(255 - pIn[1]);
pOut[2] = (byte)(255 - pIn[2]);

pIn += 3;
pOut += 3;
}

pIn += dataIn.Stride - dataIn.Width * 3;
pOut += dataOut.Stride - dataOut.Width * 3;
}
}

bmpOut.UnlockBits(dataOut);
m_Bmp.UnlockBits(dataIn);


貌似比Delphi复杂得多,难道我真的天生对指针过敏?还是Delphi的比较好理解,就是扫描每一行,然后对当前像素点的三个分量做处理,非常方便。而且C#代码中的Stride是个什么东东?

查找了不少资料,现在我是这么理解的:

假设有一张图片宽度为6,因为是Format24bppRgb格式(每像素3字节。在以下的讨论中,除非特别说明,否则Bitmap都被认为是24位RGB)的,显然,每一行需要6*3=18个字节存储。对于Bitmap就是如此。但对于BitmapData,虽然BitmapData.Width还是等于Bitmap.Width,但大概是出于显示性能的考虑,每行的实际的字节数将变成大于等于它的那个离它最近的4的整倍数,此时的实际字节数就是Stride。就此例而言,18不是4的整倍数,而比18大的离18最近的4的倍数是20,所以这个BitmapData.Stride = 20。显然,当宽度本身就是4的倍数时,BitmapData.Stride = Bitmap.Width * 3。

画个图可能更好理解。R、G、B 分别代表3个原色分量字节,BGR就表示一个像素。为了看起来方便我在每个像素之间插了个空格,实际上是没有的。X表示补足4的倍数而自动插入的字节。为了符合人类的阅读习惯我分行了,其实在计算机内存中应该看成连续的一大段。

Scan0
 
 ---------Stride----------------- 
 ---------Width-------------    注:Width是图片(BGR作为一个单位)宽度
BGR BGR BGR BGR BGR BGR XX
BGR BGR BGR BGR BGR BGR XX
.
.
.

现在应该很好理解了。首先用 BitmapData.Scan0找到第0个像素的第0个分量的地址。

共2页 首页 上一页 1 2 下一页 尾页 跳转到
相关内容
赞助商链接