[GDIPLUS]
[reactos.git] / reactos / dll / win32 / gdiplus / image.c
index 3742b87..d72d4cf 100644 (file)
@@ -94,6 +94,24 @@ GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
     return NotImplemented;
 }
 
+static inline void getpixel_1bppIndexed(BYTE *index, const BYTE *row, UINT x)
+{
+    *index = (row[x/8]>>(7-x%8)) & 1;
+}
+
+static inline void getpixel_4bppIndexed(BYTE *index, const BYTE *row, UINT x)
+{
+    if (x & 1)
+        *index = row[x/2]&0xf;
+    else
+        *index = row[x/2]>>4;
+}
+
+static inline void getpixel_8bppIndexed(BYTE *index, const BYTE *row, UINT x)
+{
+    *index = row[x];
+}
+
 static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
     const BYTE *row, UINT x)
 {
@@ -211,6 +229,7 @@ GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
     ARGB *color)
 {
     BYTE r, g, b, a;
+    BYTE index;
     BYTE *row;
     TRACE("%p %d %d %p\n", bitmap, x, y, color);
 
@@ -222,6 +241,15 @@ GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
 
     switch (bitmap->format)
     {
+        case PixelFormat1bppIndexed:
+            getpixel_1bppIndexed(&index,row,x);
+            break;
+        case PixelFormat4bppIndexed:
+            getpixel_4bppIndexed(&index,row,x);
+            break;
+        case PixelFormat8bppIndexed:
+            getpixel_8bppIndexed(&index,row,x);
+            break;
         case PixelFormat16bppGrayScale:
             getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
             break;
@@ -257,10 +285,13 @@ GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
             break;
         default:
             FIXME("not implemented for format 0x%x\n", bitmap->format);
-    return NotImplemented;
-}
+            return NotImplemented;
+    }
 
-    *color = a<<24|r<<16|g<<8|b;
+    if (bitmap->format & PixelFormatIndexed)
+        *color = bitmap->image.palette_entries[index];
+    else
+        *color = a<<24|r<<16|g<<8|b;
 
     return Ok;
 }
@@ -405,12 +436,418 @@ GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
             break;
         default:
             FIXME("not implemented for format 0x%x\n", bitmap->format);
-    return NotImplemented;
-}
+            return NotImplemented;
+    }
 
     return Ok;
 }
 
+GpStatus convert_pixels(UINT width, UINT height,
+    INT dst_stride, BYTE *dst_bits, PixelFormat dst_format,
+    INT src_stride, const BYTE *src_bits, PixelFormat src_format, ARGB *src_palette)
+{
+    UINT x, y;
+
+    if (src_format == dst_format ||
+        (dst_format == PixelFormat32bppRGB && PIXELFORMATBPP(src_format) == 32))
+    {
+        UINT widthbytes = PIXELFORMATBPP(src_format) * width / 8;
+        for (y=0; y<height; y++)
+            memcpy(dst_bits+dst_stride*y, src_bits+src_stride*y, widthbytes);
+        return Ok;
+    }
+
+#define convert_indexed_to_rgb(getpixel_function, setpixel_function) do { \
+    for (x=0; x<width; x++) \
+        for (y=0; y<height; y++) { \
+            BYTE index; \
+            BYTE *color; \
+            getpixel_function(&index, src_bits+src_stride*y, x); \
+            color = (BYTE*)(&src_palette[index]); \
+            setpixel_function(color[2], color[1], color[0], color[3], dst_bits+dst_stride*y, x); \
+        } \
+    return Ok; \
+} while (0);
+
+#define convert_rgb_to_rgb(getpixel_function, setpixel_function) do { \
+    for (x=0; x<width; x++) \
+        for (y=0; y<height; y++) { \
+            BYTE r, g, b, a; \
+            getpixel_function(&r, &g, &b, &a, src_bits+src_stride*y, x); \
+            setpixel_function(r, g, b, a, dst_bits+dst_stride*y, x); \
+        } \
+    return Ok; \
+} while (0);
+
+    switch (src_format)
+    {
+    case PixelFormat1bppIndexed:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_indexed_to_rgb(getpixel_1bppIndexed, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat4bppIndexed:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_indexed_to_rgb(getpixel_4bppIndexed, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat8bppIndexed:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_indexed_to_rgb(getpixel_8bppIndexed, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat16bppGrayScale:
+        switch (dst_format)
+        {
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppGrayScale, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat16bppRGB555:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB555, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat16bppRGB565:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppRGB555);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppRGB565, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat16bppARGB1555:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_16bppRGB565);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_16bppARGB1555, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat24bppRGB:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_16bppARGB1555);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_24bppRGB, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat32bppRGB:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_24bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_32bppRGB, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat32bppARGB:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_24bppRGB);
+        case PixelFormat32bppPARGB:
+            convert_32bppARGB_to_32bppPARGB(width, height, dst_bits, dst_stride, src_bits, src_stride);
+            return Ok;
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_32bppARGB, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat32bppPARGB:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_32bppARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_32bppPARGB, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat48bppRGB:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_32bppPARGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_48bppRGB, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat64bppARGB:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_64bppARGB, setpixel_48bppRGB);
+        default:
+            break;
+        }
+        break;
+    case PixelFormat64bppPARGB:
+        switch (dst_format)
+        {
+        case PixelFormat16bppGrayScale:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppGrayScale);
+        case PixelFormat16bppRGB555:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB555);
+        case PixelFormat16bppRGB565:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppRGB565);
+        case PixelFormat16bppARGB1555:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_16bppARGB1555);
+        case PixelFormat24bppRGB:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_24bppRGB);
+        case PixelFormat32bppRGB:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppRGB);
+        case PixelFormat32bppARGB:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppARGB);
+        case PixelFormat32bppPARGB:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_32bppPARGB);
+        case PixelFormat48bppRGB:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_48bppRGB);
+        case PixelFormat64bppARGB:
+            convert_rgb_to_rgb(getpixel_64bppPARGB, setpixel_64bppARGB);
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+
+#undef convert_indexed_to_rgb
+#undef convert_rgb_to_rgb
+
+    return NotImplemented;
+}
+
 /* This function returns a pointer to an array of pixels that represents the
  * bitmap. The *entire* bitmap is locked according to the lock mode specified by
  * flags.  It is correct behavior that a user who calls this function with write
@@ -420,16 +857,13 @@ GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
 GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
     UINT flags, PixelFormat format, BitmapData* lockeddata)
 {
-    BOOL bm_is_selected;
     INT stride, bitspp = PIXELFORMATBPP(format);
-    HDC hdc;
-    HBITMAP hbm, old = NULL;
-    BITMAPINFO *pbmi;
     BYTE *buff = NULL;
     UINT abs_height;
     GpRect act_rect; /* actual rect to be used */
+    GpStatus stat;
 
-    TRACE("%p %p %d %d %p\n", bitmap, rect, flags, format, lockeddata);
+    TRACE("%p %p %d 0x%x %p\n", bitmap, rect, flags, format, lockeddata);
 
     if(!lockeddata || !bitmap)
         return InvalidParameter;
@@ -448,10 +882,17 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
     }
 
     if(flags & ImageLockModeUserInputBuf)
+    {
+        static int fixme=0;
+        if (!fixme++) FIXME("ImageLockModeUserInputBuf not implemented\n");
         return NotImplemented;
+    }
 
     if(bitmap->lockmode)
+    {
+        WARN("bitmap is already locked and cannot be locked again\n");
         return WrongState;
+    }
 
     if (bitmap->bits && bitmap->format == format)
     {
@@ -470,83 +911,77 @@ GpStatus WINGDIPAPI GdipBitmapLockBits(GpBitmap* bitmap, GDIPCONST GpRect* rect,
         return Ok;
     }
 
-    hbm = bitmap->hbitmap;
-    hdc = bitmap->hdc;
-    bm_is_selected = (hdc != 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, hbm);
+    /* Make sure we can convert to the requested format. */
+    stat = convert_pixels(0, 0, 0, NULL, format, 0, NULL, bitmap->format, NULL);
+    if (stat == NotImplemented)
+    {
+        FIXME("cannot read bitmap from %x to %x\n", bitmap->format, format);
+        return NotImplemented;
     }
 
-    /* fill out bmi */
-    GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+    /* If we're opening for writing, make sure we'll be able to write back in
+     * the original format. */
+    if (flags & ImageLockModeWrite)
+    {
+        stat = convert_pixels(0, 0, 0, NULL, bitmap->format, 0, NULL, format, NULL);
+        if (stat == NotImplemented)
+        {
+            FIXME("cannot write bitmap from %x to %x\n", format, bitmap->format);
+            return NotImplemented;
+        }
+    }
 
-    abs_height = abs(pbmi->bmiHeader.biHeight);
-    stride = pbmi->bmiHeader.biWidth * bitspp / 8;
+    abs_height = bitmap->height;
+    stride = (bitmap->width * bitspp + 7) / 8;
     stride = (stride + 3) & ~3;
 
     buff = GdipAlloc(stride * abs_height);
 
-    pbmi->bmiHeader.biBitCount = bitspp;
+    if (!buff) return OutOfMemory;
 
-    if(buff)
-        GetDIBits(hdc, hbm, 0, abs_height, buff, pbmi, DIB_RGB_COLORS);
-
-    if(!bm_is_selected){
-        SelectObject(hdc, old);
-        DeleteDC(hdc);
-    }
+    stat = convert_pixels(bitmap->width, bitmap->height,
+        stride, buff, format,
+        bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries);
 
-    if(!buff){
-        GdipFree(pbmi);
-        return OutOfMemory;
+    if (stat != Ok)
+    {
+        GdipFree(buff);
+        return stat;
     }
 
     lockeddata->Width  = act_rect.Width;
     lockeddata->Height = act_rect.Height;
     lockeddata->PixelFormat = format;
     lockeddata->Reserved = flags;
-
-    if(pbmi->bmiHeader.biHeight > 0){
-        lockeddata->Stride = -stride;
-        lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X +
-                             stride * (abs_height - 1 - act_rect.Y);
-    }
-    else{
-        lockeddata->Stride = stride;
-        lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
-    }
+    lockeddata->Stride = stride;
+    lockeddata->Scan0  = buff + (bitspp / 8) * act_rect.X + stride * act_rect.Y;
 
     bitmap->lockmode = flags;
     bitmap->numlocks++;
-
     bitmap->bitmapbits = buff;
 
-    GdipFree(pbmi);
     return Ok;
 }
 
 GpStatus WINGDIPAPI GdipBitmapSetResolution(GpBitmap* bitmap, REAL xdpi, REAL ydpi)
 {
-    FIXME("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
+    TRACE("(%p, %.2f, %.2f)\n", bitmap, xdpi, ydpi);
 
-    return NotImplemented;
+    if (!bitmap || xdpi == 0.0 || ydpi == 0.0)
+        return InvalidParameter;
+
+    bitmap->image.xres = xdpi;
+    bitmap->image.yres = ydpi;
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
     BitmapData* lockeddata)
 {
-    HDC hdc;
-    HBITMAP hbm, old = NULL;
-    BOOL bm_is_selected;
-    BITMAPINFO *pbmi;
+    GpStatus stat;
+
+    TRACE("(%p,%p)\n", bitmap, lockeddata);
 
     if(!bitmap || !lockeddata)
         return InvalidParameter;
@@ -570,54 +1005,97 @@ GpStatus WINGDIPAPI GdipBitmapUnlockBits(GpBitmap* bitmap,
     {
         /* we passed a direct reference; no need to do anything */
         bitmap->lockmode = 0;
+        bitmap->numlocks = 0;
         return Ok;
     }
 
-    hbm = bitmap->hbitmap;
-    hdc = bitmap->hdc;
-    bm_is_selected = (hdc != 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, hbm);
-    }
-
-    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);
+    stat = convert_pixels(bitmap->width, bitmap->height,
+        bitmap->stride, bitmap->bits, bitmap->format,
+        lockeddata->Stride, bitmap->bitmapbits, lockeddata->PixelFormat, NULL);
 
-    if(!bm_is_selected){
-        SelectObject(hdc, old);
-        DeleteDC(hdc);
+    if (stat != Ok)
+    {
+        ERR("failed to convert pixels; this should never happen\n");
     }
 
-    GdipFree(pbmi);
     GdipFree(bitmap->bitmapbits);
     bitmap->bitmapbits = NULL;
     bitmap->lockmode = 0;
+    bitmap->numlocks = 0;
 
-    return Ok;
+    return stat;
 }
 
 GpStatus WINGDIPAPI GdipCloneBitmapArea(REAL x, REAL y, REAL width, REAL height,
     PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
 {
-    FIXME("(%f,%f,%f,%f,%i,%p,%p): stub\n", x, y, width, height, format, srcBitmap, dstBitmap);
+    BitmapData lockeddata_src, lockeddata_dst;
+    int i;
+    UINT row_size;
+    Rect area;
+    GpStatus stat;
 
-    return NotImplemented;
+    TRACE("(%f,%f,%f,%f,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
+
+    if (!srcBitmap || !dstBitmap || srcBitmap->image.type != ImageTypeBitmap ||
+        x < 0 || y < 0 ||
+        x + width > srcBitmap->width || y + height > srcBitmap->height)
+    {
+        TRACE("<-- InvalidParameter\n");
+        return InvalidParameter;
+    }
+
+    if (format == PixelFormatDontCare)
+        format = srcBitmap->format;
+
+    area.X = roundr(x);
+    area.Y = roundr(y);
+    area.Width = roundr(width);
+    area.Height = roundr(height);
+
+    stat = GdipBitmapLockBits(srcBitmap, &area, ImageLockModeRead, format,
+        &lockeddata_src);
+    if (stat != Ok) return stat;
+
+    stat = GdipCreateBitmapFromScan0(lockeddata_src.Width, lockeddata_src.Height,
+        0, lockeddata_src.PixelFormat, NULL, dstBitmap);
+    if (stat == Ok)
+    {
+        stat = GdipBitmapLockBits(*dstBitmap, NULL, ImageLockModeWrite,
+            lockeddata_src.PixelFormat, &lockeddata_dst);
+
+        if (stat == Ok)
+        {
+            /* copy the image data */
+            row_size = (lockeddata_src.Width * PIXELFORMATBPP(lockeddata_src.PixelFormat) +7)/8;
+            for (i=0; i<lockeddata_src.Height; i++)
+                memcpy((BYTE*)lockeddata_dst.Scan0+lockeddata_dst.Stride*i,
+                       (BYTE*)lockeddata_src.Scan0+lockeddata_src.Stride*i,
+                       row_size);
+
+            GdipBitmapUnlockBits(*dstBitmap, &lockeddata_dst);
+        }
+
+        if (stat != Ok)
+            GdipDisposeImage((GpImage*)*dstBitmap);
+    }
+
+    GdipBitmapUnlockBits(srcBitmap, &lockeddata_src);
+
+    if (stat != Ok)
+    {
+        *dstBitmap = NULL;
+    }
+
+    return stat;
 }
 
 GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
     PixelFormat format, GpBitmap* srcBitmap, GpBitmap** dstBitmap)
 {
-    FIXME("(%i,%i,%i,%i,%i,%p,%p): stub\n", x, y, width, height, format, srcBitmap, dstBitmap);
+    TRACE("(%i,%i,%i,%i,0x%x,%p,%p)\n", x, y, width, height, format, srcBitmap, dstBitmap);
 
-    return NotImplemented;
+    return GdipCloneBitmapArea(x, y, width, height, format, srcBitmap, dstBitmap);
 }
 
 GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
@@ -690,12 +1168,14 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
                 GdipBitmapUnlockBits((GpBitmap*)*cloneImage, &lockeddata_dst);
             }
 
-            GdipBitmapUnlockBits(bitmap, &lockeddata_src);
+            if (stat != Ok)
+                GdipDisposeImage(*cloneImage);
         }
 
+        GdipBitmapUnlockBits(bitmap, &lockeddata_src);
+
         if (stat != Ok)
         {
-            GdipDisposeImage(*cloneImage);
             *cloneImage = NULL;
         }
         else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
@@ -879,6 +1359,9 @@ GpStatus WINGDIPAPI GdipConvertToEmfPlus(const GpGraphics* ref,
 {
     static int calls;
 
+    TRACE("(%p,%p,%p,%u,%s,%p)\n", ref, metafile, succ, emfType,
+        debugstr_w(description), out_metafile);
+
     if(!ref || !metafile || !out_metafile)
         return InvalidParameter;
 
@@ -1076,17 +1559,71 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
     return Ok;
 }
 
+static void generate_halftone_palette(ARGB *entries, UINT count)
+{
+    static const BYTE halftone_values[6]={0x00,0x33,0x66,0x99,0xcc,0xff};
+    UINT i;
+
+    for (i=0; i<8 && i<count; i++)
+    {
+        entries[i] = 0xff000000;
+        if (i&1) entries[i] |= 0x800000;
+        if (i&2) entries[i] |= 0x8000;
+        if (i&4) entries[i] |= 0x80;
+    }
+
+    if (8 < count)
+        entries[i] = 0xffc0c0c0;
+
+    for (i=9; i<16 && i<count; i++)
+    {
+        entries[i] = 0xff000000;
+        if (i&1) entries[i] |= 0xff0000;
+        if (i&2) entries[i] |= 0xff00;
+        if (i&4) entries[i] |= 0xff;
+    }
+
+    for (i=16; i<40 && i<count; i++)
+    {
+        entries[i] = 0;
+    }
+
+    for (i=40; i<256 && i<count; i++)
+    {
+        entries[i] = 0xff000000;
+        entries[i] |= halftone_values[(i-40)%6];
+        entries[i] |= halftone_values[((i-40)/6)%6] << 8;
+        entries[i] |= halftone_values[((i-40)/36)%6] << 16;
+    }
+}
+
+static GpStatus get_screen_resolution(REAL *xres, REAL *yres)
+{
+    HDC screendc = GetDC(0);
+
+    if (!screendc) return GenericError;
+
+    *xres = (REAL)GetDeviceCaps(screendc, LOGPIXELSX);
+    *yres = (REAL)GetDeviceCaps(screendc, LOGPIXELSY);
+
+    ReleaseDC(0, screendc);
+
+    return Ok;
+}
+
 GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     PixelFormat format, BYTE* scan0, GpBitmap** bitmap)
 {
-    BITMAPINFOHEADER bmih;
+    BITMAPINFO* pbmi;
     HBITMAP hbitmap;
     INT row_size, dib_stride;
     HDC hdc;
     BYTE *bits;
     int i;
+    REAL xres, yres;
+    GpStatus stat;
 
-    TRACE("%d %d %d %d %p %p\n", width, height, stride, format, scan0, bitmap);
+    TRACE("%d %d %d 0x%x %p %p\n", width, height, stride, format, scan0, bitmap);
 
     if (!bitmap) return InvalidParameter;
 
@@ -1098,32 +1635,42 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     if(scan0 && !stride)
         return InvalidParameter;
 
+    stat = get_screen_resolution(&xres, &yres);
+    if (stat != Ok) return stat;
+
     row_size = (width * PIXELFORMATBPP(format)+7) / 8;
     dib_stride = (row_size + 3) & ~3;
 
     if(stride == 0)
         stride = dib_stride;
 
-    bmih.biSize = sizeof(BITMAPINFOHEADER);
-    bmih.biWidth = width;
-    bmih.biHeight = -height;
-    bmih.biPlanes = 1;
+    pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+    if (!pbmi)
+        return OutOfMemory;
+
+    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+    pbmi->bmiHeader.biWidth = width;
+    pbmi->bmiHeader.biHeight = -height;
+    pbmi->bmiHeader.biPlanes = 1;
     /* FIXME: use the rest of the data from format */
-    bmih.biBitCount = PIXELFORMATBPP(format);
-    bmih.biCompression = BI_RGB;
-    bmih.biSizeImage = 0;
-    bmih.biXPelsPerMeter = 0;
-    bmih.biYPelsPerMeter = 0;
-    bmih.biClrUsed = 0;
-    bmih.biClrImportant = 0;
+    pbmi->bmiHeader.biBitCount = PIXELFORMATBPP(format);
+    pbmi->bmiHeader.biCompression = BI_RGB;
+    pbmi->bmiHeader.biSizeImage = 0;
+    pbmi->bmiHeader.biXPelsPerMeter = 0;
+    pbmi->bmiHeader.biYPelsPerMeter = 0;
+    pbmi->bmiHeader.biClrUsed = 0;
+    pbmi->bmiHeader.biClrImportant = 0;
 
     hdc = CreateCompatibleDC(NULL);
-    if (!hdc) return GenericError;
+    if (!hdc) {
+        GdipFree(pbmi);
+        return GenericError;
+    }
 
-    hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits,
-        NULL, 0);
+    hbitmap = CreateDIBSection(hdc, pbmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
 
     DeleteDC(hdc);
+    GdipFree(pbmi);
 
     if (!hbitmap) return GenericError;
 
@@ -1143,6 +1690,12 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->image.type = ImageTypeBitmap;
     memcpy(&(*bitmap)->image.format, &ImageFormatMemoryBMP, sizeof(GUID));
     (*bitmap)->image.flags = ImageFlagsNone;
+    (*bitmap)->image.palette_flags = 0;
+    (*bitmap)->image.palette_count = 0;
+    (*bitmap)->image.palette_size = 0;
+    (*bitmap)->image.palette_entries = NULL;
+    (*bitmap)->image.xres = xres;
+    (*bitmap)->image.yres = yres;
     (*bitmap)->width = width;
     (*bitmap)->height = height;
     (*bitmap)->format = format;
@@ -1152,6 +1705,38 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
     (*bitmap)->bits = bits;
     (*bitmap)->stride = dib_stride;
 
+    if (format == PixelFormat1bppIndexed ||
+        format == PixelFormat4bppIndexed ||
+        format == PixelFormat8bppIndexed)
+    {
+        (*bitmap)->image.palette_size = (*bitmap)->image.palette_count = 1 << PIXELFORMATBPP(format);
+        (*bitmap)->image.palette_entries = GdipAlloc(sizeof(ARGB) * ((*bitmap)->image.palette_size));
+
+        if (!(*bitmap)->image.palette_entries)
+        {
+            GdipDisposeImage(&(*bitmap)->image);
+            *bitmap = NULL;
+            return OutOfMemory;
+        }
+
+        if (format == PixelFormat1bppIndexed)
+        {
+            (*bitmap)->image.palette_flags = PaletteFlagsGrayScale;
+            (*bitmap)->image.palette_entries[0] = 0xff000000;
+            (*bitmap)->image.palette_entries[1] = 0xffffffff;
+        }
+        else
+        {
+            if (format == PixelFormat8bppIndexed)
+                (*bitmap)->image.palette_flags = PaletteFlagsHalftone;
+
+            generate_halftone_palette((*bitmap)->image.palette_entries,
+                (*bitmap)->image.palette_count);
+        }
+    }
+
+    TRACE("<-- %p\n", *bitmap);
+
     return Ok;
 }
 
@@ -1259,7 +1844,9 @@ GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
     {
         GdipFree(((GpBitmap*)image)->bitmapbits);
         DeleteDC(((GpBitmap*)image)->hdc);
+        DeleteObject(((GpBitmap*)image)->hbitmap);
     }
+    GdipFree(image->palette_entries);
     GdipFree(image);
 
     return Ok;
@@ -1267,9 +1854,28 @@ GpStatus WINGDIPAPI GdipDisposeImage(GpImage *image)
 
 GpStatus WINGDIPAPI GdipFindFirstImageItem(GpImage *image, ImageItemData* item)
 {
+    static int calls;
+
+    TRACE("(%p,%p)\n", image, item);
+
     if(!image || !item)
         return InvalidParameter;
 
+    if (!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
+GpStatus WINGDIPAPI GdipGetImageItemData(GpImage *image, ImageItemData *item)
+{
+    static int calls;
+
+    TRACE("(%p,%p)\n", image, item);
+
+    if (!(calls++))
+        FIXME("not implemented\n");
+
     return NotImplemented;
 }
 
@@ -1389,25 +1995,31 @@ GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
 
 GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
 {
-    static int calls;
-
     if(!image || !res)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    *res = image->xres;
 
-    return NotImplemented;
+    TRACE("(%p) <-- %0.2f\n", image, *res);
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetImagePaletteSize(GpImage *image, INT *size)
 {
-    FIXME("%p %p\n", image, size);
+    TRACE("%p %p\n", image, size);
 
     if(!image || !size)
         return InvalidParameter;
 
-    return NotImplemented;
+    if (image->palette_count == 0)
+        *size = sizeof(ColorPalette);
+    else
+        *size = sizeof(UINT)*2 + sizeof(ARGB)*image->palette_count;
+
+    TRACE("<-- %u\n", *size);
+
+    return Ok;
 }
 
 /* FIXME: test this function for non-bitmap types */
@@ -1450,15 +2062,14 @@ GpStatus WINGDIPAPI GdipGetImageType(GpImage *image, ImageType *type)
 
 GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
 {
-    static int calls;
-
     if(!image || !res)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    *res = image->yres;
 
-    return NotImplemented;
+    TRACE("(%p) <-- %0.2f\n", image, *res);
+
+    return Ok;
 }
 
 GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
@@ -1562,17 +2173,34 @@ GpStatus WINGDIPAPI GdipGetPropertySize(GpImage *image, UINT* size, UINT* num)
 {
     static int calls;
 
+    TRACE("(%p,%p,%p)\n", image, size, num);
+
     if(!(calls++))
         FIXME("not implemented\n");
 
     return InvalidParameter;
 }
 
+struct image_format_dimension
+{
+    const GUID *format;
+    const GUID *dimension;
+};
+
+struct image_format_dimension image_format_dimensions[] =
+{
+    {&ImageFormatGIF, &FrameDimensionTime},
+    {&ImageFormatIcon, &FrameDimensionResolution},
+    {NULL}
+};
+
 GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
     GDIPCONST GUID* dimensionID, UINT* count)
 {
     static int calls;
 
+    TRACE("(%p,%s,%p)\n", image, debugstr_guid(dimensionID), count);
+
     if(!image || !dimensionID || !count)
         return InvalidParameter;
 
@@ -1585,26 +2213,40 @@ GpStatus WINGDIPAPI GdipImageGetFrameCount(GpImage *image,
 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsCount(GpImage *image,
     UINT* count)
 {
+    /* Native gdiplus 1.1 does not yet support multiple frame dimensions. */
+
     if(!image || !count)
         return InvalidParameter;
 
     *count = 1;
 
-    FIXME("stub\n");
-
     return Ok;
 }
 
 GpStatus WINGDIPAPI GdipImageGetFrameDimensionsList(GpImage* image,
     GUID* dimensionIDs, UINT count)
 {
-    static int calls;
+    int i;
+    const GUID *result=NULL;
+
+    TRACE("(%p,%p,%u)\n", image, dimensionIDs, count);
 
-    if(!image || !dimensionIDs)
+    if(!image || !dimensionIDs || count != 1)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    for (i=0; image_format_dimensions[i].format; i++)
+    {
+        if (IsEqualGUID(&image->format, image_format_dimensions[i].format))
+        {
+            result = image_format_dimensions[i].dimension;
+            break;
+        }
+    }
+
+    if (!result)
+        result = &FrameDimensionPage;
+
+    memcpy(dimensionIDs, result, sizeof(GUID));
 
     return Ok;
 }
@@ -1789,23 +2431,23 @@ static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **imag
     bitmap = (GpBitmap*)*image;
 
     if (status == Ok && bitmap->format == PixelFormat32bppARGB)
-{
+    {
         /* WIC supports bmp files with alpha, but gdiplus does not */
         bitmap->format = PixelFormat32bppRGB;
     }
 
     return status;
-    }
+}
 
 static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
 {
     return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
-    }
+}
 
 static GpStatus decode_image_png(IStream* stream, REFCLSID clsid, GpImage **image)
-    {
+{
     return decode_image_wic(stream, &CLSID_WICPngDecoder, image);
-    }
+}
 
 static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
 {
@@ -1833,6 +2475,12 @@ static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid
     (*image)->type = ImageTypeMetafile;
     (*image)->picture = pic;
     (*image)->flags   = ImageFlagsNone;
+    (*image)->palette_flags = 0;
+    (*image)->palette_count = 0;
+    (*image)->palette_size = 0;
+    (*image)->palette_entries = NULL;
+
+    TRACE("<-- %p\n", *image);
 
     return Ok;
 }
@@ -1925,7 +2573,7 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
     if (stat == Ok)
     {
         memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
-}
+    }
 
     return stat;
 }
@@ -1942,6 +2590,8 @@ GpStatus WINGDIPAPI GdipRemovePropertyItem(GpImage *image, PROPID propId)
 {
     static int calls;
 
+    TRACE("(%p,%u)\n", image, propId);
+
     if(!image)
         return InvalidParameter;
 
@@ -1955,6 +2605,8 @@ GpStatus WINGDIPAPI GdipSetPropertyItem(GpImage *image, GDIPCONST PropertyItem*
 {
     static int calls;
 
+    TRACE("(%p,%p)\n", image, item);
+
     if(!(calls++))
         FIXME("not implemented\n");
 
@@ -2168,15 +2820,22 @@ GpStatus WINGDIPAPI GdipSaveImageToStream(GpImage *image, IStream* stream,
  */
 GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, INT size)
 {
-    static int calls = 0;
+    TRACE("(%p,%p,%i)\n", image, palette, size);
 
-    if(!image)
+    if (!image || !palette)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (size < (sizeof(UINT)*2+sizeof(ARGB)*image->palette_count))
+    {
+        TRACE("<-- InsufficientBuffer\n");
+        return InsufficientBuffer;
+    }
 
-    return NotImplemented;
+    palette->Flags = image->palette_flags;
+    palette->Count = image->palette_count;
+    memcpy(palette->Entries, image->palette_entries, sizeof(ARGB)*image->palette_count);
+
+    return Ok;
 }
 
 /*****************************************************************************
@@ -2185,15 +2844,28 @@ GpStatus WINGDIPAPI GdipGetImagePalette(GpImage *image, ColorPalette *palette, I
 GpStatus WINGDIPAPI GdipSetImagePalette(GpImage *image,
     GDIPCONST ColorPalette *palette)
 {
-    static int calls;
+    TRACE("(%p,%p)\n", image, palette);
 
-    if(!image || !palette)
+    if(!image || !palette || palette->Count > 256)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    if (palette->Count > image->palette_size)
+    {
+        ARGB *new_palette;
 
-    return NotImplemented;
+        new_palette = GdipAlloc(sizeof(ARGB) * palette->Count);
+        if (!new_palette) return OutOfMemory;
+
+        GdipFree(image->palette_entries);
+        image->palette_entries = new_palette;
+        image->palette_size = palette->Count;
+    }
+
+    image->palette_flags = palette->Flags;
+    image->palette_count = palette->Count;
+    memcpy(image->palette_entries, palette->Entries, sizeof(ARGB)*palette->Count);
+
+    return Ok;
 }
 
 /*************************************************************************
@@ -2497,7 +3169,8 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi
     BITMAP bm;
     GpStatus retval;
     PixelFormat format;
-    BYTE* bits;
+    BitmapData lockeddata;
+    INT y;
 
     TRACE("%p %p %p\n", hbm, hpal, bitmap);
 
@@ -2538,16 +3211,75 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHBITMAP(HBITMAP hbm, HPALETTE hpal, GpBi
             return InvalidParameter;
     }
 
-    if (bm.bmBits)
-        bits = (BYTE*)bm.bmBits + (bm.bmHeight - 1) * bm.bmWidthBytes;
-    else
+    retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, 0,
+        format, NULL, bitmap);
+
+    if (retval == Ok)
     {
-        FIXME("can only get image data from DIB sections\n");
-        bits = NULL;
-    }
+        retval = GdipBitmapLockBits(*bitmap, NULL, ImageLockModeWrite,
+            format, &lockeddata);
+        if (retval == Ok)
+        {
+            if (bm.bmBits)
+            {
+                for (y=0; y<bm.bmHeight; y++)
+                {
+                    memcpy((BYTE*)lockeddata.Scan0+lockeddata.Stride*y,
+                           (BYTE*)bm.bmBits+bm.bmWidthBytes*(bm.bmHeight-1-y),
+                           bm.bmWidthBytes);
+                }
+            }
+            else
+            {
+                HDC hdc;
+                HBITMAP oldhbm;
+                BITMAPINFO *pbmi;
+                INT src_height, dst_stride;
+                BYTE *dst_bits;
+
+                hdc = CreateCompatibleDC(NULL);
+                oldhbm = SelectObject(hdc, hbm);
+
+                pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
+
+                if (pbmi)
+                {
+                    pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+                    pbmi->bmiHeader.biBitCount = 0;
+
+                    GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
+
+                    src_height = abs(pbmi->bmiHeader.biHeight);
+
+                    if (pbmi->bmiHeader.biHeight > 0)
+                    {
+                        dst_bits = (BYTE*)lockeddata.Scan0+lockeddata.Stride*(src_height-1);
+                        dst_stride = -lockeddata.Stride;
+                    }
+                    else
+                    {
+                        dst_bits = lockeddata.Scan0;
+                        dst_stride = lockeddata.Stride;
+                    }
 
-    retval = GdipCreateBitmapFromScan0(bm.bmWidth, bm.bmHeight, -bm.bmWidthBytes,
-        format, bits, bitmap);
+                    for (y=0; y<src_height; y++)
+                    {
+                        GetDIBits(hdc, hbm, y, 1, dst_bits+dst_stride*y,
+                            pbmi, DIB_RGB_COLORS);
+                    }
+
+                    GdipFree(pbmi);
+                }
+                else
+                    retval = OutOfMemory;
+
+                SelectObject(hdc, oldhbm);
+                DeleteDC(hdc);
+            }
+
+            GdipBitmapUnlockBits(*bitmap, &lockeddata);
+        }
+    }
 
     return retval;
 }
@@ -2568,6 +3300,8 @@ GpStatus WINGDIPAPI GdipSetEffectParameters(CGpEffect *effect,
 {
     static int calls;
 
+    TRACE("(%p,%p,%u)\n", effect, params, size);
+
     if(!(calls++))
         FIXME("not implemented\n");