Introduction
Recently, I wanted to evaluate the use of OpenGL ES on Windows Mobile devices, and as always, I found very good articles but written in C#. So, I started to port them to WTL/C++ but during the port, I started wondering if I could find an easier way of translating the graphics parts, and after some research, I found a very good article from Alex Feinman entitled "Using GDI+ on Windows Mobile". The interesting part was the fact it was using Marshalling to call GDI+, so it meant that GDI+ could be used with native code. Then, after more research, I found a set of classes and a library from Ernest Laurentin that was a wrapper around GDI+ and that could be used in native code.
Background
GDI+ is a graphics library introduced in 2001 by Microsoft to make two-dimensional drawing easier. It runs on top of GDI32, and besides the changes in the programming model, it also adds new features such as gradient fills, anti-aliasing, more extensive image handling, etc. There are two main components of GDI+: a flat C API where the main implementation rests, and C++ wrappers that reside in the public headers associated with GDI+.
Unfortunately, on Windows Mobile, GDI+ is only partially implemented, and lots of functions (for instance, Font
and FontFamily
) return NotImplemented
.
Using the code
To be able to use GDI+, you need to initialize it first, as shown below:
ULONG_PTR _gdiplusToken;
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&_gdiplusToken, &gdiplusStartupInput, NULL);
...
int nRet = CMainFrame::AppRun(lpstrCmdLine, nCmdShow);
...
Gdiplus::GdiplusShutdown(_gdiplusToken);
Implementation of missing functions (Bitmap)
As I wrote above, GDI+ is split in two, a gdiplus.dll that exports some C functions used to handle memory and drawing, and some C++ classes declared inline and that calls the exported functions. Please note that the allocation/deallocation operator has been overloaded because memory management is done by the DLL.
So, if you write the following code:
Gdiplus:: Pen pen = new Pen(Color::Black, 15);
the following functions are called:
DllExports::GdipAlloc(in_size);
- corresponds to the new
operator
DllExports::GdipCreatePen1
- corresponds to Pen(IN const Color& color, IN REAL width = 1.0f)
On Windows Mobile, some functions were not implemented, and in particular I focused on the Bitmap
class.
If you look at MSDN, you will see that a Gdiplus::Bitmap
can be created from a file, resource, stream, or HBITMAP
, but from my experiments on a Windows Mobile 6, only the following functions are implemented:
DllExports::GdipCreateBitmapFromStreamICM(...)
DllExports::GdipCreateBitmapFromScan0(..)
DllExports::GdipCreateBitmapFromGraphics(...)
DllExports::GdipCreateBitmapFromGdiDib(...)
DllExports::GdipCreateBitmapFromHBITMAP(hbm, hpal, &bitmap)
So, I have implemented the missing functions to be able to easily load bitmaps from files or resources, and to save them.
Implementation of bitmap loading relies on GdipCreateBitmapFromStreamICM
, and I have developed two classes used to stream files (CStreamOnFile
) and resources (CStreamOnResource
). I have added to the base Image class, two pointers on these objects.
class Image : public GdiplusBase
{
...
#ifdef _WIN32_WCE
CStreamOnFile* pFileStream;
CStreamOnResource* pResStream;
#endif
...
};
and in the bitmap implementation:
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) {
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);
}
Unfortunately, on Windows Mobile, EnumResourceTypes
is not implemented, so I chose to handle only the following resource types:
How to use it
So now, you should be able to easily load and save images, as shown below:
#include "gdiplushelper.h"
HINSTANCE hResInstance = ModuleHelper::GetResourceInstance();
bmpRes = Bitmap::FromResource(hResInstance, MAKEINTRESOURCE(IDR_JPEG2));
bmpFile = Bitmap::FromFile(_T("\\My Documents\\My Pictures\\Spring.jpg"));
CLSID encoderClassId;
if (GetEncoderClsid(m_pImgFactory, L"image/png", &encoderClassId) == TRUE)
GdiplusSaveBitmap(m_pImgFactory, &*bmp,
_T("testsave.png"), &encoderClassId);
Conclusion
GDI+ is not officially supported on Windows Mobile, and I wouldn't recommend using it for big applications. However, if you need to manipulate some bitmaps, this wrapper could help you. Please note that I haven't tested indexed bitmaps, and you might have some issues if you are using bitmaps with palettes.
History
- 21 April, 2009: Article submitted.