- Sync gdiplus with Wine head
[reactos.git] / reactos / dll / win32 / gdiplus / image.c
index 72bf7f5..02f8f5a 100644 (file)
@@ -28,6 +28,7 @@
 #include "olectl.h"
 #include "ole2.h"
 
+#include "initguid.h"
 #include "gdiplus.h"
 #include "gdiplus_private.h"
 #include "wine/debug.h"
@@ -95,21 +96,30 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
 {
     BOOL bm_is_selected;
     INT stride, bitspp = PIXELFORMATBPP(format);
-    OLE_HANDLE hbm;
     HDC hdc;
-    HBITMAP old = NULL;
-    BITMAPINFO bmi;
+    HBITMAP hbm, old = NULL;
+    BITMAPINFO *pbmi;
     BYTE *buff = NULL;
     UINT abs_height;
+    GpRect act_rect; /* actual rect to be used */
 
     TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
 
-    if(!lockeddata || !bitmap || !rect)
+    if(!lockeddata || !bitmap)
         return InvalidParameter;
 
-    if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
-       (rect->Y + rect->Height > bitmap->height) || !flags)
-        return InvalidParameter;
+    if(rect){
+        if(rect->X < 0 || rect->Y < 0 || (rect->X + rect->Width > bitmap->width) ||
+          (rect->Y + rect->Height > bitmap->height) || !flags)
+            return InvalidParameter;
+
+        act_rect = *rect;
+    }
+    else{
+        act_rect.X = act_rect.Y = 0;
+        act_rect.Width  = bitmap->width;
+        act_rect.Height = bitmap->height;
+    }
 
     if(flags & ImageLockModeUserInputBuf)
         return NotImplemented;
@@ -117,53 +127,58 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
     if(bitmap->lockmode)
         return WrongState;
 
-    IPicture_get_Handle(bitmap->image.picture, &hbm);
+    IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
     IPicture_get_CurDC(bitmap->image.picture, &hdc);
     bm_is_selected = (hdc != 0);
 
-    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-    bmi.bmiHeader.biBitCount = 0;
+    pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+    if (!pbmi)
+        return OutOfMemory;
+    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    pbmi->bmiHeader.biBitCount = 0;
 
     if(!bm_is_selected){
         hdc = CreateCompatibleDC(0);
-        old = SelectObject(hdc, (HBITMAP)hbm);
+        old = SelectObject(hdc, hbm);
     }
 
     /* fill out bmi */
-    GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
+    GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
 
-    abs_height = abs(bmi.bmiHeader.biHeight);
-    stride = bmi.bmiHeader.biWidth * bitspp / 8;
+    abs_height = abs(pbmi->bmiHeader.biHeight);
+    stride = pbmi->bmiHeader.biWidth * bitspp / 8;
     stride = (stride + 3) & ~3;
 
     buff = GdipAlloc(stride * abs_height);
 
-    bmi.bmiHeader.biBitCount = bitspp;
+    pbmi->bmiHeader.biBitCount = bitspp;
 
     if(buff)
-        GetDIBits(hdc, (HBITMAP)hbm, 0, abs_height, buff, &bmi, DIB_RGB_COLORS);
+        GetDIBits(hdc, hbm, 0, abs_height, buff, pbmi, DIB_RGB_COLORS);
 
     if(!bm_is_selected){
         SelectObject(hdc, old);
         DeleteDC(hdc);
     }
 
-    if(!buff)
+    if(!buff){
+        GdipFree(pbmi);
         return OutOfMemory;
+    }
 
-    lockeddata->Width = rect->Width;
-    lockeddata->Height = rect->Height;
+    lockeddata->Width  = act_rect.Width;
+    lockeddata->Height = act_rect.Height;
     lockeddata->PixelFormat = format;
     lockeddata->Reserved = flags;
 
-    if(bmi.bmiHeader.biHeight > 0){
+    if(pbmi->bmiHeader.biHeight > 0){
         lockeddata->Stride = -stride;
-        lockeddata->Scan0 = buff + (bitspp / 8) * rect->X +
-                            stride * (abs_height - 1 - rect->Y);
+        lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X +
+                             stride * (abs_height - 1 - act_rect.Y);
     }
     else{
         lockeddata->Stride = stride;
-        lockeddata->Scan0 = buff + (bitspp / 8) * rect->X + stride * rect->Y;
+        lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
     }
 
     bitmap->lockmode = flags;
@@ -171,17 +186,17 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
 
     bitmap->bitmapbits = buff;
 
+    GdipFree(pbmi);
     return Ok;
 }
 
 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
     BitmapData* lockeddata)
 {
-    OLE_HANDLE hbm;
     HDC hdc;
-    HBITMAP old = NULL;
+    HBITMAP hbm, old = NULL;
     BOOL bm_is_selected;
-    BITMAPINFO bmi;
+    BITMAPINFO *pbmi;
 
     if(!bitmap || !lockeddata)
         return InvalidParameter;
@@ -201,28 +216,30 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
         return Ok;
     }
 
-    IPicture_get_Handle(bitmap->image.picture, &hbm);
+    IPicture_get_Handle(bitmap->image.picture, (OLE_HANDLE*)&hbm);
     IPicture_get_CurDC(bitmap->image.picture, &hdc);
     bm_is_selected = (hdc != 0);
 
-    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
-    bmi.bmiHeader.biBitCount = 0;
+    pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    pbmi->bmiHeader.biBitCount = 0;
 
     if(!bm_is_selected){
         hdc = CreateCompatibleDC(0);
-        old = SelectObject(hdc, (HBITMAP)hbm);
+        old = SelectObject(hdc, hbm);
     }
 
-    GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
-    bmi.bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
-    SetDIBits(hdc, (HBITMAP)hbm, 0, abs(bmi.bmiHeader.biHeight),
-              bitmap->bitmapbits, &bmi, DIB_RGB_COLORS);
+    GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+    pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(lockeddata->PixelFormat);
+    SetDIBits(hdc, hbm, 0, abs(pbmi->bmiHeader.biHeight),
+              bitmap->bitmapbits, pbmi, DIB_RGB_COLORS);
 
     if(!bm_is_selected){
         SelectObject(hdc, old);
         DeleteDC(hdc);
     }
 
+    GdipFree(pbmi);
     GdipFree(bitmap->bitmapbits);
     bitmap->bitmapbits = NULL;
     bitmap->lockmode = 0;
@@ -230,12 +247,52 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
+{
+    IStream* stream;
+    HRESULT hr;
+    INT size;
+    LARGE_INTEGER move;
+    GpStatus stat = GenericError;
+
+    TRACE("%p, %p\n", image, cloneImage);
+
+    if (!image || !cloneImage)
+        return InvalidParameter;
+
+    hr = CreateStreamOnHGlobal(0, TRUE, &stream);
+    if (FAILED(hr))
+        return GenericError;
+
+    hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
+    if(FAILED(hr))
+    {
+        WARN("Failed to save image on stream\n");
+        goto out;
+    }
+
+    /* Set seek pointer back to the beginning of the picture */
+    move.QuadPart = 0;
+    hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr))
+        goto out;
+
+    stat = GdipLoadImageFromStream(stream, cloneImage);
+    if (stat != Ok) WARN("Failed to load image from stream\n");
+
+out:
+    IStream_Release(stream);
+    return stat;
+}
+
 GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
     GpBitmap **bitmap)
 {
     GpStatus stat;
     IStream *stream;
 
+    TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
+
     if(!filename || !bitmap)
         return InvalidParameter;
 
@@ -251,13 +308,79 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromFile(GDIPCONST WCHAR* filename,
     return stat;
 }
 
+GpStatus WINGDIPAPI GdipCreateBitmapFromGdiDib(GDIPCONST BITMAPINFO* info,
+                                               VOID *bits, GpBitmap **bitmap)
+{
+    DWORD height, stride;
+    PixelFormat format;
+
+    FIXME("(%p, %p, %p) - partially implemented\n", info, bits, bitmap);
+
+    height = abs(info->bmiHeader.biHeight);
+    stride = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
+
+    if(info->bmiHeader.biHeight > 0) /* bottom-up */
+    {
+        bits = (BYTE*)bits + (height - 1) * stride;
+        stride = -stride;
+    }
+
+    switch(info->bmiHeader.biBitCount) {
+    case 1:
+        format = PixelFormat1bppIndexed;
+        break;
+    case 4:
+        format = PixelFormat4bppIndexed;
+        break;
+    case 8:
+        format = PixelFormat8bppIndexed;
+        break;
+    case 24:
+        format = PixelFormat24bppRGB;
+        break;
+    default:
+        FIXME("don't know how to handle %d bpp\n", info->bmiHeader.biBitCount);
+        *bitmap = NULL;
+        return InvalidParameter;
+    }
+
+    return GdipCreateBitmapFromScan0(info->bmiHeader.biWidth, height, stride, format,
+                                     bits, bitmap);
+
+}
+
 /* FIXME: no icm */
 GpStatus WINGDIPAPI GdipCreateBitmapFromFileICM(GDIPCONST WCHAR* filename,
     GpBitmap **bitmap)
 {
+    TRACE("(%s) %p\n", debugstr_w(filename), bitmap);
+
     return GdipCreateBitmapFromFile(filename, bitmap);
 }
 
+GpStatus WINGDIPAPI GdipCreateBitmapFromResource(HINSTANCE hInstance,
+    GDIPCONST WCHAR* lpBitmapName, GpBitmap** bitmap)
+{
+    HBITMAP hbm;
+    GpStatus stat = InvalidParameter;
+
+    TRACE("%p (%s) %p\n", hInstance, debugstr_w(lpBitmapName), bitmap);
+
+    if(!lpBitmapName || !bitmap)
+        return InvalidParameter;
+
+    /* load DIB */
+    hbm = LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0,
+                     LR_CREATEDIBSECTION);
+
+    if(hbm){
+        stat = GdipCreateBitmapFromHBITMAP(hbm, NULL, bitmap);
+        DeleteObject(hbm);
+    }
+
+    return stat;
+}
+
 GpStatus WINGDIPAPI GdipCreateHBITMAPFromBitmap(GpBitmap* bitmap,
     HBITMAP* hbmReturn, ARGB background)
 {
@@ -317,7 +440,9 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
 
     TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
 
-    if(!bitmap || width <= 0 || height <= 0 || (scan0 && (stride % 4))){
+    if (!bitmap) return InvalidParameter;
+
+    if(width <= 0 || height <= 0 || (scan0 && (stride % 4))){
         *bitmap = NULL;
         return InvalidParameter;
     }
@@ -397,6 +522,8 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
 {
     GpStatus stat;
 
+    TRACE("%p %p\n", stream, bitmap);
+
     stat = GdipLoadImageFromStream(stream, (GpImage**) bitmap);
 
     if(stat != Ok)
@@ -415,13 +542,64 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromStream(IStream* stream,
 GpStatus WINGDIPAPI GdipCreateBitmapFromStreamICM(IStream* stream,
     GpBitmap **bitmap)
 {
+    TRACE("%p %p\n", stream, bitmap);
+
     return GdipCreateBitmapFromStream(stream, bitmap);
 }
 
+GpStatus WINGDIPAPI GdipCreateCachedBitmap(GpBitmap *bitmap, GpGraphics *graphics,
+    GpCachedBitmap **cachedbmp)
+{
+    GpStatus stat;
+
+    TRACE("%p %p %p\n", bitmap, graphics, cachedbmp);
+
+    if(!bitmap || !graphics || !cachedbmp)
+        return InvalidParameter;
+
+    *cachedbmp = GdipAlloc(sizeof(GpCachedBitmap));
+    if(!*cachedbmp)
+        return OutOfMemory;
+
+    stat = GdipCloneImage(&(bitmap->image), &(*cachedbmp)->image);
+    if(stat != Ok){
+        GdipFree(*cachedbmp);
+        return stat;
+    }
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipDeleteCachedBitmap(GpCachedBitmap *cachedbmp)
+{
+    TRACE("%p\n", cachedbmp);
+
+    if(!cachedbmp)
+        return InvalidParameter;
+
+    GdipDisposeImage(cachedbmp->image);
+    GdipFree(cachedbmp);
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipDrawCachedBitmap(GpGraphics *graphics,
+    GpCachedBitmap *cachedbmp, INT x, INT y)
+{
+    TRACE("%p %p %d %d\n", graphics, cachedbmp, x, y);
+
+    if(!graphics || !cachedbmp)
+        return InvalidParameter;
+
+    return GdipDrawImage(graphics, cachedbmp->image, (REAL)x, (REAL)y);
+}
+
 GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
 {
     HDC hdc;
 
+    TRACE("%p\n", image);
+
     if(!image)
         return InvalidParameter;
 
@@ -446,6 +624,8 @@ GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
 GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
     GpUnit *srcUnit)
 {
+    TRACE("%p %p %p\n", image, srcRect, srcUnit);
+
     if(!image || !srcRect || !srcUnit)
         return InvalidParameter;
     if(image->type == ImageTypeMetafile){
@@ -474,6 +654,8 @@ GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
 GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
     REAL *height)
 {
+    TRACE("%p %p %p\n", image, width, height);
+
     if(!image || !height || !width)
         return InvalidParameter;
 
@@ -507,6 +689,8 @@ GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
 {
     HDC hdc;
 
+    TRACE("%p %p\n", image, graphics);
+
     if(!image || !graphics)
         return InvalidParameter;
 
@@ -527,6 +711,8 @@ GpStatus WINGDIPAPI GdipGetImageGraphicsContext(GpImage *image,
 
 GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
 {
+    TRACE("%p %p\n", image, height);
+
     if(!image || !height)
         return InvalidParameter;
 
@@ -561,9 +747,21 @@ GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
+{
+    FIXME("%p %p\n", image, size);
+
+    if(!image || !size)
+        return InvalidParameter;
+
+    return NotImplemented;
+}
+
 /* FIXME: test this function for non-bitmap types */
 GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
 {
+    TRACE("%p %p\n", image, format);
+
     if(!image || !format)
         return InvalidParameter;
 
@@ -583,13 +781,24 @@ GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
         return InvalidParameter;
 
     if(!(calls++))
-        FIXME("not implemented\n");
+        FIXME("stub\n");
 
-    return NotImplemented;
+    /* FIXME: should be detected from embedded picture or stored separately */
+    switch (image->type)
+    {
+    case ImageTypeBitmap:   *format = ImageFormatBMP; break;
+    case ImageTypeMetafile: *format = ImageFormatEMF; break;
+    default:
+        WARN("unknown type %u\n", image->type);
+        *format = ImageFormatUndefined;
+    }
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
 {
+    TRACE("%p %p\n", image, type);
+
     if(!image || !type)
         return InvalidParameter;
 
@@ -613,6 +822,8 @@ GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
 
 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
 {
+    TRACE("%p %p\n", image, width);
+
     if(!image || !width)
         return InvalidParameter;
 
@@ -648,6 +859,48 @@ GpStatus WINGDIPAPI GdipGetMetafileHeaderFromMetafile(GpMetafile * metafile,
     return Ok;
 }
 
+GpStatus WINGDIPAPI GdipGetAllPropertyItems(GpImage *image, UINT size,
+    UINT num, PropertyItem* items)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return InvalidParameter;
+}
+
+GpStatus WINGDIPAPI GdipGetPropertyCount(GpImage *image, UINT* num)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return InvalidParameter;
+}
+
+GpStatus WINGDIPAPI GdipGetPropertyIdList(GpImage *image, UINT num, PROPID* list)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return InvalidParameter;
+}
+
+GpStatus WINGDIPAPI GdipGetPropertyItem(GpImage *image, PROPID id, UINT size,
+    PropertyItem* buffer)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return InvalidParameter;
+}
+
 GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
     UINT* size)
 {
@@ -664,6 +917,16 @@ GpStatus WINGDIPAPI GdipGetPropertyItemSize(GpImage *image, PROPID pid,
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT* size, UINT* num)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return InvalidParameter;
+}
+
 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
     GDIPCONST GUID* dimensionID, UINT* count)
 {
@@ -678,6 +941,19 @@ GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
+    UINT* count)
+{
+    if(!image || !count)
+        return InvalidParameter;
+
+    *count = 1;
+
+    FIXME("stub\n");
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
     GUID* dimensionIDs, UINT count)
 {
@@ -712,6 +988,8 @@ GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
     GpStatus stat;
     IStream *stream;
 
+    TRACE("(%s) %p\n", debugstr_w(filename), image);
+
     if (!filename || !image)
         return InvalidParameter;
 
@@ -730,6 +1008,8 @@ GpStatus WINGDIPAPI GdipLoadImageFromFile(GDIPCONST WCHAR* filename,
 /* FIXME: no icm handling */
 GpStatus WINGDIPAPI GdipLoadImageFromFileICM(GDIPCONST WCHAR* filename,GpImage **image)
 {
+    TRACE("(%s) %p\n", debugstr_w(filename), image);
+
     return GdipLoadImageFromFile(filename, image);
 }
 
@@ -738,6 +1018,8 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
     IPicture *pic;
     short type;
 
+    TRACE("%p %p\n", stream, image);
+
     if(!stream || !image)
         return InvalidParameter;
 
@@ -750,38 +1032,72 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
     IPicture_get_Type(pic, &type);
 
     if(type == PICTYPE_BITMAP){
-        BITMAPINFO bmi;
+        BITMAPINFO *pbmi;
         BITMAPCOREHEADER* bmch;
-        OLE_HANDLE hbm;
+        HBITMAP hbm;
         HDC hdc;
 
+        pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+        if (!pbmi)
+            return OutOfMemory;
         *image = GdipAlloc(sizeof(GpBitmap));
-        if(!*image) return OutOfMemory;
+        if(!*image){
+            GdipFree(pbmi);
+            return OutOfMemory;
+        }
         (*image)->type = ImageTypeBitmap;
 
         (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
         (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
 
         /* get the pixel format */
-        IPicture_get_Handle(pic, &hbm);
+        IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm);
         IPicture_get_CurDC(pic, &hdc);
 
-        ZeroMemory(&bmi, sizeof(bmi));
-        bmch = (BITMAPCOREHEADER*) (&bmi.bmiHeader);
+        bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader);
         bmch->bcSize = sizeof(BITMAPCOREHEADER);
 
         if(!hdc){
             HBITMAP old;
             hdc = CreateCompatibleDC(0);
-            old = SelectObject(hdc, (HBITMAP)hbm);
-            GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
+            old = SelectObject(hdc, hbm);
+            GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
             SelectObject(hdc, old);
             DeleteDC(hdc);
         }
         else
-            GetDIBits(hdc, (HBITMAP)hbm, 0, 0, NULL, &bmi, DIB_RGB_COLORS);
+            GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+
+        switch(bmch->bcBitCount)
+        {
+            case 1:
+                (*((GpBitmap**) image))->format = PixelFormat1bppIndexed;
+                break;
+            case 4:
+                (*((GpBitmap**) image))->format = PixelFormat4bppIndexed;
+                break;
+            case 8:
+                (*((GpBitmap**) image))->format = PixelFormat8bppIndexed;
+                break;
+            case 16:
+                (*((GpBitmap**) image))->format = PixelFormat16bppRGB565;
+                break;
+            case 24:
+                (*((GpBitmap**) image))->format = PixelFormat24bppRGB;
+                break;
+            case 32:
+                (*((GpBitmap**) image))->format = PixelFormat32bppRGB;
+                break;
+            case 48:
+                (*((GpBitmap**) image))->format = PixelFormat48bppRGB;
+                break;
+            default:
+                FIXME("Bit depth %d is not fully supported yet\n", bmch->bcBitCount);
+                (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
+                break;
+        }
 
-        (*((GpBitmap**) image))->format = (bmch->bcBitCount << 8) | PixelFormatGDI;
+        GdipFree(pbmi);
     }
     else if(type == PICTYPE_METAFILE || type == PICTYPE_ENHMETAFILE){
         /* FIXME: missing initialization code */
@@ -804,6 +1120,8 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
 /* FIXME: no ICM */
 GpStatus WINGDIPAPI GdipLoadImageFromStreamICM(IStream* stream, GpImage **image)
 {
+    TRACE("%p %p\n", stream, image);
+
     return GdipLoadImageFromStream(stream, image);
 }
 
@@ -820,6 +1138,16 @@ GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem* item)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
 GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filename,
                                         GDIPCONST CLSID *clsidEncoder,
                                         GDIPCONST EncoderParameters *encoderParams)
@@ -827,6 +1155,8 @@ GpStatus WINGDIPAPI GdipSaveImageToFile(GpImage *image, GDIPCONST WCHAR* filenam
     GpStatus stat;
     IStream *stream;
 
+    TRACE("%p (%s) %p %p\n", image, debugstr_w(filename), clsidEncoder, encoderParams);
+
     if (!image || !filename|| !clsidEncoder)
         return InvalidParameter;
 
@@ -878,7 +1208,7 @@ static GpStatus encode_image_BMP(LPVOID bitmap_bits, LPBITMAPINFO bitmap_info,
 
     *output = GdipAlloc(*output_size);
 
-    bmp_file_hdr = (BITMAPFILEHEADER*) *output;
+    bmp_file_hdr = *output;
     bmp_file_hdr->bfType = BITMAP_FORMAT_BMP;
     bmp_file_hdr->bfSize = *output_size;
     bmp_file_hdr->bfOffBits =
@@ -910,6 +1240,9 @@ static encode_image_func *const encode_image_funcs[NUM_ENCODERS_SUPPORTED] = {
     encode_image_BMP,
 };
 
+/*****************************************************************************
+ * GdipSaveImageToStream [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
     GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
 {
@@ -932,6 +1265,8 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
     output = NULL;
     output_size = 0;
 
+    TRACE("%p %p %p %p\n", image, stream, clsid, params);
+
     if(!image || !stream)
         return InvalidParameter;
 
@@ -992,6 +1327,9 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
     return stat;
 }
 
+/*****************************************************************************
+ * GdipSetImagePalette [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
     GDIPCONST ColorPalette *palette)
 {
@@ -1038,8 +1376,42 @@ static const ImageCodecInfo codecs[NUM_ENCODERS_SUPPORTED] =
         },
     };
 
+/*****************************************************************************
+ * GdipGetImageDecodersSize [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetImageDecodersSize(UINT *numDecoders, UINT *size)
+{
+    FIXME("%p %p stub!\n", numDecoders, size);
+
+    if (!numDecoders || !size)
+        return InvalidParameter;
+
+    *numDecoders = 0;
+    *size = 0;
+
+    return Ok;
+}
+
+/*****************************************************************************
+ * GdipGetImageDecoders [GDIPLUS.@]
+ */
+GpStatus WINGDIPAPI GdipGetImageDecoders(UINT numDecoders, UINT size, ImageCodecInfo *decoders)
+{
+    FIXME("%u %u %p stub!\n", numDecoders, size, decoders);
+
+    if (!decoders)
+        return GenericError;
+
+    return NotImplemented;
+}
+
+/*****************************************************************************
+ * GdipGetImageEncodersSize [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
 {
+    TRACE("%p %p\n", numEncoders, size);
+
     if (!numEncoders || !size)
         return InvalidParameter;
 
@@ -1049,8 +1421,13 @@ GpStatus WINGDIPAPI GdipGetImageEncodersSize(UINT *numEncoders, UINT *size)
     return Ok;
 }
 
+/*****************************************************************************
+ * GdipGetImageEncoders [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodecInfo *encoders)
 {
+    TRACE("%u %u %p\n", numEncoders, size, encoders);
+
     if (!encoders ||
         (numEncoders != NUM_ENCODERS_SUPPORTED) ||
         (size != sizeof (codecs)))
@@ -1060,12 +1437,18 @@ GpStatus WINGDIPAPI GdipGetImageEncoders(UINT numEncoders, UINT size, ImageCodec
 
     return Ok;
 }
+
+/*****************************************************************************
+ * GdipCreateBitmapFromHBITMAP [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBitmap** bitmap)
 {
     BITMAP bm;
     GpStatus retval;
     PixelFormat format;
 
+    TRACE("%p %p %p\n", hbm, hpal, bitmap);
+
     if(!hbm || !bitmap)
         return InvalidParameter;
 
@@ -1092,6 +1475,9 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi
         case 24:
             format = PixelFormat24bppRGB;
             break;
+        case 32:
+            format = PixelFormat32bppRGB;
+            break;
         case 48:
             format = PixelFormat48bppRGB;
             break;
@@ -1106,6 +1492,9 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi
     return retval;
 }
 
+/*****************************************************************************
+ * GdipSetEffectParameters [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
     const VOID *params, const UINT size)
 {
@@ -1117,8 +1506,13 @@ GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
     return NotImplemented;
 }
 
+/*****************************************************************************
+ * GdipGetImageFlags [GDIPLUS.@]
+ */
 GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
 {
+    TRACE("%p %p\n", image, flags);
+
     if(!image || !flags)
         return InvalidParameter;
 
@@ -1126,3 +1520,52 @@ GpStatus WINGDIPAPI GdipGetImageFlags(GpImage *image, UINT *flags)
 
     return Ok;
 }
+
+GpStatus WINGDIPAPI GdipTestControl(GpTestControlEnum control, void *param)
+{
+    TRACE("(%d, %p)\n", control, param);
+
+    switch(control){
+        case TestControlForceBilinear:
+            if(param)
+                FIXME("TestControlForceBilinear not handled\n");
+            break;
+        case TestControlNoICM:
+            if(param)
+                FIXME("TestControlNoICM not handled\n");
+            break;
+        case TestControlGetBuildNumber:
+            *((DWORD*)param) = 3102;
+            break;
+    }
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipRecordMetafileFileName(GDIPCONST WCHAR* fileName,
+                            HDC hdc, EmfType type, GDIPCONST GpRectF *pFrameRect,
+                            MetafileFrameUnit frameUnit, GDIPCONST WCHAR *desc,
+                            GpMetafile **metafile)
+{
+    FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
+                                 frameUnit, debugstr_w(desc), metafile);
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipRecordMetafileFileNameI(GDIPCONST WCHAR* fileName, HDC hdc, EmfType type,
+                            GDIPCONST GpRect *pFrameRect, MetafileFrameUnit frameUnit,
+                            GDIPCONST WCHAR *desc, GpMetafile **metafile)
+{
+    FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName), hdc, type, pFrameRect,
+                                 frameUnit, debugstr_w(desc), metafile);
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipImageForceValidation(GpImage *image)
+{
+    FIXME("%p\n", image);
+
+    return Ok;
+}