优化Duilib图片属性解析代码,提升绘制效率
Posted Redrain
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优化Duilib图片属性解析代码,提升绘制效率相关的知识,希望对你有一定的参考价值。
转载请说明原出处,谢谢~·http://blog.csdn.net/zhuhongshu/article/details/51245751
好长时间没写duilib博客了,最近在写毕业设计,毕设的软件界面自然就用比较熟悉的Duilib来搞了,正好把Duilib的一些地方一起改改。
Duilib的图片绘制代码中有个影响性能的地方,所有的控件的图片绘制都是调用CControlUI的DrawImage函数,而此函数调用了CRenderEngine的DrawImageString函数。在绘制图片时,DrawImageString会解析图片字符串的属性,然后找到对片的HBITMAP资源,最后调用真正的绘图函数去绘制。问题就在于每绘制一个图片都会再次解析一次字符串,当界面比较复杂,而且图片字符串也比较复杂时,这个解析的过程就影响了程序效率。
实际上这个字符串在被赋值后,只需要解析一次,然后缓存起来就可以了,在绘制图片时直接用缓存好的图片属性数据。使用内存换效率的方法可以进一步提高Duilib的效率。
写了一个图片属性解析类,代替原本的图片字符串,并且去掉了原本的DrawImageString函数。
class UILIB_API CImageAttribute
public:
CImageAttribute();
CImageAttribute(const CImageAttribute&);
const CImageAttribute& operator=(const CImageAttribute&);
virtual ~CImageAttribute();
CDuiString GetAttributeString() const;
void SetAttributeString(LPCTSTR pStrImageAttri);
void ModifyAttribute(LPCTSTR pStrModify);
bool LoadImage(CPaintManagerUI* pManager);
bool IsLoadSuccess();
operator LPCTSTR() const;
bool operator ==(LPCTSTR pStrImage) const;
const CDuiString& operator=(const CDuiString& src);
const CDuiString& operator=(const TCHAR ch);
const CDuiString& operator=(LPCTSTR pstr);
private:
void Clone(const CImageAttribute&);
void Clear();
void ParseAttribute(LPCTSTR pStrImageAttri);
protected:
friend class CRenderEngine;
CDuiString m_sImageAttribute;
CDuiString m_sImage;
CDuiString m_sResType;
TImageInfo *m_imageInfo;
bool m_bLoadSuccess;
RECT m_rcDest;
RECT m_rcSource;
RECT m_rcCorner;
BYTE m_bFade;
DWORD m_dwMask;
bool m_bHole;
bool m_bTiledX;
bool m_bTiledY;
;
CImageAttribute::CImageAttribute()
Clear();
CImageAttribute::CImageAttribute(const CImageAttribute& image)
Clone(image);
const CImageAttribute& CImageAttribute::operator=(const CImageAttribute& image)
Clone(image);
return *this;
void CImageAttribute::Clone(const CImageAttribute& image)
m_sImageAttribute = image.m_sImageAttribute;
m_sImage = image.m_sImage;
m_sResType = image.m_sResType;
m_imageInfo = image.m_imageInfo;
m_bLoadSuccess = image.m_bLoadSuccess;
m_rcDest = image.m_rcDest;
m_rcSource = image.m_rcSource;
m_rcCorner = image.m_rcCorner;
m_bFade = image.m_bFade;
m_dwMask = image.m_dwMask;
m_bHole = image.m_bHole;
m_bTiledX = image.m_bTiledX;
m_bTiledY = image.m_bTiledY;
CImageAttribute::~CImageAttribute()
CDuiString CImageAttribute::GetAttributeString() const
return m_sImageAttribute;
void CImageAttribute::SetAttributeString(LPCTSTR pStrImageAttri)
if (m_sImageAttribute == pStrImageAttri)
return;
Clear();
m_sImageAttribute = pStrImageAttri;
m_sImage = m_sImageAttribute;
ParseAttribute(pStrImageAttri);
bool CImageAttribute::LoadImage(CPaintManagerUI* pManager)
if (m_imageInfo != NULL)
return true;
if (!m_bLoadSuccess)
return false;
const TImageInfo* data = NULL;
if (m_sResType.IsEmpty())
data = pManager->GetImageEx((LPCTSTR)m_sImage, NULL, m_dwMask);
else
data = pManager->GetImageEx((LPCTSTR)m_sImage, (LPCTSTR)m_sResType, m_dwMask);
if (data == NULL)
m_bLoadSuccess = false;
return false;
else
m_bLoadSuccess = true;
if (m_rcSource.left == 0 && m_rcSource.right == 0 && m_rcSource.top == 0 && m_rcSource.bottom == 0)
m_rcSource.right = data->nX;
m_rcSource.bottom = data->nY;
if (m_rcSource.right > data->nX) m_rcSource.right = data->nX;
if (m_rcSource.bottom > data->nY) m_rcSource.bottom = data->nY;
m_imageInfo = const_cast<TImageInfo*>(data);
return true;
bool CImageAttribute::IsLoadSuccess()
return !m_sImageAttribute.IsEmpty() && m_bLoadSuccess;
void CImageAttribute::ModifyAttribute(LPCTSTR pStrModify)
ParseAttribute(pStrModify);
void CImageAttribute::Clear()
m_sImageAttribute.Empty();
m_sImage.Empty();
m_sResType.Empty();
m_imageInfo = NULL;
m_bLoadSuccess = true;
ZeroMemory(&m_rcDest, sizeof(RECT));
ZeroMemory(&m_rcSource, sizeof(RECT));
ZeroMemory(&m_rcCorner, sizeof(RECT));
m_bFade = 0xFF;
m_dwMask = 0;
m_bHole = false;
m_bTiledX = false;
m_bTiledY = false;
void CImageAttribute::ParseAttribute(LPCTSTR pStrImage)
if (pStrImage == NULL)
return;
// 1、aaa.jpg
// 2、file='aaa.jpg' res='' restype='0' dest='0,0,0,0' source='0,0,0,0' corner='0,0,0,0'
// mask='#FF0000' fade='255' hole='false' xtiled='false' ytiled='false'
CDuiString sItem;
CDuiString sValue;
LPTSTR pstr = NULL;
while (*pStrImage != _T('\\0'))
sItem.Empty();
sValue.Empty();
while (*pStrImage > _T('\\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
while (*pStrImage != _T('\\0') && *pStrImage != _T('=') && *pStrImage > _T(' '))
LPTSTR pstrTemp = ::CharNext(pStrImage);
while (pStrImage < pstrTemp)
sItem += *pStrImage++;
while (*pStrImage > _T('\\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
if (*pStrImage++ != _T('=')) break;
while (*pStrImage > _T('\\0') && *pStrImage <= _T(' ')) pStrImage = ::CharNext(pStrImage);
if (*pStrImage++ != _T('\\'')) break;
while (*pStrImage != _T('\\0') && *pStrImage != _T('\\''))
LPTSTR pstrTemp = ::CharNext(pStrImage);
while (pStrImage < pstrTemp)
sValue += *pStrImage++;
if (*pStrImage++ != _T('\\'')) break;
if (!sValue.IsEmpty())
if (sItem == _T("file") || sItem == _T("res"))
m_sImage = sValue;
else if (sItem == _T("restype"))
m_sResType = sValue;
else if (sItem == _T("dest"))
m_rcDest.left = _tcstol(sValue.GetData(), &pstr, 10); ASSERT(pstr);
m_rcDest.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
m_rcDest.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
m_rcDest.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
else if (sItem == _T("source"))
m_rcSource.left = _tcstol(sValue.GetData(), &pstr, 10); ASSERT(pstr);
m_rcSource.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
m_rcSource.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
m_rcSource.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
else if (sItem == _T("corner"))
m_rcCorner.left = _tcstol(sValue.GetData(), &pstr, 10); ASSERT(pstr);
m_rcCorner.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
m_rcCorner.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
m_rcCorner.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
else if (sItem == _T("mask"))
if (sValue[0] == _T('#')) m_dwMask = _tcstoul(sValue.GetData() + 1, &pstr, 16);
else m_dwMask = _tcstoul(sValue.GetData(), &pstr, 16);
else if (sItem == _T("fade"))
m_bFade = (BYTE)_tcstoul(sValue.GetData(), &pstr, 10);
else if (sItem == _T("hole"))
m_bHole = (_tcscmp(sValue.GetData(), _T("true")) == 0);
else if (sItem == _T("xtiled"))
m_bTiledX = (_tcscmp(sValue.GetData(), _T("true")) == 0);
else if (sItem == _T("ytiled"))
m_bTiledY = (_tcscmp(sValue.GetData(), _T("true")) == 0);
if (*pStrImage++ != _T(' ')) break;
CImageAttribute::operator LPCTSTR() const
return m_sImageAttribute;
bool CImageAttribute::operator==(LPCTSTR pStrImage) const
return m_sImageAttribute == pStrImage;
const CDuiString& CImageAttribute::operator=(const CDuiString& src)
SetAttributeString(src);
return m_sImageAttribute;
const CDuiString& CImageAttribute::operator=(LPCTSTR lpStr)
SetAttributeString(lpStr);
return m_sImageAttribute;
const CDuiString& CImageAttribute::operator=(const TCHAR ch)
m_sImageAttribute = ch;
SetAttributeString(m_sImageAttribute);
return m_sImageAttribute;
对CControlUI控件的修改如下:
bool CControlUI::DrawImage(HDC hDC, CImageAttribute& image, const RECT& rcDest, LPCTSTR pStrModify /*= NULL*/)
if (!image.LoadImage(m_pManager))
return false;
if (pStrModify != NULL)
CImageAttribute modifyImage = image;
modifyImage.ModifyAttribute(pStrModify);
return CRenderEngine::DrawImage(hDC, m_pManager, rcDest, m_rcPaint, modifyImage);
return CRenderEngine::DrawImage(hDC, m_pManager, rcDest, m_rcPaint, image);
为CRenderEngine类新增DrawImage函数代替DrawImageString函数:
bool CRenderEngine::DrawImage(HDC hDC, CPaintManagerUI* pManager, const RECT& rcControl, const RECT& rcPaint, CImageAttribute& image)
if ((pManager == NULL) || (hDC == NULL))
return false;
if (image.m_sImage.IsEmpty())
return false;
TImageInfo* data = image.m_imageInfo;
if (!data) return false;
RECT rcDest = image.m_rcDest;
rcDest.left += rcControl.left;
rcDest.top += rcControl.top;
rcDest.right = rcDest.left + rcControl.right;
if (rcDest.right > rcControl.right)
rcDest.right = rcControl.right;
rcDest.bottom = rcDest.top + rcControl.bottom;
if (rcDest.bottom > rcControl.bottom)
rcDest.bottom = rcControl.bottom;
RECT rcTemp;
if (!::IntersectRect(&rcTemp, &rcDest, &rcControl)) return true;
if (!::IntersectRect(&rcTemp, &rcDest, &rcPaint)) return true;
CRenderEngine::DrawImage(hDC, data->hBitmap, rcDest, rcPaint, image.m_rcSource, image.m_rcCorner,
pManager->IsBackgroundTransparent() ? true : data->alphaChannel,
image.m_bFade, image.m_bHole, image.m_bTiledX, image.m_bTiledY);
return true;
总结:
这次修改的内容比较多,因为每个控件原本都有图片字符串,所以我把很多控件的绘制代码对应的修改了,这些就不贴了。所有控件的修改我都提交到我个人的Duilib库中: 点击打开链接Redrain QQ:491646717 2016.4.26
以上是关于优化Duilib图片属性解析代码,提升绘制效率的主要内容,如果未能解决你的问题,请参考以下文章
duilib corner属性的贴图技巧——让图片自动贴到控件的的某一边或者一角并自适应控件的大小
duilib corner属性的贴图技巧——让图片自动贴到控件的的某一边或者一角并自适应控件的大小