65.9K
CodeProject 正在变化。 阅读更多。
Home

释放 Windows Mobile 上的 GDI+ 功能

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (7投票s)

2009年4月21日

CPOL

3分钟阅读

viewsIcon

49069

downloadIcon

850

如何在 Windows Mobile 上使用 GDI+。

GDIPlusCE

引言

最近,我想评估在 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+ 仅部分实现,并且许多函数(例如,FontFontFamily)返回 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 日:文章已提交。
© . All rights reserved.