Click here to Skip to main content
15,889,176 members
Articles / Mobile Apps / Windows Mobile

Unleash GDI+ power on Windows Mobile

Rate me:
Please Sign up or sign in to vote.
4.86/5 (7 votes)
21 Apr 2009CPOL3 min read 47.4K   834   31   10
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:

C++
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:

C#
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.

C++
class Image : public GdiplusBase
{
...
#ifdef _WIN32_WCE
    CStreamOnFile* pFileStream;
    CStreamOnResource*  pResStream;
#endif
...
};

and in the bitmap implementation:

C++
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:

C++
#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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Smartmobili
France France
I have founded a company specialized in mobile development and I am always trying to develop multi-platform things.
I am currently looking for new interesting job, so if you need someone please let me know.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Manoj Kumar Choubey17-Feb-12 0:16
professionalManoj Kumar Choubey17-Feb-12 0:16 
Questionare you sure about png? Pin
EvIl_DeViL15-Mar-10 5:58
EvIl_DeViL15-Mar-10 5:58 
AnswerRe: are you sure about png? Pin
EvIl_DeViL16-Mar-10 2:55
EvIl_DeViL16-Mar-10 2:55 
after many try i can say that "graphics.DrawImage" don't work really well with PNG because this function paint only the alpha channel as black (seems to skip RGB value and setting them 255, 255, 255).
where "0 > transparency < 255" DrawImage paint as semi-black.
I say DrawImage because the same code on a win32 app with the official ms-sdk draw a correct image using graphics.DrawImage. and if you (in windows mobile code) do
------------------------------------------------------------------------------------------------------
for (unsigned int j = 0; j < m_pBitmap->GetHeight(); j++)
{
for (unsigned int i = 0; i < m_pBitmap->GetWidth(); i++)
{
m_pBitmap->GetPixel(i, j, &pixelColor);
if (pixelColor.GetAlpha())
{
pen->SetColor(pixelColor);
graphics->DrawLine(&*pen, (int)i, (int)j, (int)i+1, (int)j+1);
}
}
}
------------------------------------------------------------------------------------------------------
this code paint very slowly your image correctly.
so how can I draw a transparent png in a reasonable amount time?
tnx
GeneralRe: are you sure about png? Pin
EvIl_DeViL17-Mar-10 5:26
EvIl_DeViL17-Mar-10 5:26 
QuestionIs there can set clip? Pin
bigpin2dl25-Nov-09 15:50
bigpin2dl25-Nov-09 15:50 
QuestionAbout Bezier? Pin
bigpin2dl18-Nov-09 14:58
bigpin2dl18-Nov-09 14:58 
AnswerRe: About Bezier? Pin
bigpin2dl18-Nov-09 16:30
bigpin2dl18-Nov-09 16:30 
QuestionLegal issues? Pin
Alain Rist22-Apr-09 7:42
Alain Rist22-Apr-09 7:42 
AnswerRe: Legal issues? Pin
Vince Ricci23-Apr-09 1:25
Vince Ricci23-Apr-09 1:25 
GeneralRe: Legal issues? Pin
Ernest Laurentin23-Apr-09 5:30
Ernest Laurentin23-Apr-09 5:30 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.