释放 Windows Mobile 上的 GDI+ 功能






4.86/5 (7投票s)
如何在 Windows Mobile 上使用 GDI+。
引言
最近,我想评估在 Windows Mobile 设备上使用 OpenGL ES 的情况,而且像往常一样,我发现了很多不错的文章,但都是用 C# 编写的。 所以,我开始将它们移植到 WTL/C++,但在移植过程中,我开始想,是否可以找到一种更容易翻译图形部分的方法,经过一些研究,我找到了一篇来自 Alex Feinman 的非常好的文章,题为“在 Windows Mobile 上使用 GDI+”。有趣的部分是它使用 Marshalling 来调用 GDI+,这意味着 GDI+ 可以与原生代码一起使用。然后,经过更多的研究,我找到了一组类和来自 Ernest Laurentin 的一个库,它是一个围绕 GDI+ 的包装器,可以在原生代码中使用。
背景
GDI+ 是微软于 2001 年推出的一款图形库,旨在简化二维绘图。它运行在 GDI32 之上,除了编程模型的更改之外,它还增加了新功能,例如渐变填充、抗锯齿、更广泛的图像处理等。 GDI+ 有两个主要组件:一个主要的实现所在的扁平 C API,以及位于与 GDI+ 关联的公共头文件中的 C++ 包装器。
不幸的是,在 Windows Mobile 上,GDI+ 仅部分实现,并且许多函数(例如,Font
和 FontFamily
)返回 NotImplemented
。
使用代码
为了能够使用 GDI+,您首先需要对其进行初始化,如下所示
ULONG_PTR _gdiplusToken;
// Initialize GDI+
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&_gdiplusToken, &gdiplusStartupInput, NULL);
...
int nRet = CMainFrame::AppRun(lpstrCmdLine, nCmdShow);
...
// Release GDI+
Gdiplus::GdiplusShutdown(_gdiplusToken);
缺失函数的实现(Bitmap)
正如我上面所写,GDI+ 分为两部分,一个导出一些用于处理内存和绘图的 C 函数的 gdiplus.dll,以及一些内联声明并调用导出的函数的 C++ 类。请注意,分配/释放运算符已被重载,因为内存管理由 DLL 完成。
所以,如果你写下以下代码
Gdiplus:: Pen pen = new Pen(Color::Black, 15);
将调用以下函数
DllExports::GdipAlloc(in_size);
- 对应于new
运算符DllExports::GdipCreatePen1
- 对应于Pen(IN const Color& color, IN REAL width = 1.0f)
在 Windows Mobile 上,某些函数未实现,尤其是我关注的 Bitmap
类。
如果您查看 MSDN,您将看到可以从文件、资源、流或 HBITMAP
创建一个 Gdiplus::Bitmap
,但根据我在 Windows Mobile 6 上的实验,仅实现了以下函数
DllExports::GdipCreateBitmapFromStreamICM(...)
DllExports::GdipCreateBitmapFromScan0(..)
DllExports::GdipCreateBitmapFromGraphics(...)
DllExports::GdipCreateBitmapFromGdiDib(...)
DllExports::GdipCreateBitmapFromHBITMAP(hbm, hpal, &bitmap)
所以,我实现了缺失的函数,以便能够轻松地从文件或资源加载位图,并保存它们。
位图加载的实现依赖于 GdipCreateBitmapFromStreamICM
,并且我开发了两个用于流文件 (CStreamOnFile
) 和资源 (CStreamOnResource
) 的类。 我已将这两个对象的两个指针添加到基本 Image 类中。
class Image : public GdiplusBase
{
...
#ifdef _WIN32_WCE
CStreamOnFile* pFileStream;
CStreamOnResource* pResStream;
#endif
...
};
在位图实现中
inline
Bitmap::Bitmap(
IN HINSTANCE hInstance,
IN const WCHAR *bitmapName
)
{
GpBitmap *bitmap = NULL;
lastResult = DllExports::GdipCreateBitmapFromResource(hInstance,
bitmapName,
&bitmap);
#if defined(UNDER_CE)
if (lastResult == NotImplemented)
{
pResStream = new CStreamOnResource(bitmapName);
if ( pResStream->Init(hInstance, bitmapName) )
{
if (pResStream->GetResType() == RT_BITMAP) {
// code below doesn't work - image is upside down
/*const BITMAPINFO* pBmi = (BITMAPINFO*)pResStream->GetResData();
lastResult = DllExports::GdipCreateBitmapFromGdiDib(
pBmi, (void*)(pBmi+sizeof(BITMAPINFO)), &bitmap);*/
HBITMAP hBmp = LoadBitmap(hInstance, bitmapName);
if (hBmp)
{
lastResult = DllExports::GdipCreateBitmapFromHBITMAP(hBmp,
NULL, &bitmap);
}
}
else if (pResStream->GetResType() == RT_GROUP_ICON) {
HICON hIcon = LoadIcon(hInstance, bitmapName);
if (hIcon)
{
lastResult =
DllExports::GdipCreateBitmapFromHICON(hIcon, &bitmap);
}
}
else
lastResult =
DllExports::GdipCreateBitmapFromStreamICM(pResStream, &bitmap);
}
}
#endif
SetNativeImage(bitmap);
}
不幸的是,在 Windows Mobile 上,EnumResourceTypes
未实现,因此我选择仅处理以下资源类型
RT_BITMAP
PNG
JPEG
GIF
如何使用
因此,现在,您应该能够轻松加载和保存图像,如下所示
#include "gdiplushelper.h"
HINSTANCE hResInstance = ModuleHelper::GetResourceInstance();
// Load image from resource
bmpRes = Bitmap::FromResource(hResInstance, MAKEINTRESOURCE(IDR_JPEG2));
// Load image from file
bmpFile = Bitmap::FromFile(_T("\\My Documents\\My Pictures\\Spring.jpg"));
// Save file
CLSID encoderClassId;
if (GetEncoderClsid(m_pImgFactory, L"image/png", &encoderClassId) == TRUE)
GdiplusSaveBitmap(m_pImgFactory, &*bmp,
_T("testsave.png"), &encoderClassId);
结论
Windows Mobile 官方不支持 GDI+,我不建议将其用于大型应用程序。 但是,如果您需要处理一些位图,此包装器可能会有所帮助。 请注意,我没有测试索引位图,如果您使用带有调色板的位图,则可能会遇到一些问题。
历史
- 2009 年 4 月 21 日:文章已提交。