您的位置:首页 > 产品设计 > UI/UE

soui中apng 图像解码器解码图片后像素格式研究

2015-12-29 13:01 411 查看
     soui是一个非常牛逼的界面库,里面对图片透明有着很好的支持,这也是我喜欢soui的一个重要原因。soui中不仅可以设置主窗口半透明,而且还可以设置soui子窗口半透明,两者的设置都非常的简单。只需要在xml中设置下属性就好了。

     但我一直好奇,透明技术是如何实现的。看了下soui的源码,在渲染引擎为gdi模式下,透明实现用了UpdateLayeredWindow和AlphaBlend技术,两者都有一个共同的BLENDFUNCTION 参数,这个结构体对透明有着重要的影响。

    前几天在msdn上面找到了一个Alpha Blending a Bitmap(Windows)的一段 代码,下面是该原文地址的连接:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd183353%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396[/code] 
   在注释里面我发现了这样一句话:msdn意思是说32位位图像素格式是0xaarrggbb格式的。我尝试修改了像素值发现确实是这样。

// in top window area, constant alpha = 50%, but no source alpha
// the color format for each pixel is 0xaarrggbb
// set all pixels to blue and set source alpha to zero

   soui中还有一个非常牛逼的地方就是,支持多种图像解码模块,比如stb,wic,apng,gdi+,我发现除了用gdi+解码图像时用的是argb格式外,其他三种解码模块都不是argb格式,而是bgra格式。这让我很疑惑。比如下面这个是apng解码时的部分代码:

int SImgX_PNG::_DoDecode(APNGDATA *pData)
{
if(!pData) return 0;
m_pngData = pData;

int nWid = m_pngData->nWid;
int nHei = m_pngData->nHei;

//swap rgba to bgra and do premultiply
BYTE *p=m_pngData->pdata;
int pixel_count = nWid * nHei * m_pngData->nFrames;
for (int i=0; i < pixel_count; ++i) {
BYTE a = p[3];
BYTE t = p[0];
if (a)
{
p[0] = (p[2] *a)/255;
p[1] = (p[1] * a)/255;
p[2] =  (t   * a)/255;
}else
{
memset(p,0,4);
}
p += 4;
}

p=m_pngData->pdata;
m_pImgArray = new SImgFrame_PNG[m_pngData->nFrames];
for(int i=0;i<m_pngData->nFrames;i++)
{
m_pImgArray[i].Attach(p,nWid,nHei,m_pngData->pDelay?m_pngData->pDelay[i]:0);
p += nWid*nHei*4;
}
return m_pngData->nFrames;
}

       但msdn上面说的像素格式应该是0xaarrggbb的,咋一看好看soui中解码的bgra跟msdn上面说的不一样,刚开始我也是这么认为,后来发现是对的。如下是我进行的试验:

      查看了下apng的文档,发现apng是支持直接解码成argb格式的,在decoder-apng.cpp中的 APNGDATA*  loadPng(IPngReader* pSrc)函数中的 png_read_update_info 下面加入以下代码,这里就将图片格式解析成了argb。

if (png_ptr_read->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
png_set_swap_alpha(png_ptr_read);

然后在相同文件下把 _DoDecode()函数替换如下:      

int SImgX_PNG::_DoDecode(APNGDATA *pData)
{
if(!pData) return 0;
m_pngData = pData;

int nWid = m_pngData->nWid;
int nHei = m_pngData->nHei;

//swap rgba to bgra and do premultiply
BYTE *p=m_pngData->pdata;
int pixel_count = nWid * nHei * m_pngData->nFrames;
for (int i=0; i < pixel_count; ++i) {
BYTE a = p[0];
BYTE t = p[0];
if (a)
{
BYTE k = p[0];
p[0] = p[3];
p[3] = k;
k = p[1];
p[1] = p[2];
p[2] = k;
p[0] = p[0] * t/255;
p[1] = p[1]*t/255;
p[2] = p[2] * t/255;
}else
{
memset(p,0,4);
}
p += 4;
}

p=m_pngData->pdata;
m_pImgArray = new SImgFrame_PNG[m_pngData->nFrames];
for(int i=0;i<m_pngData->nFrames;i++)
{
m_pImgArray[i].Attach(p,nWid,nHei,m_pngData->pDelay?m_pngData->pDelay[i]:0);
p += nWid*nHei*4;
}
return m_pngData->nFrames;
}        编译运行也可以显示正常效果,这里就说明了apng解码出来的argb格式在内存中地址从低到高依次是b,g,r,a,这样跟msdn描述的就一样了,实在还不相信的话,可以在debug模式下面看内存数据的变化,这同样也可以发现这一点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  界面 soui directui