使用GdiPlus慢速绘图

时间:2016-05-15 17:51:17

标签: c++ winapi bitmap gdi+ gdi

我有代码,将PNG资源转换为GdiPlus::Bitmap并绘制它。

void ResBit(HINSTANCE hInstance,HDC hdcC,HWND hwnd, char *Name, int x,int y,int cx,int cy)
{
    spe sp;
    sp.h=hInstance;
    sp.name=Name;
    static int save[1000][3]={NULL};
    static int count=0;
int current;
for(int i(0);i<=count;i++)
{
if(save[i][0]==(int)hInstance&&save[i][1]==(int)Name)
{
        current=i;
        break;
}
if(i==count)
{
if (HRSRC resource = ::FindResourceA(hInstance, Name, "PNG"))
if (DWORD size = ::SizeofResource(hInstance, resource))
    if (const void* data = ::LockResource(::LoadResource(hInstance, resource)))
        if (HGLOBAL handle  = ::GlobalAlloc(GMEM_MOVEABLE, size)) {
            if (void* buffer = ::GlobalLock(handle)) {
                    CopyMemory(buffer, data, size);

                IStream* stream = NULL;
                if (::CreateStreamOnHGlobal(handle, FALSE, &stream) == S_OK)
                {
                    if (Bitmap* bitmap = 
                       Bitmap::FromStream(stream))
                    { 
                        if (bitmap->GetLastStatus() == Gdiplus::Ok) {

                            save[i][0]=(int)hInstance;
                            save[i][1]=(int)Name;
                            save[i][2]=(int)bitmap;
                            current=i;
                            count++;

                            break;
                        }
                    }
                    stream->Release();
                }
                GlobalUnlock(handle);
            }
        }
}
    }
RECT r;
GetClientRect(hwnd,&r);
Graphics g(hdcC);
if(!cx)
    g.DrawImage((Bitmap*)save[current][2],0,0,r.right,r.bottom);
 else
    g.DrawImage((Bitmap*)save[current][2],x,y,cx,cy);
}

所以当出现HINSTANCE并命名时,请检查static数组save是否有相同的数据。如果是,则返回Bitmap。如果不是,它会找到新资源,创建新的Bitmap并将数据添加到数组中。在使用Graphics::DrawImage检查绘图后。麻烦就是速度。它绘制得非常慢。我尝试将GdiPlus::Bitmap转换为HBITMAP,但遭遇了挫折。

怎么样?我需要快速画画。

1 个答案:

答案 0 :(得分:0)

static int save[1000][3]={NULL};
...
save[i][2]=(int)bitmap;

您无法强制所有内容转换为整数并返回其他数据类型。如果您开始使用Unicode函数,也可以避免很多问题。

Gdiplus::Bitmap *loadpng(HINSTANCE hInstance, const wchar_t* Name)
{
    Gdiplus::Bitmap *result = NULL;
    HRSRC resource = ::FindResourceW(hInstance, Name, L"PNG");
    if (resource)
    {
        DWORD size = ::SizeofResource(hInstance, resource);
        if (size)
        {
            LPVOID data = ::LockResource(::LoadResource(hInstance, resource));
            if (data)
            {
                HGLOBAL handle = ::GlobalAlloc(GMEM_MOVEABLE, size);
                if (handle)
                {
                    void* buffer = ::GlobalLock(handle);
                    if (buffer)
                    {
                        CopyMemory(buffer, data, size);
                        IStream* stream = NULL;
                        if (::CreateStreamOnHGlobal(handle, FALSE, &stream) == S_OK)
                        {
                            if (Gdiplus::Bitmap* bitmap = Gdiplus::Bitmap::FromStream(stream))
                            {
                                if (bitmap->GetLastStatus() == Gdiplus::Ok)
                                {
                                    result = bitmap;
                                }
                            }
                            stream->Release();
                        }
                    }
                    GlobalUnlock(handle);
                }
            }
        }
    }
    return result;
}

用法:

Gdiplus::Bitmap* bitmap = loadpng(hInstance, L"RESOURCE_ID"); //or MAKEINTRESOURCE...
Gdiplus::Graphics g(hdc);
g.DrawImage(bitmap, x, y, w, h);

如果这个功能很慢那么就是这样。应用程序一次最多可以使用10,000个资源。如果有数千张图像并达到10,000限制,则应用程序可能会减速停止。

您可能希望使用容器来避免每次都加载图像(但每次调用只会节省几微秒)。例如:

#include <map>
#include <string>
...
void ResBit(HINSTANCE hInstance, HDC hdc, wchar_t *Name, int x, int y, int w, int h)
{
    static std::map<std::wstring, Gdiplus::Bitmap*> map;

    if (!map.count(Name))
        map[Name] = loadpng(hInstance, Name);

    Gdiplus::Bitmap* bitmap = map[Name];
    if (!bitmap)
        return;

    Gdiplus::Graphics g(hdc);
    g.DrawImage(bitmap, x, y, w, h);
}