之前结合网上的一些代码及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. 026——VUE中事件修饰符之使用$event与$prevent修饰符操作表单

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. golang版并发爬虫

    准备爬取内涵段子的几则笑话,先查看网址:http://www.budejie.com/text/ 简单分析后发现每页的url呈加1趋势 第一页: http://www.budejie.com/text ...

  3. LeetCode OJ:House Robber II(房屋窃贼II)

    After robbing those houses on that street, the thief has found himself a new place for his thievery ...

  4. 如何解决虚拟机中的ubuntu系统方向键与退格键不能正常使用的问题

    问题描述: 在虚拟机中安装了ubuntu系统,打开vi,当vi进入insert模式后,后退键(backspace)不能删除字符,上下左右键也对应了W,S,A,D. 解决办法: cp /etc/vim/ ...

  5. CUDA库函数module management

    http://horacio9573.no-ip.org/cuda/group__CUDA__MODULE_ga52be009b0d4045811b30c965e1cb2cf.html

  6. LeetCode之Regular Expression Matching

    [题目描述] Implement regular expression matching with support for '.' and '*'. '.' Matches any single ch ...

  7. [置顶] JVM层对jar包字节码加密

    github https://github.com/sea-boat/ByteCodeEncrypt 需求 拿到的需求是要对某特定的jar包实现加密保护,jar包需要提供给外部使用,但核心逻辑部分需要 ...

  8. MPAndroidChart Wiki(译文)~Part 6

    22. ViewPortHandler ViewPortHandler负责处理图表的视窗.也就是说它负责图表视图中的展示给用户的那部分内容.包括图表位移,缩放级别,图表大小和绘制区域以及当前偏移量.V ...

  9. java IO 学习(一)

    io的类有好多个,总结一下,给他们列出来,下一行缩进为子类: File 文件或目录类 InputStream 字节输入流 FileInputStream 用于读取文件的原始字节流,变成字节输入流 By ...

  10. 【剑指offer】二叉树中和为某一值的路径,C++实现

    原创文章,转载请注明出处! 博客文章索引地址 1.题目 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径由结点和有向边组成,从根结点到叶节点. // 二叉树结点的定义 st ...