博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LockBits in GDI+【转】http://timothyqiu.com/archives/lockbits-in-gdiplus/
阅读量:5336 次
发布时间:2019-06-15

本文共 2352 字,大约阅读时间需要 7 分钟。

发布时间:March 31, 2011 分类:

什么东西一旦追求起效率来最终还是要归到比较底层的操作,比如 GDI 中直接操作位图数据就要用 GetDIBits / SetDIBits(或者已经废弃的 GetBitmapBits / SetBitmapBits)。因为最近要处理的都是 GDI 处理不了的 PNG 格式图片,所以还是用上了 GDI+。GDI+ 中直接操作 Bitmap 的数据就要用 LockBits / UnlockBits 了。

第一眼看见 Bitmap::LockBits 的声明我就比较晕:

Status LockBits(const Rect *rect,                UINT flags,                PixelFormat format,                BitmapData *lockedBitmapData);

不过说实话,整个 GDI+ 库的风格相对于 M$ 的其它库来说已经是很清新脱俗了 :)

rect
要锁定的矩形区域,一般都是锁定整个图像大小。(吐槽:为神马不能传 
NULL 进去表示全图啊~)
flags
锁定区域要进行读操作还是写操作,以及是否自己分配缓冲区。(看着比较不顺眼的 
UINT 类型可取的值其实是 
enum
format
锁定区域所需的像素格式,如果和图片本身的格式不符,GDI+ 会自动进行转换。
lockedBitmapData
输出锁定区域信息,成员变量 
Scan0 会指向被锁定的像素区域(如果 
flags 里指定自己分配缓冲区的话,系统只是往 
Scan0 所指缓冲区写数据)。

那么锁定全图进行读操作就是:

int w = bmp->GetWidth();int h = bmp->GetHeight();BitmapData bmpData;bmp->LockBits(Rect(0, 0, w, h), ImageLockModeRead, PixelFormat32bppARGB, &bmpData);

锁定完图像区域,就可以对得到的 BitmapData 进行操作了。BitmapData 包含了被锁定区域的长、宽、格式、指针信息。取坐标 (x, y) 的像素颜色可以用:

unsigned int *pData = reinterpret_cast
(bmpData.Scan0);int stride = bmpData.Stride;unsigned int color = pData[y * stride / 4 + x]; // color= 0xAARRGGBB

有一个比较特别的 Stride 成员,它表示「一行」图像对应的缓冲区所实际占用的字节数(因为位图文件有一条变态的规则:图片数据在存储时每一行字节数必须是 4 的倍数,如果真实图片数据宽度不是 4 的倍数则需要用垃圾数据补齐不足的字节数,于是就造成了 Stride ≠ Width 的现象,即所谓的字节对齐)。

对于图片数据操作完以后要记得对锁定区域进行解锁:

bmp->UnlockBits(&bmpData);

这样一来就功德圆满了。

嗯~这段笔记就是这样,这真是有意义的一天啊~

自己提供缓冲区

咳咳~距刚刚写这篇东西已经有大半年了,在仔细看 GDI+ 的文档时又发现了些有用的东东。

正如你所看到的,上边所说的「LockBits → 读写 bmpData.San0 → UnlockBits」的三部曲其实并不与 GDI 中的 GetDIBits / SetDIBits 完全对应。至少后者是直接从位图中读取数据到我们自己提供的颜色缓冲区、直接从自己的颜色缓冲区写到位图中去,而前者却需要在 Lock 后一行一行、甚至一个像素一个像素地手动交换。

好消息是 Bitmap::LockBits 的 flags 参数除了可以传入 ImageLockModeRead 和 ImageLockModeWrite 外还可以同时或上一个 ImageLockModeUserInputBuf。这个标志位表示让 LockBits 使用我们传入的 BitmapData 中的缓冲区信息来进行读写,而不是由它来分配、我们来读写。

举个栗子 :)

int w = bmp->GetWidth();int h = bmp->GetHeight();unsigned int *buffer = new unsigned int[w * h * 4]; // 缓冲区,以 32 位色 ARGB 模式读取BitmapData bmpData;bmpData.Width  = w;bmpData.Height = h;bmpData.Stride = w * 4; // 缓冲区每行大小,自行分配,每行就没有多余字节了bmpData.Scan0  = buffer;bmpData.PixelFormat = PixelFormat32bppARGB;bmpData.Reserved = NULL;bmp->LockBits(Rect(0, 0, w, h),              ImageLockModeRead | ImageLockModeUserInputBuf,              PixelFormat32bppARGB,              &bmpData);bmp->UnlockBits(&bmpData);

转载于:https://www.cnblogs.com/songtzu/archive/2013/01/25/2876805.html

你可能感兴趣的文章
注册表操作
查看>>
360浏览器兼容模式 不能$.post (不是a 连接 onclick的问题!!)
查看>>
Yii安装使用教程(转)
查看>>
Java四种引用包括强引用,软引用,弱引用,虚引用。
查看>>
spring注入Properties
查看>>
微信小程序开发之从相册获取图片 使用相机拍照 本地图片上传
查看>>
【BZOJ-2295】我爱你啊 暴力
查看>>
【BZOJ-1055】玩具取名 区间DP
查看>>
Bit Twiddling Hacks
查看>>
Windwos中的线程同步
查看>>
LeetCode : Reverse Vowels of a String
查看>>
时间戳与日期的相互转换
查看>>
jmeter(五)创建web测试计划
查看>>
python基本数据类型
查看>>
1305: [CQOI2009]dance跳舞 - BZOJ
查看>>
关于TDD的思考
查看>>
Cocos2d-x学习之windows 7 android环境搭建
查看>>
将html代码中的大写标签转换成小写标签
查看>>
jmeter多线程组间的参数传递
查看>>
零散笔记
查看>>