之前结合网上的一些代码及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. 019——VUE中v-for与computer结合功能实例讲解

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. HDU 2062 Subset sequence 数位dp,思路 难度:1

    http://acm.hdu.edu.cn/showproblem.php?pid=2062 Subset sequence Time Limit: 1000/1000 MS (Java/Others ...

  3. SSM整合Redis

    前言 服务端缓存的意义大多数在于减轻数据库压力,提供响应速度,而缺点也是显而易见的,会带来缓存与数据库一致性问题.当然,Redis还可以作为分布式锁. Redis 想在项目中使用Redis需要做的事情 ...

  4. cocoapods导入第三方库后,xcode上import不提示,找不到第三方库的解决办法

    选择你的工程tagets, -> Build Settings -> Search Paths -> User Header Search Paths 双击User Header S ...

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

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

  6. Uncaught TypeError: Cannot read property 'ownerDocument' of null

    /********************************************************************* * Uncaught TypeError: Cannot ...

  7. Jmeter-Threads(Users)

    setUp Thread Group---测试开始前的准备操作,每次测试前都会执行 A special type of ThreadGroup that can be utilized to perf ...

  8. Codeforces 914H Ember and Storm's Tree Game 【DP】*

    Codeforces 914H Ember and Storm's Tree Game 题目链接 ORZ佬 果然出了一套自闭题 这题让你算出第一个人有必胜策略的方案数 然后我们就发现必胜的条件就是树上 ...

  9. POJ2987 Firing 【最大权闭合图】

    POJ2987 Firing Description You've finally got mad at "the world's most stupid" employees o ...

  10. Excel VBA to Interact with Other Applications

    转载自:https://analysistabs.com/excel-vba/interact-with-other-applications/ Interact with PowerPoint fr ...