C#中Bitmap类是否在内部按列存储像素?附MSDN代码示例
C# Bitmap类内部是按列存储像素吗?
嘿,这个问题问得很关键!答案是:C#的Bitmap类内部并非按列存储像素,而是采用行优先(Row-major)的存储方式——也就是先完整存储第一行的所有像素,再存储第二行,以此类推,逐行往下。
为什么这么说?
Bitmap类底层依赖GDI+的位图实现,而GDI+的位图结构天生就是行优先的。每一行的像素数据会连续存放在内存中,不过为了满足内存对齐要求,每行末尾可能会添加一些填充字节(这就是Stride属性的由来,它代表每行实际占用的字节数,可能比宽度×每个像素字节数要大)。
结合你给出的MSDN代码示例来看
你贴的这段代码:
private void SetPixel_Example(PaintEventArgs e) { // Create a Bitmap object from a file. Bitmap myBitmap = new Bitmap("Grapes.jpg"); // Draw myBitmap to the screen. e.Graphics.DrawImage(myBitmap, 0, 0, myBitmap.Width, myBitmap.Height); // Set each pixel in myBitmap to black. for (int Xcount = 0; Xcount < myBitmap.Width; Xcount++) { for (int Ycount = 0; Ycount < myBitmap.Height; Ycount++) { myBitmap.SetPixel(Xcount, Ycount, Color.Black); } } //... }
这里的循环是先遍历X(列方向)再遍历Y(行方向),其实这种方式的效率并不高——因为每次Y变化时,都要跳转到下一行的内存起始位置,而X在每行内来回跳转,缓存命中率低。如果改成先遍历Y(行)再遍历X(列),内存访问会更连续,速度会快很多,这也从侧面印证了Bitmap是行优先存储的。
高效操作像素的方式
如果要批量处理像素,推荐使用LockBits方法直接访问内存缓冲区,这时候能更直观看到行优先的结构:
Scan0属性指向第一行第一个像素的内存地址Stride是每行的总字节数(含填充)- 第Y行第X列的像素起始地址 =
Scan0 + Y * Stride + X * 每个像素的字节数
内容的提问来源于stack exchange,提问作者John Z. Li
相关产品推荐
相关产品推荐

