Wince/VC高效PNG贴图,自定义Alpha算法
工作中,做一些炫点的界面都需要用到PNG图片,Wince里面微软也提供了PNG图片的支持,不过Alpha的混合速度比较慢,所以自己实现了一个Alpha的混合运算接口,经过测试,要比微软AlphaBlend快4、5倍。当然Alpha混合的方法也适合window下的VC使用。下面有测试的数据。
原创博文,需要转载,请标明出处:http://www.cnblogs.com/mythou/p/3150396.html
1、创建兼容32位位图。
一般界面贴图,我们都是使用微软的兼容DC和兼容位图进行处理。不过这里我需要创建一张32位的设备无关位图。(有关DIB位图相关知识,不了解的可以百度一下,这是和兼容位图对应的一种位图格式。这里就不多说了)。
/*
*hDC:兼容的DC指针
*nWidth:需要创建DIB位图宽
*nHeight:创建位图高
*pBitmapData:这是我自己定义的数据类型,就是一个unsigned char * 类型
*/ HBITMAP CPngBitBlt::Create32Bitmap(HDC hDC, int nWidth, int nHeight,HBMDC &pBitmapData)
{
if(hDC == NULL)
{
return NULL;
} if(nWidth== || nHeight==)
{
return NULL;
} BITMAPINFO *pbinfo = new BITMAPINFO;
if(!pbinfo)
{
return NULL;
}
ZeroMemory(pbinfo, sizeof(BITMAPINFO));
pbinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbinfo->bmiHeader.biWidth = nWidth;
pbinfo->bmiHeader.biHeight = -nHeight;//位图翻转
pbinfo->bmiHeader.biPlanes = ;
pbinfo->bmiHeader.biBitCount = ;//32位位图 BYTE* lpBitmapBits = NULL;
HBITMAP hDIBmp = CreateDIBSection(hDC, pbinfo, DIB_RGB_COLORS, (void **)&lpBitmapBits, NULL, );
pBitmapData = lpBitmapBits; delete pbinfo; if(hDIBmp == NULL)
{
return NULL;
} return hDIBmp;
}
上面的函数是创建一张指定大小的DIB位图,而且返回这张位图的数据指针(指向位图数据的首指针)。
这张位图,一般就是用来当做背景位图,我们一般贴图使用的双缓冲方式,需要前后两张位图,这个DIB位图就是用做内存DC的位图。
2、加载PNG图片
PNG图片加载,这里还是使用微软的IImage解码PNG图片,使用过pnglib解码库,实际解码速度还比不上IImage,也可能是我编译的libpng库没有做优化吧。所以暂时放弃使用libpng。后续有时间会研究一下libpng解码的原理和嵌入式上优化方式。Android上也是使用libpng解码png,所以解码速度应该还是可以的,不过估计需要做一些嵌入式平台的化,比较大部分嵌入式平台机器CPU主频都不高,(现在的手机例外 -_-!),我工作接触的一般也就400M到800M的范围。下面是解码部分代码,主要是从IImage解码PNG图片,然后把PNG图片构造一个DIB位图,获取一个可以操作图片的指针。
BOOL CImageData::LoadImageFromFile(const TCHAR *fileName)
{
// 参数有效性
if (fileName == NULL)
{
return FALSE;
} // 创建COM实例
HRESULT hr = NULL;
if(FAILED(hr = ::CoCreateInstance(CLSID_ImagingFactory,NULL,CLSCTX_INPROC_SERVER,IID_IImagingFactory,(void**) &m_pImagingFactory)))
{
return FALSE;
}// 从文件中创建图片
if(FAILED(hr = m_pImagingFactory->CreateImageFromFile(fileName, &m_pImage)))
{
return FALSE;
} // 得到图片信息
if(FAILED(hr = m_pImage->GetImageInfo(&m_ImageInfo)))
{
return FALSE;
} // 获取原始数据
if (ReadImageData() == FALSE)
{
return FALSE;
} //......// 成功获得图片信息
return TRUE;
}
BOOL CImageData::ReadImageData()
{
// 用于返回结果
BOOL bRet = TRUE; // 参数有效性
if (m_pImage==NULL || m_pImagingFactory==NULL)
{
return FALSE;
} // 取得图片原始数据
RECT rect = {, , m_ImageInfo.Width, m_ImageInfo.Height};
BitmapData bitmapData;
bitmapData.Width = m_ImageInfo.Width;
bitmapData.Height = m_ImageInfo.Height;
bitmapData.PixelFormat = m_ImageInfo.PixelFormat;
IBitmapImage *pBitmapImage = NULL;
m_pImagingFactory->CreateBitmapFromImage(m_pImage, m_ImageInfo.Width, m_ImageInfo.Height, PIXFMT_32BPP_ARGB, InterpolationHintDefault, &pBitmapImage);
pBitmapImage->LockBits(&rect, ImageLockModeRead, PIXFMT_32BPP_ARGB, &bitmapData); // 释放旧数据
if (m_pImgDataBuf != NULL)
{
delete[] m_pImgDataBuf;
m_pImgDataBuf = NULL;
} // 申请新空间
bRet = TRUE;
m_pImgDataBuf = new unsigned char[m_ImageInfo.Width * m_ImageInfo.Height * ];
if (m_pImgDataBuf == NULL)
{
bRet = FALSE;
goto ERROR_END_FUNCTION;
} // 拷贝数据
bRet = TRUE;
memcpy(m_pImgDataBuf, bitmapData.Scan0, m_ImageInfo.Width * m_ImageInfo.Height * ); ERROR_END_FUNCTION:
pBitmapImage->UnlockBits(&bitmapData);
pBitmapImage->Release();
return bRet;
}
上面主要m_pImgDataBuf 就是一个Byte *的指针,一个指向PNG图片数据的起始指针。我们利用这个指针就可以操作我们刚刚解码的PNG图片的数据。
3、Alpha混合
首先说说Alpha混合,Alpha是指PNG图片的透明度,一般我们使用PNG图片就是为了可以有半透明的显示效果,大部分比较炫的界面,都有这些半透明特效使用,Alpha就是指定图片的透明度,一般图片的透明度我们可以分为两种。
第一:整张图片的Alpha值,图片每个像素使用同一个Alpha值。
第二:每个像素使用独立的Alpha值。
对于32位的PNG图片来说,每个像素值,都保存了自己的Alpha值,32位PNG的像素格式:ARGB8888就是,每个值都是一个8位值。
Alpha混合的基本公式如下:AlphaResult = ALPHA * srcPixel + ( 1 - ALPHA ) * destPixel
下面给出一个Alpha的混合算法例子。
//支持自定义Alpha
//pBackDSSrcBmp:我们背景DIB位图的数据指针,也就是上面创建的DIB位图返回的指针pBitmapData
//m_ImgDataBuf:上面解码图片,获取的需要显示的PNG图片的数据指针
//支持自定义Alpha
void CImageData::DrawImage(HBMDC pBackDCSrcBmp, const int DstX, const int DstY, const int Alpha, DWORD DstBMPWidth)
{
//进行Alpha混合运算
BYTE btAlphaSRC = ;
DWORD iSrcPos = ;
int iDstPos = ; for(DWORD i=; i<m_ImageHeigh; i++)
{
DWORD SrcData = (i+DstY)*DstBMPWidth + DstX;
DWORD DstData = i*m_ImageWidth;
for(int j=; j<m_ImageWidth; j++)
{
// 计算源图像数据索引和像素点ALPHA
iSrcPos = (SrcData + j) << ;
iDstPos = (DstData + j) << ;
btAlphaSRC = m_pImgDataBuf[iDstPos+];
btAlphaSRC = btAlphaSRC*Alpha >> ; //ALPHA混合基本公式result = ALPHA * srcPixel + ( 1 - ALPHA ) * destPixel
pBackDCSrcBmp[iSrcPos] += (btAlphaSRC*(m_pImgDataBuf[iDstPos]-pBackDCSrcBmp[iSrcPos]) >> );
pBackDCSrcBmp[iSrcPos+] += (btAlphaSRC*(m_pImgDataBuf[iDstPos+]-pBackDCSrcBmp[iSrcPos+]) >> );
pBackDCSrcBmp[iSrcPos+] += (btAlphaSRC*(m_pImgDataBuf[iDstPos+]-pBackDCSrcBmp[iSrcPos+]) >> );
}
}
}
背景图和需要显示的PNG图片,两张图片对应像素值,根据Alpha混合混合,就可以得到最终的图片,这个就是整个显示过程。
这里的方法不仅仅针对PNG图片,其实对于jpg和bmp也是有效的,只是这两种图片,一般是不包含alpha信息的,所以只能控制整张图片的透明度,而不能控制每个像素的透明度。
上面的运算公式经过一些处理,主要是减少运算和减少乘除法的使用,比较cpu运行乘除法比不上加减法。
下面是我自己测试的数据结果:

这个是我在一台主频是600M的CPU上面运行的速度对比,速度单位是毫秒,可以对比,使用自己的Alpha混合要比微软的AlpBlend快不少,特别是针对大图片来说。
查过一些资料,大部分人的观点是微软的AlphaBlend里面处理过多的异常处理和对图片伸缩进行操作,导致比较慢。
有需要朋友可以自己根据我上面说的封装一个png贴图类,我前面写了一篇使用微软ALphBlend贴图的文章,里面给出了完整代码。
这个自定义的方法,代码比较多,我就不贴出来的。
微软AlphaBlend贴图类:http://www.cnblogs.com/mythou/archive/2013/06/13/3133606.html
如果有需要的朋友可以根据自己情况封装不同的接口处理,如果有不了解地方,可以留言。
新建的讨论群,有兴趣可以加入
VC/Wince群:87053214
Wince/VC高效PNG贴图,自定义Alpha算法的更多相关文章
- 你要是还学不会,请提刀来见 Typora+PicGo+Gitee + node.js 打造个人高效稳定优雅图床
你要是还学不会,请提刀来见 Typora+PicGo+Gitee + node.js 打造个人高效稳定优雅图床 经过前面两弹的介绍,相信大家对图床都不陌生了吧, 但是小魔童觉得这样做法还是不方便,使用 ...
- <<一种基于δ函数的图象边缘检测算法>>一文算法的实现。
原始论文下载: 一种基于δ函数的图象边缘检测算法. 这篇论文读起来感觉不像现在的很多论文,废话一大堆,而是直入主题,反倒使人觉得文章的前后跳跃有点大,不过算法的原理已经讲的清晰了. 一.原理 ...
- 带权图的最短路径算法(Dijkstra)实现
一,介绍 本文实现带权图的最短路径算法.给定图中一个顶点,求解该顶点到图中所有其他顶点的最短路径 以及 最短路径的长度.在决定写这篇文章之前,在网上找了很多关于Dijkstra算法实现,但大部分是不带 ...
- zw·准专利·高保真二值图细部切分算法
zw·准专利·高保真二值图细部切分算法 高保真二值图细部切分算法,是中国字体协会项目的衍生作品. 说准专利算法,是因为对于图像算法的标准不了解,虽然报过专利,但不是这方面的,需要咨询专 ...
- 图的基本算法(BFS和DFS)(转载)
图是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系.对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示. 图可以分为有向图和无向图,一般用G=(V,E)来表示图. ...
- 数据结构与算法系列研究七——图、prim算法、dijkstra算法
图.prim算法.dijkstra算法 1. 图的定义 图(Graph)可以简单表示为G=<V, E>,其中V称为顶点(vertex)集合,E称为边(edge)集合.图论中的图(graph ...
- 图的遍历算法:DFS、BFS
在图的基本算法中,最初需要接触的就是图的遍历算法,根据访问节点的顺序,可分为深度优先搜索(DFS)和广度优先搜索(BFS). DFS(深度优先搜索)算法 Depth-First-Search 深度优先 ...
- 图的基本算法(BFS和DFS)
图是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系.对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示. 图可以分为有向图和无向图,一般用G=(V,E)来表示图. ...
- 图的基本算法(BFS和DFS)
图是一种灵活的数据结构,一般作为一种模型用来定义对象之间的关系或联系.对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示. 图可以分为有向图和无向图,一般用G=(V,E)来表示图. ...
随机推荐
- 【转】TeXmacs:一个真正“所见即所得”的排版系统
TeXmacs:一个真正“所见即所得”的排版系统 好久没有推荐过自己喜欢的软件了,现在推荐一款我在美国做数学作业的私家法宝:TeXmacs.我恐怕不可能跟以前那么有闲心写个长篇的 TeXmacs 说明 ...
- JAVA Socket编程和C++ Socket编程有什么不同
原文链接: http://zhidao.baidu.com/link?url=16TEzhom2Nr8x1_2uTRp-e2pgZRgS5nW5ywtRX2XLHbtLOG8btif5DTyP85jf ...
- debian8最小化安装,字符界面的中文配置
一.现象: debian8最小化安装以后,字符界面的中文显示乱码. 二.解决 1. 安装locales apt-get install locales 2. 配置locales dpkg-reconf ...
- MPU6050陀螺仪和加速度计的校准
加速度计和陀螺仪的校准: 在传感器静止不动水平放置时,测出陀螺仪和加速度计各轴的偏移值,保存.以后每次上电调用dmp_set_xx_bias()就行了. u8 run_self_test(void) ...
- [转]PostgreSQL教程(十六):系统视图详解
这篇文章主要介绍了PostgreSQL教程(十六):系统视图详解,本文讲解了pg_tables.pg_indexes.pg_views.pg_user.pg_roles.pg_rules.pg_set ...
- JavaScript 如何从引用类型(Array 、 Object)创建一个新的对象
数组的增删改 1.新增一项可以使用concat方法,它不会对原有数组进行改动,而是创建一个新数组 let a = [0, 1, 2] let b = a.concat([3]) console.log ...
- 网络协议-网络分层、TCP/UDP、TCP三次握手和四次挥手
网络的五层划分是什么? 应用层,常见协议:HTTP.FTP 传输层,常见协议:TCP.UDP 网络层,常见协议:IP 链路层 物理层 TCP 和 UDP 的区别是什么 TCP/UDP 都属于传输层的协 ...
- HTTP、 TCP、 IP、 Socket、 XMPP
网络自下而上分为: 物理层 数据链路层 网络层 传输层 会话层 表示层 应用层 HTTP:应用层协议,主要解决如何包装数据 XMPP:应用层协议 TCP:传输层协议,主要解决数据如何在网络中传输 IP ...
- Android Studio 1.1.0 切换主题和绑定 代码提示 快捷键
这篇文章用于给刚从eclipse 转用 Android Studio 1.1.0的同学看的. 所以经常会更新的. 至于为什么要转Android Studio 1.1.0呢,就自己想吧.没有人强逼的. ...
- ASP.NET MVC中的cshtml页面中的下拉框的使用
ASP.NET MVC中的cshtml页面中的下拉框的使用 用上@Html.DropDownList 先记下来..以做备忘...