[GDIPLUS_WINETEST] Sync with Wine Staging 1.7.47. CORE-9924
[reactos.git] / rostests / winetests / gdiplus / image.c
index 46e250d..d4042f9 100644 (file)
 #include <assert.h>
 #include <stdio.h>
 
-#include "initguid.h"
-#include "windows.h"
-#include "gdiplus.h"
-#include "wine/test.h"
+#include <initguid.h>
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+//#include "windows.h"
+#include <wine/test.h>
+#include <wingdi.h>
+#include <winnls.h>
+#include <ole2.h>
+#include <gdiplus.h>
 
 #define expect(expected, got) ok((got) == (expected), "Expected %d, got %d\n", (UINT)(expected), (UINT)(got))
 #define expectf(expected, got) ok(fabs((expected) - (got)) < 0.0001, "Expected %f, got %f\n", (expected), (got))
@@ -374,24 +381,48 @@ static void test_GdipImageGetFrameDimensionsCount(void)
 static void test_LoadingImages(void)
 {
     GpStatus stat;
+    GpBitmap *bm;
+    GpImage *img;
+    static const WCHAR nonexistentW[] = {'n','o','n','e','x','i','s','t','e','n','t',0};
 
     stat = GdipCreateBitmapFromFile(0, 0);
     expect(InvalidParameter, stat);
 
-    stat = GdipCreateBitmapFromFile(0, (GpBitmap**)0xdeadbeef);
+    bm = (GpBitmap *)0xdeadbeef;
+    stat = GdipCreateBitmapFromFile(0, &bm);
     expect(InvalidParameter, stat);
+    ok(bm == (GpBitmap *)0xdeadbeef, "returned %p\n", bm);
+
+    bm = (GpBitmap *)0xdeadbeef;
+    stat = GdipCreateBitmapFromFile(nonexistentW, &bm);
+    todo_wine expect(InvalidParameter, stat);
+    ok(!bm, "returned %p\n", bm);
 
     stat = GdipLoadImageFromFile(0, 0);
     expect(InvalidParameter, stat);
 
-    stat = GdipLoadImageFromFile(0, (GpImage**)0xdeadbeef);
+    img = (GpImage *)0xdeadbeef;
+    stat = GdipLoadImageFromFile(0, &img);
     expect(InvalidParameter, stat);
+    ok(img == (GpImage *)0xdeadbeef, "returned %p\n", img);
+
+    img = (GpImage *)0xdeadbeef;
+    stat = GdipLoadImageFromFile(nonexistentW, &img);
+    todo_wine expect(OutOfMemory, stat);
+    ok(!img, "returned %p\n", img);
 
     stat = GdipLoadImageFromFileICM(0, 0);
     expect(InvalidParameter, stat);
 
-    stat = GdipLoadImageFromFileICM(0, (GpImage**)0xdeadbeef);
+    img = (GpImage *)0xdeadbeef;
+    stat = GdipLoadImageFromFileICM(0, &img);
     expect(InvalidParameter, stat);
+    ok(img == (GpImage *)0xdeadbeef, "returned %p\n", img);
+
+    img = (GpImage *)0xdeadbeef;
+    stat = GdipLoadImageFromFileICM(nonexistentW, &img);
+    todo_wine expect(OutOfMemory, stat);
+    ok(!img, "returned %p\n", img);
 }
 
 static void test_SavingImages(void)
@@ -1311,6 +1342,12 @@ static const unsigned char gifimage[35] = {
 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
 0x01,0x00,0x3b
 };
+/* 1x1 pixel transparent gif */
+static const unsigned char transparentgif[] = {
+0x47,0x49,0x46,0x38,0x39,0x61,0x01,0x00,0x01,0x00,0xf0,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x21,0xf9,0x04,0x01,0x00,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0x00,
+0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,0x01,0x00,0x3b
+};
 /* 1x1 pixel bmp */
 static const unsigned char bmpimage[66] = {
 0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
@@ -1671,6 +1708,10 @@ static void test_createhbitmap(void)
     stat = GdipDisposeImage((GpImage*)bitmap);
     expect(Ok, stat);
 
+    /* make (1,0) have no alpha and (2,0) a different blue value. */
+    bits[7] = 0x00;
+    bits[8] = 0x40;
+
     /* create alpha Bitmap */
     stat = GdipCreateBitmapFromScan0(8, 20, 32, PixelFormat32bppARGB, bits, &bitmap);
     expect(Ok, stat);
@@ -1696,21 +1737,106 @@ static void test_createhbitmap(void)
         {
             DWORD val = *(DWORD*)bm.bmBits;
             ok(val == 0x682a2a2a, "got %x, expected 0x682a2a2a\n", val);
+            val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1);
+            ok(val == 0x0, "got %x, expected 0x682a2a2a\n", val);
         }
 
         hdc = CreateCompatibleDC(NULL);
 
         oldhbitmap = SelectObject(hdc, hbitmap);
         pixel = GetPixel(hdc, 5, 5);
+        expect(0x2a2a2a, pixel);
+        pixel = GetPixel(hdc, 1, 0);
+        expect(0x0, pixel);
+
         SelectObject(hdc, oldhbitmap);
 
         DeleteDC(hdc);
 
-        expect(0x2a2a2a, pixel);
 
         DeleteObject(hbitmap);
     }
 
+    /* create HBITMAP with bkgnd colour */
+    stat = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0xff00ff);
+    expect(Ok, stat);
+
+    if (stat == Ok)
+    {
+        ret = GetObjectA(hbitmap, sizeof(BITMAP), &bm);
+        expect(sizeof(BITMAP), ret);
+
+        expect(0, bm.bmType);
+        expect(8, bm.bmWidth);
+        expect(20, bm.bmHeight);
+        expect(32, bm.bmWidthBytes);
+        expect(1, bm.bmPlanes);
+        expect(32, bm.bmBitsPixel);
+        ok(bm.bmBits != NULL, "got DDB, expected DIB\n");
+
+        if (bm.bmBits)
+        {
+            DWORD val = *(DWORD*)bm.bmBits;
+            ok(val == 0x68c12ac1, "got %x, expected 0x682a2a2a\n", val);
+            val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1);
+            ok(val == 0xff00ff, "got %x, expected 0x682a2a2a\n", val);
+        }
+
+        hdc = CreateCompatibleDC(NULL);
+
+        oldhbitmap = SelectObject(hdc, hbitmap);
+        pixel = GetPixel(hdc, 5, 5);
+        expect(0xc12ac1, pixel);
+        pixel = GetPixel(hdc, 1, 0);
+        expect(0xff00ff, pixel);
+        pixel = GetPixel(hdc, 2, 0);
+        expect(0xb12ac1, pixel);
+
+        SelectObject(hdc, oldhbitmap);
+        DeleteDC(hdc);
+        DeleteObject(hbitmap);
+    }
+
+    /* create HBITMAP with bkgnd colour with alpha and show it behaves with no alpha. */
+    stat = GdipCreateHBITMAPFromBitmap(bitmap, &hbitmap, 0x80ff00ff);
+    expect(Ok, stat);
+
+    if (stat == Ok)
+    {
+        ret = GetObjectA(hbitmap, sizeof(BITMAP), &bm);
+        expect(sizeof(BITMAP), ret);
+
+        expect(0, bm.bmType);
+        expect(8, bm.bmWidth);
+        expect(20, bm.bmHeight);
+        expect(32, bm.bmWidthBytes);
+        expect(1, bm.bmPlanes);
+        expect(32, bm.bmBitsPixel);
+        ok(bm.bmBits != NULL, "got DDB, expected DIB\n");
+
+        if (bm.bmBits)
+        {
+            DWORD val = *(DWORD*)bm.bmBits;
+            ok(val == 0x68c12ac1, "got %x, expected 0x682a2a2a\n", val);
+            val = *((DWORD*)bm.bmBits + (bm.bmHeight-1) * bm.bmWidthBytes/4 + 1);
+            ok(val == 0xff00ff, "got %x, expected 0x682a2a2a\n", val);
+        }
+
+        hdc = CreateCompatibleDC(NULL);
+
+        oldhbitmap = SelectObject(hdc, hbitmap);
+        pixel = GetPixel(hdc, 5, 5);
+        expect(0xc12ac1, pixel);
+        pixel = GetPixel(hdc, 1, 0);
+        expect(0xff00ff, pixel);
+        pixel = GetPixel(hdc, 2, 0);
+        expect(0xb12ac1, pixel);
+
+        SelectObject(hdc, oldhbitmap);
+        DeleteDC(hdc);
+        DeleteObject(hbitmap);
+    }
+
     stat = GdipDisposeImage((GpImage*)bitmap);
     expect(Ok, stat);
 }
@@ -2211,6 +2337,17 @@ static void test_colormatrix(void)
     expect(Ok, stat);
     ok(color_match(0xeeff40cc, color, 3), "expected 0xeeff40cc, got 0x%08x\n", color);
 
+    stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
+    expect(Ok, stat);
+
+    stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
+        UnitPixel, imageattr, NULL, NULL);
+    expect(Ok, stat);
+
+    stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
+    expect(Ok, stat);
+    ok(color_match(0xff40ccee, color, 1), "Expected ff40ccee, got %.8x\n", color);
+
     GdipDeleteGraphics(graphics);
     GdipDisposeImage((GpImage*)bitmap1);
     GdipDisposeImage((GpImage*)bitmap2);
@@ -2273,6 +2410,17 @@ static void test_gamma(void)
     expect(Ok, stat);
     ok(color_match(0xff20ffff, color, 1), "Expected ff20ffff, got %.8x\n", color);
 
+    stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
+    expect(Ok, stat);
+
+    stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
+        UnitPixel, imageattr, NULL, NULL);
+    expect(Ok, stat);
+
+    stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
+    expect(Ok, stat);
+    ok(color_match(0xff80ffff, color, 1), "Expected ff80ffff, got %.8x\n", color);
+
     GdipDeleteGraphics(graphics);
     GdipDisposeImage((GpImage*)bitmap1);
     GdipDisposeImage((GpImage*)bitmap2);
@@ -2288,6 +2436,51 @@ static const unsigned char gifanimation[72] = {
 0x00,0x00,0x02,0x02,0x44,0x01,0x00,0x3b
 };
 
+/* Generated with ImageMagick:
+ * convert -transparent black -delay 100 -size 8x2 xc:black \
+ *     -dispose none -page +0+0 -size 2x2 xc:red \
+ *     -dispose background -page +2+0 -size 2x2 xc:blue \
+ *     -dispose previous -page +4+0 -size 2x2 xc:green \
+ *     -dispose undefined -page +6+0 -size 2x2 xc:gray \
+ *     test.gif
+ */
+static const unsigned char gifanimation2[] = {
+    0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x08, 0x00,
+    0x02, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x01, 0x64,
+    0x00, 0x00, 0x00, 0x21, 0xff, 0x0b, 0x4e, 0x45,
+    0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e,
+    0x30, 0x03, 0x01, 0x00, 0x00, 0x00, 0x2c, 0x00,
+    0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
+    0x02, 0x04, 0x84, 0x8f, 0x09, 0x05, 0x00, 0x21,
+    0xf9, 0x04, 0x04, 0x64, 0x00, 0x00, 0x00, 0x2c,
+    0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
+    0x81, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff,
+    0x00, 0x00, 0xff, 0x00, 0x00, 0x02, 0x03, 0x44,
+    0x34, 0x05, 0x00, 0x21, 0xf9, 0x04, 0x08, 0x64,
+    0x00, 0x00, 0x00, 0x2c, 0x02, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x02, 0x00, 0x81, 0x00, 0x00, 0xff,
+    0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00,
+    0xff, 0x02, 0x03, 0x44, 0x34, 0x05, 0x00, 0x21,
+    0xf9, 0x04, 0x0c, 0x64, 0x00, 0x00, 0x00, 0x2c,
+    0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00,
+    0x81, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00,
+    0x80, 0x00, 0x00, 0x80, 0x00, 0x02, 0x03, 0x44,
+    0x34, 0x05, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x64,
+    0x00, 0x00, 0x00, 0x2c, 0x06, 0x00, 0x00, 0x00,
+    0x02, 0x00, 0x02, 0x00, 0x80, 0x7e, 0x7e, 0x7e,
+    0x00, 0x00, 0x00, 0x02, 0x02, 0x84, 0x51, 0x00,
+    0x3b
+};
+
+static ARGB gifanimation2_pixels[5][4] = {
+    {0, 0, 0, 0},
+    {0xffff0000, 0, 0, 0},
+    {0xffff0000, 0xff0000ff, 0, 0},
+    {0xffff0000, 0, 0xff008000, 0},
+    {0xffff0000, 0, 0, 0xff7e7e7e}
+};
+
 static void test_multiframegif(void)
 {
     LPSTREAM stream;
@@ -2299,6 +2492,11 @@ static void test_multiframegif(void)
     ARGB color;
     UINT count;
     GUID dimension;
+    PixelFormat pixel_format;
+    INT palette_size, i, j;
+    char palette_buf[256];
+    ColorPalette *palette;
+    ARGB *palette_entries;
 
     /* Test frame functions with an animated GIF */
     hglob = GlobalAlloc (0, sizeof(gifanimation));
@@ -2317,6 +2515,16 @@ static void test_multiframegif(void)
         return;
     }
 
+    stat = GdipGetImagePixelFormat((GpImage*)bmp, &pixel_format);
+    expect(Ok, stat);
+    expect(PixelFormat32bppARGB, pixel_format);
+
+    stat = GdipGetImagePaletteSize((GpImage*)bmp, &palette_size);
+    expect(Ok, stat);
+    ok(palette_size == sizeof(ColorPalette) ||
+            broken(palette_size == sizeof(ColorPalette)+sizeof(ARGB[3])),
+            "palette_size = %d\n", palette_size);
+
     /* Bitmap starts at frame 0 */
     color = 0xdeadbeef;
     stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
@@ -2408,6 +2616,10 @@ static void test_multiframegif(void)
         return;
     }
 
+    stat = GdipGetImagePixelFormat((GpImage*)bmp, &pixel_format);
+    expect(Ok, stat);
+    expect(PixelFormat8bppIndexed, pixel_format);
+
     /* Check metadata */
     stat = GdipImageGetFrameDimensionsCount((GpImage*)bmp,&count);
     expect(Ok, stat);
@@ -2424,6 +2636,98 @@ static void test_multiframegif(void)
 
     GdipDisposeImage((GpImage*)bmp);
     IStream_Release(stream);
+
+    /* Test with a non-animated transparent gif */
+    hglob = GlobalAlloc (0, sizeof(transparentgif));
+    data = GlobalLock (hglob);
+    memcpy(data, transparentgif, sizeof(transparentgif));
+    GlobalUnlock(hglob);
+
+    hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
+    ok(hres == S_OK, "Failed to create a stream\n");
+
+    stat = GdipCreateBitmapFromStream(stream, &bmp);
+    IStream_Release(stream);
+    ok(stat == Ok, "Failed to create a Bitmap\n");
+
+    stat = GdipGetImagePixelFormat((GpImage*)bmp, &pixel_format);
+    expect(Ok, stat);
+    expect(PixelFormat8bppIndexed, pixel_format);
+
+    stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
+    expect(Ok, stat);
+    expect(0, color);
+
+    stat = GdipGetImagePaletteSize((GpImage*)bmp, &palette_size);
+    expect(Ok, stat);
+    ok(palette_size == sizeof(ColorPalette)+sizeof(ARGB),
+            "palette_size = %d\n", palette_size);
+
+    memset(palette_buf, 0xfe, sizeof(palette_buf));
+    palette = (ColorPalette*)palette_buf;
+    stat = GdipGetImagePalette((GpImage*)bmp, palette,
+            sizeof(ColorPalette)+sizeof(ARGB));
+    palette_entries = palette->Entries;
+    expect(Ok, stat);
+    expect(PaletteFlagsHasAlpha, palette->Flags);
+    expect(2, palette->Count);
+    expect(0, palette_entries[0]);
+    expect(0xff000000, palette_entries[1]);
+
+    count = 12345;
+    stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
+    expect(Ok, stat);
+    expect(1, count);
+
+    GdipDisposeImage((GpImage*)bmp);
+
+    /* Test frame dispose methods */
+    hglob = GlobalAlloc (0, sizeof(gifanimation2));
+    data = GlobalLock (hglob);
+    memcpy(data, gifanimation2, sizeof(gifanimation2));
+    GlobalUnlock(hglob);
+
+    hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
+    ok(hres == S_OK, "Failed to create a stream\n");
+
+    stat = GdipCreateBitmapFromStream(stream, &bmp);
+    ok(stat == Ok, "Failed to create a Bitmap\n");
+    IStream_Release(stream);
+
+    stat = GdipImageGetFrameDimensionsList((GpImage*)bmp, &dimension, 1);
+    expect(Ok, stat);
+    expect_guid(&FrameDimensionTime, &dimension, __LINE__, FALSE);
+
+    stat = GdipImageGetFrameCount((GpImage*)bmp, &dimension, &count);
+    expect(Ok, stat);
+    expect(5, count);
+
+    stat = GdipBitmapGetPixel(bmp, 0, 0, &color);
+    expect(Ok, stat);
+    expect(0, color);
+
+    stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, 3);
+    stat = GdipBitmapGetPixel(bmp, 2, 0, &color);
+    expect(Ok, stat);
+    ok(color==0 || broken(color==0xff0000ff), "color = %x\n", color);
+    if(color != 0) {
+        win_skip("broken animated gif support\n");
+        GdipDisposeImage((GpImage*)bmp);
+        return;
+    }
+
+    for(i=0; i<6; i++) {
+        stat = GdipImageSelectActiveFrame((GpImage*)bmp, &dimension, i%5);
+        expect(Ok, stat);
+
+        for(j=0; j<4; j++) {
+            stat = GdipBitmapGetPixel(bmp, j*2, 0, &color);
+            expect(Ok, stat);
+            ok(gifanimation2_pixels[i%5][j] == color, "at %d,%d got %x, expected %x\n", i, j, color, gifanimation2_pixels[i%5][j]);
+        }
+    }
+
+    GdipDisposeImage((GpImage*)bmp);
 }
 
 static void test_rotateflip(void)
@@ -2604,6 +2908,17 @@ static void test_remaptable(void)
     expect(Ok, stat);
     ok(color_match(0xffff00ff, color, 1), "Expected ffff00ff, got %.8x\n", color);
 
+    stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
+    expect(Ok, stat);
+
+    stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,1,1, 0,0,1,1,
+        UnitPixel, imageattr, NULL, NULL);
+    expect(Ok, stat);
+
+    stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
+    expect(Ok, stat);
+    ok(color_match(0xff00ff00, color, 1), "Expected ff00ff00, got %.8x\n", color);
+
     GdipDeleteGraphics(graphics);
     GdipDisposeImage((GpImage*)bitmap1);
     GdipDisposeImage((GpImage*)bitmap2);
@@ -2661,19 +2976,43 @@ static void test_colorkey(void)
 
     stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
     expect(Ok, stat);
-    ok(color_match(0x00000000, color, 1), "Expected ffff00ff, got %.8x\n", color);
+    ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color);
+
+    stat = GdipBitmapGetPixel(bitmap2, 0, 1, &color);
+    expect(Ok, stat);
+    ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color);
+
+    stat = GdipBitmapGetPixel(bitmap2, 1, 0, &color);
+    expect(Ok, stat);
+    ok(color_match(0x00000000, color, 1), "Expected 00000000, got %.8x\n", color);
+
+    stat = GdipBitmapGetPixel(bitmap2, 1, 1, &color);
+    expect(Ok, stat);
+    ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8x\n", color);
+
+    stat = GdipResetImageAttributes(imageattr, ColorAdjustTypeDefault);
+    expect(Ok, stat);
+
+    stat = GdipDrawImageRectRectI(graphics, (GpImage*)bitmap1, 0,0,2,2, 0,0,2,2,
+       UnitPixel, imageattr, NULL, NULL);
+    expect(Ok, stat);
+
+    stat = GdipBitmapGetPixel(bitmap2, 0, 0, &color);
+    expect(Ok, stat);
+    ok(color_match(0x20405060, color, 1), "Expected 20405060, got %.8x\n", color);
 
     stat = GdipBitmapGetPixel(bitmap2, 0, 1, &color);
     expect(Ok, stat);
-    ok(color_match(0x00000000, color, 1), "Expected ffff00ff, got %.8x\n", color);
+    ok(color_match(0x40506070, color, 1), "Expected 40506070, got %.8x\n", color);
 
     stat = GdipBitmapGetPixel(bitmap2, 1, 0, &color);
     expect(Ok, stat);
-    ok(color_match(0x00000000, color, 1), "Expected ffff00ff, got %.8x\n", color);
+    ok(color_match(0x60708090, color, 1), "Expected 60708090, got %.8x\n", color);
 
     stat = GdipBitmapGetPixel(bitmap2, 1, 1, &color);
     expect(Ok, stat);
-    ok(color_match(0xffffffff, color, 1), "Expected ffff00ff, got %.8x\n", color);
+    ok(color_match(0xffffffff, color, 1), "Expected ffffffff, got %.8x\n", color);
+
 
     GdipDeleteGraphics(graphics);
     GdipDisposeImage((GpImage*)bitmap1);
@@ -3105,8 +3444,11 @@ static void test_tiff_properties(void)
     PropertyItem *prop_item;
 
     image = load_image((const BYTE *)&TIFF_data, sizeof(TIFF_data));
-    ok(image != 0, "Failed to load TIFF image data\n");
-    if (!image) return;
+    if (!image)
+    {
+        win_skip("Failed to load TIFF image data. Might not be supported. Skipping.\n");
+        return;
+    }
 
     status = GdipImageGetFrameDimensionsCount(image, &dim_count);
     expect(Ok, status);
@@ -3153,8 +3495,10 @@ static void test_tiff_properties(void)
         ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id);
         prop_size -= sizeof(*prop_item);
         ok(prop_item->length == prop_size, "%u: expected length %u, got %u\n", i, prop_size, prop_item->length);
-        ok(td[i].length == prop_item->length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length);
-        ok(td[i].length == prop_size, "%u: expected length %u, got %u\n", i, td[i].length, prop_size);
+        ok(td[i].length == prop_item->length || broken(td[i].id == 0xf00f && td[i].length == prop_item->length+1) /* XP */,
+           "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length);
+        ok(td[i].length == prop_size || broken(td[i].id == 0xf00f && td[i].length == prop_size+1) /* XP */,
+           "%u: expected length %u, got %u\n", i, td[i].length, prop_size);
         if (td[i].length == prop_item->length)
         {
             int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0;
@@ -3163,10 +3507,10 @@ static void test_tiff_properties(void)
             {
                 UINT j;
                 BYTE *data = prop_item->value;
-                printf("id %#x:", prop_item->id);
+                trace("id %#x:", prop_item->id);
                 for (j = 0; j < prop_item->length; j++)
-                    printf(" %02x", data[j]);
-                printf("\n");
+                    trace(" %02x", data[j]);
+                trace("\n");
             }
         }
         HeapFree(GetProcessHeap(), 0, prop_item);
@@ -3269,10 +3613,10 @@ static void test_GdipGetAllPropertyItems(void)
             {
                 UINT j;
                 BYTE *data = prop_item->value;
-                printf("id %#x:", prop_item->id);
+                trace("id %#x:", prop_item->id);
                 for (j = 0; j < prop_item->length; j++)
-                    printf(" %02x", data[j]);
-                printf("\n");
+                    trace(" %02x", data[j]);
+                trace("\n");
             }
         }
         HeapFree(GetProcessHeap(), 0, prop_item);
@@ -3331,10 +3675,10 @@ static void test_GdipGetAllPropertyItems(void)
             {
                 UINT j;
                 BYTE *data = prop_item[i].value;
-                printf("id %#x:", prop_item[i].id);
+                trace("id %#x:", prop_item[i].id);
                 for (j = 0; j < prop_item[i].length; j++)
-                    printf(" %02x", data[j]);
-                printf("\n");
+                    trace(" %02x", data[j]);
+                trace("\n");
             }
         }
         item_data += prop_item[i].length;
@@ -3360,8 +3704,11 @@ static void test_tiff_palette(void)
 
     /* 1bpp TIFF without palette */
     image = load_image((const BYTE *)&TIFF_data, sizeof(TIFF_data));
-    ok(image != 0, "Failed to load TIFF image data\n");
-    if (!image) return;
+    if (!image)
+    {
+        win_skip("Failed to load TIFF image data. Might not be supported. Skipping.\n");
+        return;
+    }
 
     status = GdipGetImagePixelFormat(image, &format);
     expect(Ok, status);
@@ -3560,10 +3907,10 @@ static void test_bitmapbits(void)
                 if (!match)
                 {
                     BYTE *bits = data.Scan0;
-                    printf("%u: data mismatch for format %#x:", i, td[i].format);
+                    trace("%u: data mismatch for format %#x:", i, td[i].format);
                     for (j = 0; j < td[i].size; j++)
-                        printf(" %02x", bits[j]);
-                    printf("\n");
+                        trace(" %02x", bits[j]);
+                    trace("\n");
                 }
             }
             else
@@ -3591,10 +3938,10 @@ static void test_bitmapbits(void)
             {
                 UINT j;
                 BYTE *bits = data.Scan0;
-                printf("%u: data mismatch for format %#x:", i, td[i].format);
+                trace("%u: data mismatch for format %#x:", i, td[i].format);
                 for (j = 0; j < 48; j++)
-                    printf(" %02x", bits[j]);
-                printf("\n");
+                    trace(" %02x", bits[j]);
+                trace("\n");
             }
         }
 
@@ -3646,8 +3993,8 @@ static void test_DrawImage(void)
         UINT i, size = sizeof(white_2x2);
         BYTE *bits = white_2x2;
         for (i = 0; i < size; i++)
-            printf(" %02x", bits[i]);
-        printf("\n");
+            trace(" %02x", bits[i]);
+        trace("\n");
     }
 
     status = GdipDeleteGraphics(graphics);
@@ -3698,8 +4045,8 @@ static void test_GdipDrawImagePointRect(void)
         UINT i, size = sizeof(white_2x2);
         BYTE *bits = white_2x2;
         for (i = 0; i < size; i++)
-            printf(" %02x", bits[i]);
-        printf("\n");
+            trace(" %02x", bits[i]);
+        trace("\n");
     }
 
     status = GdipDeleteGraphics(graphics);
@@ -3746,7 +4093,7 @@ static void test_image_format(void)
         else
         {
             expect(Ok, status);
-            ret = GetObject(hbitmap, sizeof(bm), &bm);
+            ret = GetObjectW(hbitmap, sizeof(bm), &bm);
             expect(sizeof(bm), ret);
             expect(0, bm.bmType);
             expect(1, bm.bmWidth);
@@ -3763,8 +4110,9 @@ static void test_image_format(void)
             ok(status == OutOfMemory || broken(status == InvalidParameter) /* before win7 */,
                "expected OutOfMemory, got %d\n", status);
         else
-        {
             expect(Ok, status);
+        if (status == Ok)
+        {
             status = GdipGetImagePixelFormat(thumb, &format);
             expect(Ok, status);
             ok(format == PixelFormat32bppPARGB || broken(format != PixelFormat32bppPARGB) /* before win7 */,
@@ -3905,8 +4253,8 @@ static void test_DrawImage_scale(void)
             UINT i, size = sizeof(dst_8x1);
             const BYTE *bits = dst_8x1;
             for (i = 0; i < size; i++)
-                printf(" %02x", bits[i]);
-            printf("\n");
+                trace(" %02x", bits[i]);
+            trace("\n");
         }
     }
 
@@ -4031,10 +4379,10 @@ static void test_gif_properties(void)
             {
                 UINT j;
                 BYTE *data = prop_item->value;
-                printf("id %#x:", prop_item->id);
+                trace("id %#x:", prop_item->id);
                 for (j = 0; j < prop_item->length; j++)
-                    printf(" %02x", data[j]);
-                printf("\n");
+                    trace(" %02x", data[j]);
+                trace("\n");
             }
         }
         HeapFree(GetProcessHeap(), 0, prop_item);
@@ -4093,10 +4441,10 @@ static void test_gif_properties(void)
             {
                 UINT j;
                 BYTE *data = prop_item[i].value;
-                printf("id %#x:", prop_item[i].id);
+                trace("id %#x:", prop_item[i].id);
                 for (j = 0; j < prop_item[i].length; j++)
-                    printf(" %02x", data[j]);
-                printf("\n");
+                    trace(" %02x", data[j]);
+                trace("\n");
             }
         }
         item_data += prop_item[i].length;
@@ -4107,6 +4455,187 @@ static void test_gif_properties(void)
     GdipDisposeImage(image);
 }
 
+static void test_ARGB_conversion(void)
+{
+    BYTE argb[8] = { 0x11,0x22,0x33,0x80, 0xff,0xff,0xff,0 };
+    BYTE pargb[8] = { 0x09,0x11,0x1a,0x80, 0,0,0,0 };
+    BYTE rgb32_xp[8] = { 0x11,0x22,0x33,0xff, 0xff,0xff,0xff,0xff };
+    BYTE rgb24[6] = { 0x11,0x22,0x33, 0xff,0xff,0xff };
+    BYTE *bits;
+    GpBitmap *bitmap;
+    BitmapData data;
+    GpStatus status;
+    int match;
+
+    status = GdipCreateBitmapFromScan0(2, 1, 8, PixelFormat32bppARGB, argb, &bitmap);
+    expect(Ok, status);
+
+    status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppPARGB, &data);
+    expect(Ok, status);
+    ok(data.Width == 2, "expected 2, got %d\n", data.Width);
+    ok(data.Height == 1, "expected 1, got %d\n", data.Height);
+    ok(data.Stride == 8, "expected 8, got %d\n", data.Stride);
+    ok(data.PixelFormat == PixelFormat32bppPARGB, "expected PixelFormat32bppPARGB, got %d\n", data.PixelFormat);
+    match = !memcmp(data.Scan0, pargb, sizeof(pargb));
+    ok(match, "bits don't match\n");
+    if (!match)
+    {
+        bits = data.Scan0;
+        trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppPARGB,
+               bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
+    }
+    status = GdipBitmapUnlockBits(bitmap, &data);
+    expect(Ok, status);
+
+    status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat32bppRGB, &data);
+    expect(Ok, status);
+    ok(data.Width == 2, "expected 2, got %d\n", data.Width);
+    ok(data.Height == 1, "expected 1, got %d\n", data.Height);
+    ok(data.Stride == 8, "expected 8, got %d\n", data.Stride);
+    ok(data.PixelFormat == PixelFormat32bppRGB, "expected PixelFormat32bppRGB, got %d\n", data.PixelFormat);
+    match = !memcmp(data.Scan0, argb, sizeof(argb)) ||
+            !memcmp(data.Scan0, rgb32_xp, sizeof(rgb32_xp));
+    ok(match, "bits don't match\n");
+    if (!match)
+    {
+        bits = data.Scan0;
+        trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat32bppRGB,
+               bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
+    }
+    status = GdipBitmapUnlockBits(bitmap, &data);
+    expect(Ok, status);
+
+    status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB, &data);
+    expect(Ok, status);
+    ok(data.Width == 2, "expected 2, got %d\n", data.Width);
+    ok(data.Height == 1, "expected 1, got %d\n", data.Height);
+    ok(data.Stride == 8, "expected 8, got %d\n", data.Stride);
+    ok(data.PixelFormat == PixelFormat24bppRGB, "expected PixelFormat24bppRGB, got %d\n", data.PixelFormat);
+    match = !memcmp(data.Scan0, rgb24, sizeof(rgb24));
+    ok(match, "bits don't match\n");
+    if (!match)
+    {
+        bits = data.Scan0;
+        trace("format %#x, bits %02x,%02x,%02x,%02x %02x,%02x,%02x,%02x\n", PixelFormat24bppRGB,
+               bits[0], bits[1], bits[2], bits[3], bits[4], bits[5], bits[6], bits[7]);
+    }
+    status = GdipBitmapUnlockBits(bitmap, &data);
+    expect(Ok, status);
+
+    GdipDisposeImage((GpImage *)bitmap);
+}
+
+
+static void test_CloneBitmapArea(void)
+{
+    GpStatus status;
+    GpBitmap *bitmap, *copy;
+    BitmapData data, data2;
+
+    status = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat24bppRGB, NULL, &bitmap);
+    expect(Ok, status);
+
+    status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead | ImageLockModeWrite, PixelFormat24bppRGB, &data);
+    expect(Ok, status);
+
+    status = GdipBitmapLockBits(bitmap, NULL, ImageLockModeRead, PixelFormat24bppRGB, &data2);
+    expect(WrongState, status);
+
+    status = GdipCloneBitmapAreaI(0, 0, 1, 1, PixelFormat24bppRGB, bitmap, &copy);
+    expect(Ok, status);
+
+    status = GdipBitmapUnlockBits(bitmap, &data);
+    expect(Ok, status);
+
+    GdipDisposeImage((GpImage *)copy);
+    GdipDisposeImage((GpImage *)bitmap);
+}
+
+static BOOL get_encoder_clsid(LPCWSTR mime, GUID *format, CLSID *clsid)
+{
+    GpStatus status;
+    UINT n_codecs, info_size, i;
+    ImageCodecInfo *info;
+    BOOL ret = FALSE;
+
+    status = GdipGetImageEncodersSize(&n_codecs, &info_size);
+    expect(Ok, status);
+
+    info = GdipAlloc(info_size);
+
+    status = GdipGetImageEncoders(n_codecs, info_size, info);
+    expect(Ok, status);
+
+    for (i = 0; i < n_codecs; i++)
+    {
+        if (!lstrcmpW(info[i].MimeType, mime))
+        {
+            *format = info[i].FormatID;
+            *clsid = info[i].Clsid;
+            ret = TRUE;
+            break;
+        }
+    }
+
+    GdipFree(info);
+    return ret;
+}
+
+static void test_supported_encoders(void)
+{
+    static const WCHAR bmp_mimetype[] = {'i', 'm', 'a','g', 'e', '/', 'b', 'm', 'p', 0};
+    static const WCHAR jpeg_mimetype[] = {'i','m','a','g','e','/','j','p','e','g', 0};
+    static const WCHAR gif_mimetype[] = {'i','m','a','g','e','/','g','i','f', 0};
+    static const WCHAR tiff_mimetype[] = {'i','m','a','g','e','/','t','i','f','f', 0};
+    static const WCHAR png_mimetype[] = {'i','m','a','g','e','/','p','n','g', 0};
+    static const struct test_data
+    {
+        LPCWSTR mime;
+        const GUID *format;
+        BOOL todo;
+    } td[] =
+    {
+        { bmp_mimetype, &ImageFormatBMP, FALSE },
+        { jpeg_mimetype, &ImageFormatJPEG, FALSE },
+        { gif_mimetype, &ImageFormatGIF, TRUE },
+        { tiff_mimetype, &ImageFormatTIFF, FALSE },
+        { png_mimetype, &ImageFormatPNG, FALSE }
+    };
+    GUID format, clsid;
+    BOOL ret;
+    HRESULT hr;
+    GpStatus status;
+    GpBitmap *bm;
+    IStream *stream;
+    HGLOBAL hmem;
+    int i;
+
+    status = GdipCreateBitmapFromScan0(1, 1, 0, PixelFormat24bppRGB, NULL, &bm);
+    ok(status == Ok, "GdipCreateBitmapFromScan0 error %d\n", status);
+
+    for (i = 0; i < sizeof(td)/sizeof(td[0]); i++)
+    {
+        ret = get_encoder_clsid(td[i].mime, &format, &clsid);
+        ok(ret, "%s encoder is not in the list\n", wine_dbgstr_w(td[i].mime));
+        expect_guid(td[i].format, &format, __LINE__, FALSE);
+
+        hmem = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 16);
+
+        hr = CreateStreamOnHGlobal(hmem, TRUE, &stream);
+        ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
+
+        status = GdipSaveImageToStream((GpImage *)bm, stream, &clsid, NULL);
+        if (td[i].todo)
+            todo_wine ok(status == Ok, "GdipSaveImageToStream error %d\n", status);
+        else
+            ok(status == Ok, "GdipSaveImageToStream error %d\n", status);
+
+        IStream_Release(stream);
+    }
+
+    GdipDisposeImage((GpImage *)bm);
+}
+
 START_TEST(image)
 {
     struct GdiplusStartupInput gdiplusStartupInput;
@@ -4119,6 +4648,9 @@ START_TEST(image)
 
     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
 
+    test_supported_encoders();
+    test_CloneBitmapArea();
+    test_ARGB_conversion();
     test_DrawImage_scale();
     test_image_format();
     test_DrawImage();