Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Unleash GDI+ power on Windows Mobile

0.00/5 (No votes)
21 Apr 2009 1  
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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here