65.9K
CodeProject is changing. Read more.
Home

Unleash GDI+ power on Windows Mobile

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (7 votes)

Apr 21, 2009

CPOL

3 min read

viewsIcon

48492

downloadIcon

835

How to use GDI+ on Windows Mobile.

GDIPlusCE

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;

// Initialize GDI+
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&_gdiplusToken, &gdiplusStartupInput, NULL);
...
int nRet = CMainFrame::AppRun(lpstrCmdLine, nCmdShow);
...

// Release GDI+
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) {
                // 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);
}

Unfortunately, on Windows Mobile, EnumResourceTypes is not implemented, so I chose to handle only the following resource types:

  • RT_BITMAP
  • PNG
  • JPEG
  • GIF

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();

// 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);

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.