之前结合网上的一些代码及ATL::CImage的实现,自己写了一个将HBITMAP以PNG格式保存到文件到函数。见上一篇日记。

不过,后来换了个环境又发现了问题,昨天和今天上午把《Windows程序设计》中位图处理相关的部分又粗略瞄了一下,然后把之前的函数改了一下,现在在新环境下也可以了,当然,这个函数也并不十分严谨,但是考虑到位图格式的历史渊源和复杂性,测试起来目测会相当麻烦,还是不要深究的好。而且,现在基本上都是32位图像,老的格式中很多东西都已无用武之地,所以且将就用着。

首先,幸好需要处理的只是带Alpha通道的图像,而Alpha通道只有ARGB有,ARGB又不需要颜色表(每个像素值都是真实的颜色值,而非颜色表索引)。对于ARGB来说,位图数据可以随意拷贝,不需要先针对目标DC或目标DDB/DIB进行转换。

所以,鉴于只要解决Alpha通道失效的问题,所以处理办法可以简化一下,首先判断位图每像素的位数(ARGB为32位),如果不是32位,则必定不是ARGB,不存在Alpha通道,因此可以直接使用Gdiplus::Bitmap::FromHBITMAP再保存。这样,就可以把非32位的位图可能的种种情况(对齐、颜色掩码、颜色表、坐标系)通通丢给GDI+去处理。

如果是32位,即可认为是ARGB,由于不存在颜色表,所以也可以用采比较粗糙的办法处理:用ARGB格式来建立一个新的Bitmap对象,然后不考虑原位图是DIB还是DDB,直接将它的图像数据填充到新Bitmap对象。

上一篇日记里的函数其实也是这个思路,但是有个小问题:通过GetObject得到的BITMAP,其中的bmBits成员(即图像数据块的指针),只有在图像是DIB时才是有效的,如果图像是DDB,得到的指针将是NULL。之前没有在GetObject的说明中留意到这一点,又在ATL::CImage中找不到DDB的处理代码,所以就直接放弃了DDB。

新函数纠正了这个问题,对于DDB,通过GetDIBits可以拿到图像数据再填充到Bitmap。由于ARGB不存在颜色表,所以可以用更简单的GetBitmapBits来代替GetDIBits。

新函数中依然存一个不确定性问题:

在从ATL::CImage中提取出来DIB处理代码中,会处理坐标系。当取到的BITMAPINFOHEADER.biHeight为正数时,会把位数据块的指针移到最后一行,并把行宽置为负值(这样每次通过+行宽值的操作就能得到上一行的数据地址)。

而对DDB来说,我不知道是不是也存在坐标系的问题,而没有BITMAPINFOHEADER数据,而根据MSDN,BITMAP中的bmHeight是必须为正值的,它不能用来指示坐标系。所以,我没有考虑这个问题,用GetBitmapBits把位图数据取出来并直接填到Bitmap对象中去了。目前看到的结果是图像没有发生倒置,但是我不确定是否会存在其它情况。

代码在此:

bool ImageUtil::SavePng( HBITMAP hBmp, LPCTSTR lpszFilePath )
{
DIBSECTION dibsection = {0};
int nBytes = ::GetObject( hBmp, sizeof( DIBSECTION ), &dibsection ); Gdiplus::Bitmap* bitmap = 0; if(dibsection.dsBm.bmBitsPixel != 32)
{
bitmap = Gdiplus::Bitmap::FromHBITMAP(hBmp, NULL);
}
else
{
int width, height, pitch;
LPVOID bits; width = dibsection.dsBm.bmWidth;
height = abs( dibsection.dsBm.bmHeight );
pitch = (((width*dibsection.dsBm.bmBitsPixel)+31)/32)*4; //计算行宽,四字节对齐 ATL::CImage::ComputePitch // 32位位图不存在对齐问题,so其实没必要
bits = dibsection.dsBm.bmBits; if( dibsection.dsBmih.biHeight > 0 ) // 对于DDB,不会取到dsBmih数据,所以biHeight成员始终为0
{
bits = LPBYTE( bits )+((height-1)*pitch);
pitch = -pitch;
} bitmap = new Gdiplus::Bitmap(width, height, pitch, PixelFormat32bppARGB, static_cast< BYTE* >(bits )); if(0 == bits)
{
BitmapData bitmapData;
Rect rc(0, 0, width, height);
bitmap->LockBits(&rc, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData);
GetBitmapBits(hBmp, pitch * height, bitmapData.Scan0); // 上面的bits在biHeight>0时要倒置的,但是这里不知道要不要,也不好测试
bitmap->UnlockBits(&bitmapData);
}
} bool ret = false;
CLSID clsid = GetGdiplusEncoderClsid(NULL, &Gdiplus::ImageFormatPNG);
if(clsid != CLSID_NULL)
{
ret = (Gdiplus::Ok == bitmap->Save(lpszFilePath, &clsid, NULL));
}
delete bitmap;
return ret;
}

  

使用GDI+保存带Alpha通道的图像(续)的更多相关文章

  1. 使用GDI+保存带Alpha通道的图像

    带Alpha通道的图像(ARBG)在通过GDIPlus::Bitmap::FromHBITMAP等转为GDI+位图,再存储时,透明区域会变成纯黑(也有可能是纯白?).   网上找了两段保持透明的实现代 ...

  2. 带Alpha通道的色彩叠加问题

    css3的rgba色彩模式.png/gif图片的alpha通道.canvas的rgba色彩模式.css3的阴影.css3的opacity属性等等,这些应用在网页中,有意无意间,我们的页面多了许多半透明 ...

  3. Unity 播放 带 alpha 通道的视频(Video Player组件)

    孙广东  2017.6.18 http://blog.csdn.NET/u010019717 通常是  .webm类型文件!!!!!  你可以下载这个文件到本地: Http://tsubakit1.s ...

  4. 如何基于纯GDI实现alpha通道的矢量和文字绘制

    今天有人在QQ群里问GDI能不能支持带alpha通道的线条绘制? 大家的答案当然是否定的,很多人推荐用GDI+. 一个基本的图形引擎要包括几个方面的支持:位图绘制,文字绘制,矢量绘制(如矩形,线条). ...

  5. 什么是Alpha通道?

    图像处理(Alpha通道,RGB,...)祁连山(Adobe 系列教程)****的UI课程 一个也许很傻的问题,在图像处理中alpha到底是什么?  Alpha通道是计算机图形学中的术语,指的是特别的 ...

  6. Alpha通道

     Alpha通道是计算机图形学中的术语,指的是特别的通道,意思是“非彩色”通道,主要是用来保存选区和编辑选区.真正让图片变透明的不是Alpha 实际是Alpha所代表的数值和其他数值做了一次运算  为 ...

  7. ImagXpress中如何修改Alpha通道方法汇总

    ImagXpress支持处理Alpha通道信息来管理图像的透明度,Alpha通道支持PNG ,TARGA和TIFF文件,同时还支持BMP和ICO文件.如果说保存的图像样式不支持Alpha通道,就将会丢 ...

  8. PIE SDK Alpha通道数据渲染

    1.  功能简介 在计算机图形学中,一个RGB颜色模型的真彩图形,用由红.绿.蓝三个色彩信息通道合成的,每个通道用了8位色彩深度,共计24位,包含了所有彩色信息.为实现图形的透明效果,采取在图形文件的 ...

  9. 使用opencv为没有透明通道的图像加入透明通道

    在图像处理中,我们经常需要处理带透明通道的图片,比如为图片或视频添加水印,为图片或视频添加字幕.贴图等.然而,我们的素材图片未必总是带有透明通道.比如,素材的背景本该透明的地方,却是黑色和白色.有时, ...

随机推荐

  1. mysqldump 使用方法

    1.仅导出数据: mysqldump -t -uroot -proot pgenius RES_COM_PFT_FCST>RES_COM_PFT_FCST.sql 2.有条的导出数据: mysq ...

  2. iOS系统知识架构(转)

    转载的,哪些所谓的资深开发,谁敢说自己没有知识盲区?http://ios.skyfox.org/route.html

  3. 你必须了解的Session的本质

    http://netsecurity.51cto.com/art/201402/428721.htm Cookie和session由于实现手段不同,因此也各有优缺点和各自的应用场景: 1.   应用场 ...

  4. Gcov 详解 + 内核函数覆盖率测试方法详述及产生错误解决办法

    http://blog.csdn.net/wangyezi19930928/article/details/42638345 http://www.uml.org.cn/Test/201208311. ...

  5. Android程序员学WEB前端(3)-HTML(3)-表单嵌套-Sublime

    转载请注明出处:http://blog.csdn.net/iwanghang/article/details/76522586觉得博文有用,请点赞,请评论,请关注,谢谢!~ 表单嵌套: <!DO ...

  6. Redis的高可用技术方案

    引言: redis是广为使用的缓存解决方案,本文将给出基于Sequential的高可用方案,自动进行主从的切换,在master节点down机之后,透明的进行切换. 主从节点的设置方案 设置主节点red ...

  7. Vim技能修炼教程(1) - 使用vundle管理插件

    世界上有两个伟大的编辑器:一个是emacs,一个是vi.它们从诞生以来,一直在Unix/Linux世界得到最广泛的支持. 尽管过了几十年,在Windows平台上和跨平台上有层出不穷的后起之秀不断挑战它 ...

  8. Shell 批量搜索关键词并保存结果到文件中(数组、循环)

    #!/bin/bash keywords=("不需要" "不用谢谢" "xxx" "xxx") for var in $ ...

  9. 什么是URL,URI或URN?

    什么是URI? 每个Web服务器资源都有一个名字,这样客户端就可以说明它们感兴趣的资源是什么了. 服务器资源名被称为统一资源标识符(Uniform Resource Identifier, URI). ...

  10. linux中的网络基础

    ifconfig -a 查看所有网口ifconfig eth 查看具体网口 ifup ethoifdown etho 网卡配置文件/etc/sysconfig/networkk-scripts/ifc ...