[gdiplus]
authorGregor Schneider <grschneider@gmail.com>
Sat, 28 Nov 2009 15:26:02 +0000 (15:26 +0000)
committerGregor Schneider <grschneider@gmail.com>
Sat, 28 Nov 2009 15:26:02 +0000 (15:26 +0000)
- Update to current Wine sources
- Now routes BMP drawing to gdi instead of doing ole32 magic (bug #3412)

svn path=/trunk/; revision=44308

reactos/dll/win32/gdiplus/brush.c
reactos/dll/win32/gdiplus/gdiplus.c
reactos/dll/win32/gdiplus/gdiplus.spec
reactos/dll/win32/gdiplus/gdiplus_private.h
reactos/dll/win32/gdiplus/graphics.c
reactos/dll/win32/gdiplus/image.c

index 6220443..bfce7d8 100644 (file)
@@ -143,7 +143,7 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
         }
         case BrushTypeLinearGradient:{
             GpLineGradient *dest, *src;
-            INT count;
+            INT count, pcount;
 
             dest = GdipAlloc(sizeof(GpLineGradient));
             if(!dest)    return OutOfMemory;
@@ -157,11 +157,20 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
             count = dest->blendcount;
             dest->blendfac = GdipAlloc(count * sizeof(REAL));
             dest->blendpos = GdipAlloc(count * sizeof(REAL));
+            pcount = dest->pblendcount;
+            if (pcount)
+            {
+                dest->pblendcolor = GdipAlloc(pcount * sizeof(ARGB));
+                dest->pblendpos = GdipAlloc(pcount * sizeof(REAL));
+            }
 
-            if (!dest->blendfac || !dest->blendpos)
+            if (!dest->blendfac || !dest->blendpos ||
+                (pcount && (!dest->pblendcolor || !dest->pblendpos)))
             {
                 GdipFree(dest->blendfac);
                 GdipFree(dest->blendpos);
+                GdipFree(dest->pblendcolor);
+                GdipFree(dest->pblendpos);
                 DeleteObject(dest->brush.gdibrush);
                 GdipFree(dest);
                 return OutOfMemory;
@@ -170,6 +179,12 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
             memcpy(dest->blendfac, src->blendfac, count * sizeof(REAL));
             memcpy(dest->blendpos, src->blendpos, count * sizeof(REAL));
 
+            if (pcount)
+            {
+                memcpy(dest->pblendcolor, src->pblendcolor, pcount * sizeof(ARGB));
+                memcpy(dest->pblendpos, src->pblendpos, pcount * sizeof(REAL));
+            }
+
             *clone = &dest->brush;
             break;
         }
@@ -189,19 +204,38 @@ GpStatus WINGDIPAPI GdipCloneBrush(GpBrush *brush, GpBrush **clone)
     return Ok;
 }
 
-static LONG HatchStyleToHatch(HatchStyle hatchstyle)
-{
-    switch (hatchstyle)
-    {
-        case HatchStyleHorizontal:        return HS_HORIZONTAL;
-        case HatchStyleVertical:          return HS_VERTICAL;
-        case HatchStyleForwardDiagonal:   return HS_FDIAGONAL;
-        case HatchStyleBackwardDiagonal:  return HS_BDIAGONAL;
-        case HatchStyleCross:             return HS_CROSS;
-        case HatchStyleDiagonalCross:     return HS_DIAGCROSS;
-        default:                          return 0;
-    }
-}
+static const char HatchBrushes[][8] = {
+    { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00 }, /* HatchStyleHorizontal */
+    { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleVertical */
+    { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }, /* HatchStyleForwardDiagonal */
+    { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }, /* HatchStyleBackwardDiagonal */
+    { 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08 }, /* HatchStyleCross */
+    { 0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81 }, /* HatchStyleDiagonalCross */
+    { 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80 }, /* HatchStyle05Percent */
+    { 0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88 }, /* HatchStyle10Percent */
+    { 0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc }, /* HatchStyle20Percent */
+    { 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc }, /* HatchStyle25Percent */
+    { 0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc }, /* HatchStyle30Percent */
+    { 0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc }, /* HatchStyle40Percent */
+    { 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc }, /* HatchStyle50Percent */
+    { 0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee }, /* HatchStyle60Percent */
+    { 0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff }, /* HatchStyle70Percent */
+    { 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff }, /* HatchStyle75Percent */
+    { 0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff }, /* HatchStyle80Percent */
+    { 0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff }, /* HatchStyle90Percent */
+    { 0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88 }, /* HatchStyleLightDownwardDiagonal */
+    { 0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11 }, /* HatchStyleLightUpwardDiagonal */
+    { 0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc }, /* HatchStyleDarkDownwardDiagonal */
+    { 0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99 }, /* HatchStyleDarkUpwardDiagonal */
+    { 0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0 }, /* HatchStyleWideDownwardDiagonal */
+    { 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1 }, /* HatchStyleWideUpwardDiagonal */
+    { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88 }, /* HatchStyleLightVertical */
+    { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff }, /* HatchStyleLightHorizontal */
+    { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }, /* HatchStyleNarrowVertical */
+    { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff }, /* HatchStyleNarrowHorizontal */
+    { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, /* HatchStyleDarkVertical */
+    { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff }, /* HatchStyleDarkHorizontal */
+};
 
 /******************************************************************************
  * GdipCreateHatchBrush [GDIPLUS.@]
@@ -209,6 +243,7 @@ static LONG HatchStyleToHatch(HatchStyle hatchstyle)
 GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, ARGB backcol, GpHatch **brush)
 {
     COLORREF fgcol = ARGB2COLORREF(forecol);
+    GpStatus stat = Ok;
 
     TRACE("(%d, %d, %d, %p)\n", hatchstyle, forecol, backcol, brush);
 
@@ -217,37 +252,79 @@ GpStatus WINGDIPAPI GdipCreateHatchBrush(HatchStyle hatchstyle, ARGB forecol, AR
     *brush = GdipAlloc(sizeof(GpHatch));
     if (!*brush) return OutOfMemory;
 
-    switch (hatchstyle)
+    if (hatchstyle < sizeof(HatchBrushes) / sizeof(HatchBrushes[0]))
     {
-        case HatchStyleHorizontal:
-        case HatchStyleVertical:
-        case HatchStyleForwardDiagonal:
-        case HatchStyleBackwardDiagonal:
-        case HatchStyleCross:
-        case HatchStyleDiagonalCross:
-            /* Brushes that map to BS_HATCHED */
-            (*brush)->brush.lb.lbStyle = BS_HATCHED;
-            (*brush)->brush.lb.lbColor = fgcol;
-            (*brush)->brush.lb.lbHatch = HatchStyleToHatch(hatchstyle);
-            break;
+        HBITMAP hbmp;
+        HDC hdc;
+        BITMAPINFOHEADER bmih;
+        DWORD* bits;
+        int x, y;
 
-        default:
-            FIXME("Unimplemented hatch style %d\n", hatchstyle);
+        hdc = CreateCompatibleDC(0);
 
-            (*brush)->brush.lb.lbStyle = BS_SOLID;
-            (*brush)->brush.lb.lbColor = fgcol;
-            (*brush)->brush.lb.lbHatch = 0;
-            break;
+        if (hdc)
+        {
+            bmih.biSize = sizeof(bmih);
+            bmih.biWidth = 8;
+            bmih.biHeight = 8;
+            bmih.biPlanes = 1;
+            bmih.biBitCount = 32;
+            bmih.biCompression = BI_RGB;
+            bmih.biSizeImage = 0;
+
+            hbmp = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+
+            if (hbmp)
+            {
+                for (y=0; y<8; y++)
+                    for (x=0; x<8; x++)
+                        if ((HatchBrushes[hatchstyle][y] & (0x80 >> x)) != 0)
+                            bits[y*8+x] = forecol;
+                        else
+                            bits[y*8+x] = backcol;
+            }
+            else
+                stat = GenericError;
+
+            DeleteDC(hdc);
+        }
+        else
+            stat = GenericError;
+
+        if (stat == Ok)
+        {
+            (*brush)->brush.lb.lbStyle = BS_PATTERN;
+            (*brush)->brush.lb.lbColor = 0;
+            (*brush)->brush.lb.lbHatch = (ULONG_PTR)hbmp;
+            (*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb);
+
+            DeleteObject(hbmp);
+        }
     }
+    else
+    {
+        FIXME("Unimplemented hatch style %d\n", hatchstyle);
 
+        (*brush)->brush.lb.lbStyle = BS_SOLID;
+        (*brush)->brush.lb.lbColor = fgcol;
+        (*brush)->brush.lb.lbHatch = 0;
+        (*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb);
+    }
 
-    (*brush)->brush.gdibrush = CreateBrushIndirect(&(*brush)->brush.lb);
-    (*brush)->brush.bt = BrushTypeHatchFill;
-    (*brush)->forecol = forecol;
-    (*brush)->backcol = backcol;
-    (*brush)->hatchstyle = hatchstyle;
+    if (stat == Ok)
+    {
+        (*brush)->brush.bt = BrushTypeHatchFill;
+        (*brush)->forecol = forecol;
+        (*brush)->backcol = backcol;
+        (*brush)->hatchstyle = hatchstyle;
+    }
+    else
+    {
+        GdipFree(*brush);
+        *brush = NULL;
+    }
 
-    return Ok;
+    return stat;
 }
 
 /******************************************************************************
@@ -316,6 +393,10 @@ GpStatus WINGDIPAPI GdipCreateLineBrush(GDIPCONST GpPointF* startpoint,
     (*line)->blendfac[0] = 1.0f;
     (*line)->blendpos[0] = 1.0f;
 
+    (*line)->pblendcolor = NULL;
+    (*line)->pblendpos = NULL;
+    (*line)->pblendcount = 0;
+
     return Ok;
 }
 
@@ -762,7 +843,7 @@ GpStatus WINGDIPAPI GdipCreateTextureIA(GpImage *image,
 
     /* image is flipped */
     if(pbmi->bmiHeader.biHeight > 0){
-        dibits += pbmi->bmiHeader.biSizeImage;
+        dibits += image_stride * (pbmi->bmiHeader.biHeight - 1);
         image_stride *= -1;
         textbits += stride * (n_height - 1);
         stride *= -1;
@@ -893,6 +974,8 @@ GpStatus WINGDIPAPI GdipDeleteBrush(GpBrush *brush)
         case BrushTypeLinearGradient:
             GdipFree(((GpLineGradient*)brush)->blendfac);
             GdipFree(((GpLineGradient*)brush)->blendpos);
+            GdipFree(((GpLineGradient*)brush)->pblendcolor);
+            GdipFree(((GpLineGradient*)brush)->pblendpos);
             break;
         case BrushTypeTextureFill:
             GdipDeleteMatrix(((GpTexture*)brush)->transform);
@@ -1600,6 +1683,69 @@ GpStatus WINGDIPAPI GdipSetLineLinearBlend(GpLineGradient *brush, REAL focus,
 
 GpStatus WINGDIPAPI GdipSetLinePresetBlend(GpLineGradient *brush,
     GDIPCONST ARGB *blend, GDIPCONST REAL* positions, INT count)
+{
+    ARGB *new_color;
+    REAL *new_pos;
+    TRACE("(%p,%p,%p,%i)\n", brush, blend, positions, count);
+
+    if (!brush || !blend || !positions || count < 2 ||
+        positions[0] != 0.0f || positions[count-1] != 1.0f)
+    {
+        return InvalidParameter;
+    }
+
+    new_color = GdipAlloc(count * sizeof(ARGB));
+    new_pos = GdipAlloc(count * sizeof(REAL));
+    if (!new_color || !new_pos)
+    {
+        GdipFree(new_color);
+        GdipFree(new_pos);
+        return OutOfMemory;
+    }
+
+    memcpy(new_color, blend, sizeof(ARGB) * count);
+    memcpy(new_pos, positions, sizeof(REAL) * count);
+
+    GdipFree(brush->pblendcolor);
+    GdipFree(brush->pblendpos);
+
+    brush->pblendcolor = new_color;
+    brush->pblendpos = new_pos;
+    brush->pblendcount = count;
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetLinePresetBlend(GpLineGradient *brush,
+    ARGB *blend, REAL* positions, INT count)
+{
+    if (!brush || !blend || !positions || count < 2)
+        return InvalidParameter;
+
+    if (brush->pblendcount == 0)
+        return GenericError;
+
+    if (count < brush->pblendcount)
+        return InsufficientBuffer;
+
+    memcpy(blend, brush->pblendcolor, sizeof(ARGB) * brush->pblendcount);
+    memcpy(positions, brush->pblendpos, sizeof(REAL) * brush->pblendcount);
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipGetLinePresetBlendCount(GpLineGradient *brush,
+    INT *count)
+{
+    if (!brush || !count)
+        return InvalidParameter;
+
+    *count = brush->pblendcount;
+
+    return Ok;
+}
+
+GpStatus WINGDIPAPI GdipResetLineTransform(GpLineGradient *brush)
 {
     static int calls;
 
@@ -1620,6 +1766,17 @@ GpStatus WINGDIPAPI GdipSetLineTransform(GpLineGradient *brush,
     return NotImplemented;
 }
 
+GpStatus WINGDIPAPI GdipScaleLineTransform(GpLineGradient *brush, REAL sx, REAL sy,
+    GpMatrixOrder order)
+{
+    static int calls;
+
+    if(!(calls++))
+        FIXME("not implemented\n");
+
+    return NotImplemented;
+}
+
 GpStatus WINGDIPAPI GdipTranslateLineTransform(GpLineGradient* brush,
         REAL dx, REAL dy, GpMatrixOrder order)
 {
index ec956f3..9fe9332 100644 (file)
@@ -86,7 +86,7 @@ Status WINAPI GdiplusStartup(ULONG_PTR *token, const struct GdiplusStartupInput
           input->DebugEventCallback, input->SuppressBackgroundThread,
           input->SuppressExternalCodecs);
 
-    if(input->GdiplusVersion != 1)
+    if(input->GdiplusVersion < 1 || input->GdiplusVersion > 2)
         return UnsupportedGdiplusVersion;
 
     if(input->SuppressBackgroundThread){
@@ -211,38 +211,37 @@ static void unstretch_angle(REAL * angle, REAL rad_x, REAL rad_y)
 INT arc2polybezier(GpPointF * points, REAL x1, REAL y1, REAL x2, REAL y2,
     REAL startAngle, REAL sweepAngle)
 {
-    INT i, count;
+    INT i;
     REAL end_angle, start_angle, endAngle;
 
     endAngle = startAngle + sweepAngle;
     unstretch_angle(&startAngle, x2 / 2.0, y2 / 2.0);
     unstretch_angle(&endAngle, x2 / 2.0, y2 / 2.0);
 
-    count = ceilf(fabs(endAngle - startAngle) / M_PI_2) * 3 + 1;
-    /* don't make more than a full circle */
-    count = min(MAX_ARC_PTS, count);
-
-    if(count == 1)
-        return 0;
-    if(!points)
-        return count;
-
     /* start_angle and end_angle are the iterative variables */
     start_angle = startAngle;
 
-    for(i = 0; i < count - 1; i += 3){
+    for(i = 0; i < MAX_ARC_PTS - 1; i += 3){
         /* check if we've overshot the end angle */
         if( sweepAngle > 0.0 )
+        {
+            if (start_angle >= endAngle) break;
             end_angle = min(start_angle + M_PI_2, endAngle);
+        }
         else
+        {
+            if (start_angle <= endAngle) break;
             end_angle = max(start_angle - M_PI_2, endAngle);
+        }
 
-        add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0);
+        if (points)
+            add_arc_part(&points[i], x1, y1, x2, y2, start_angle, end_angle, i == 0);
 
         start_angle += M_PI_2 * (sweepAngle < 0.0 ? -1.0 : 1.0);
     }
 
-    return count;
+    if (i == 0) return 0;
+    else return i+1;
 }
 
 COLORREF ARGB2COLORREF(ARGB color)
@@ -419,7 +418,7 @@ void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
 }
 
 /* recursive deletion of GpRegion nodes */
-inline void delete_element(region_element* element)
+void delete_element(region_element* element)
 {
     switch(element->type)
     {
index bda241e..aa64a3c 100644 (file)
 @ stdcall GdipGetLineBlendCount(ptr ptr)
 @ stdcall GdipGetLineColors(ptr ptr)
 @ stdcall GdipGetLineGammaCorrection(ptr ptr)
-@ stub GdipGetLinePresetBlend
-@ stub GdipGetLinePresetBlendCount
+@ stdcall GdipGetLinePresetBlend(ptr ptr ptr long)
+@ stdcall GdipGetLinePresetBlendCount(ptr ptr)
 @ stdcall GdipGetLineRect(ptr ptr)
 @ stdcall GdipGetLineRectI(ptr ptr)
 @ stdcall GdipGetLineSpacing(ptr long ptr)
 @ stdcall GdipRemovePropertyItem(ptr long)
 @ stdcall GdipResetClip(ptr)
 @ stub GdipResetImageAttributes
-@ stub GdipResetLineTransform
+@ stdcall GdipResetLineTransform(ptr)
 @ stub GdipResetPageTransform
 @ stdcall GdipResetPath(ptr)
 @ stub GdipResetPathGradientTransform
 @ stdcall GdipSaveGraphics(ptr ptr)
 @ stdcall GdipSaveImageToFile(ptr ptr ptr ptr)
 @ stdcall GdipSaveImageToStream(ptr ptr ptr ptr)
-@ stub GdipScaleLineTransform
+@ stdcall GdipScaleLineTransform(ptr long long long)
 @ stdcall GdipScaleMatrix(ptr long long long)
 @ stub GdipScalePathGradientTransform
 @ stdcall GdipScalePenTransform(ptr long long long)
index e87176e..dfff66c 100644 (file)
@@ -61,7 +61,7 @@ extern BOOL lengthen_path(GpPath *path, INT len);
 extern GpStatus trace_path(GpGraphics *graphics, GpPath *path);
 
 typedef struct region_element region_element;
-extern inline void delete_element(region_element *element);
+extern void delete_element(region_element *element);
 
 static inline INT roundr(REAL x)
 {
@@ -166,6 +166,9 @@ struct GpLineGradient{
     REAL* blendfac;  /* blend factors */
     REAL* blendpos;  /* blend positions */
     INT blendcount;
+    ARGB* pblendcolor; /* preset blend colors */
+    REAL* pblendpos; /* preset blend positions */
+    INT pblendcount;
 };
 
 struct GpTexture{
@@ -208,6 +211,7 @@ struct GpAdustableArrowCap{
 struct GpImage{
     IPicture* picture;
     ImageType type;
+    GUID format;
     UINT flags;
 };
 
index 1df3eee..df107e4 100644 (file)
@@ -220,7 +220,27 @@ static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)
         blendfac = (left_blendfac * (right_blendpos - position) +
                     right_blendfac * (position - left_blendpos)) / range;
     }
-    return blend_colors(brush->startcolor, brush->endcolor, blendfac);
+
+    if (brush->pblendcount == 0)
+        return blend_colors(brush->startcolor, brush->endcolor, blendfac);
+    else
+    {
+        int i=1;
+        ARGB left_blendcolor, right_blendcolor;
+        REAL left_blendpos, right_blendpos;
+
+        /* locate the blend colors surrounding this position */
+        while (blendfac > brush->pblendpos[i])
+            i++;
+
+        /* interpolate between the blend colors */
+        left_blendpos = brush->pblendpos[i-1];
+        left_blendcolor = brush->pblendcolor[i-1];
+        right_blendpos = brush->pblendpos[i];
+        right_blendcolor = brush->pblendcolor[i];
+        blendfac = (blendfac - left_blendpos) / (right_blendpos - left_blendpos);
+        return blend_colors(left_blendcolor, right_blendcolor, blendfac);
+    }
 }
 
 static void brush_fill_path(GpGraphics *graphics, GpBrush* brush)
@@ -1235,6 +1255,7 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
 
 
     (*metafile)->image.type = ImageTypeMetafile;
+    memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID));
     (*metafile)->bounds.X = ((REAL) placeable->BoundingBox.Left) / ((REAL) placeable->Inch);
     (*metafile)->bounds.Y = ((REAL) placeable->BoundingBox.Right) / ((REAL) placeable->Inch);
     (*metafile)->bounds.Width = ((REAL) (placeable->BoundingBox.Right
@@ -1795,16 +1816,25 @@ GpStatus WINGDIPAPI GdipDrawImagePointRect(GpGraphics *graphics, GpImage *image,
     REAL x, REAL y, REAL srcx, REAL srcy, REAL srcwidth, REAL srcheight,
     GpUnit srcUnit)
 {
-    FIXME("(%p, %p, %f, %f, %f, %f, %f, %f, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
-    return NotImplemented;
+    GpPointF points[3];
+    TRACE("(%p, %p, %f, %f, %f, %f, %f, %f, %d)\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
+
+    points[0].X = points[2].X = x;
+    points[0].Y = points[1].Y = y;
+
+    /* FIXME: convert image coordinates to Graphics coordinates? */
+    points[1].X = x + srcwidth;
+    points[2].Y = y + srcheight;
+
+    return GdipDrawImagePointsRect(graphics, image, points, 3, srcx, srcy,
+        srcwidth, srcheight, srcUnit, NULL, NULL, NULL);
 }
 
 GpStatus WINGDIPAPI GdipDrawImagePointRectI(GpGraphics *graphics, GpImage *image,
     INT x, INT y, INT srcx, INT srcy, INT srcwidth, INT srcheight,
     GpUnit srcUnit)
 {
-    FIXME("(%p, %p, %d, %d, %d, %d, %d, %d, %d): stub\n", graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
-    return NotImplemented;
+    return GdipDrawImagePointRect(graphics, image, x, y, srcx, srcy, srcwidth, srcheight, srcUnit);
 }
 
 GpStatus WINGDIPAPI GdipDrawImagePoints(GpGraphics *graphics, GpImage *image,
@@ -1854,15 +1884,6 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
         else
             return NotImplemented;
 
-        /* IPicture renders bitmaps with the y-axis reversed
-         * FIXME: flipping for unknown image type might not be correct. */
-        if(image->type != ImageTypeMetafile){
-            INT temp;
-            temp = pti[0].y;
-            pti[0].y = pti[2].y;
-            pti[2].y = temp;
-        }
-
         if(IPicture_Render(image->picture, graphics->hdc,
             pti[0].x, pti[0].y, pti[1].x - pti[0].x, pti[2].y - pti[0].y,
             srcx * dx, srcy * dy,
@@ -2362,7 +2383,7 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
     HFONT gdifont;
     LOGFONTW lfw;
     TEXTMETRICW textmet;
-    GpPointF pt[2], rectcpy[4];
+    GpPointF pt[3], rectcpy[4];
     POINT corners[4];
     WCHAR* stringdup;
     REAL angle, ang_cos, ang_sin, rel_width, rel_height;
@@ -2409,6 +2430,21 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
     SetBkMode(graphics->hdc, TRANSPARENT);
     SetTextColor(graphics->hdc, brush->lb.lbColor);
 
+    pt[0].X = 0.0;
+    pt[0].Y = 0.0;
+    pt[1].X = 1.0;
+    pt[1].Y = 0.0;
+    pt[2].X = 0.0;
+    pt[2].Y = 1.0;
+    GdipTransformPoints(graphics, CoordinateSpaceDevice, CoordinateSpaceWorld, pt, 3);
+    angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
+    ang_cos = cos(angle);
+    ang_sin = sin(angle);
+    rel_width = sqrt((pt[1].Y-pt[0].Y)*(pt[1].Y-pt[0].Y)+
+                     (pt[1].X-pt[0].X)*(pt[1].X-pt[0].X));
+    rel_height = sqrt((pt[2].Y-pt[0].Y)*(pt[2].Y-pt[0].Y)+
+                      (pt[2].X-pt[0].X)*(pt[2].X-pt[0].X));
+
     rectcpy[3].X = rectcpy[0].X = rect->X;
     rectcpy[1].Y = rectcpy[0].Y = rect->Y + offsety;
     rectcpy[2].X = rectcpy[1].X = rect->X + rect->Width;
@@ -2416,30 +2452,14 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
     transform_and_round_points(graphics, corners, rectcpy, 4);
 
     if (roundr(rect->Width) == 0)
-    {
-        rel_width = 1.0;
         nwidth = INT_MAX;
-    }
     else
-    {
-        rel_width = sqrt((corners[1].x - corners[0].x) * (corners[1].x - corners[0].x) +
-                         (corners[1].y - corners[0].y) * (corners[1].y - corners[0].y))
-                         / rect->Width;
         nwidth = roundr(rel_width * rect->Width);
-    }
 
     if (roundr(rect->Height) == 0)
-    {
-        rel_height = 1.0;
         nheight = INT_MAX;
-    }
     else
-    {
-        rel_height = sqrt((corners[2].x - corners[1].x) * (corners[2].x - corners[1].x) +
-                          (corners[2].y - corners[1].y) * (corners[2].y - corners[1].y))
-                          / rect->Height;
         nheight = roundr(rel_height * rect->Height);
-    }
 
     if (roundr(rect->Width) != 0 && roundr(rect->Height) != 0)
     {
@@ -2457,14 +2477,6 @@ GpStatus WINGDIPAPI GdipDrawString(GpGraphics *graphics, GDIPCONST WCHAR *string
     lfw.lfHeight = roundr(((REAL)lfw.lfHeight) * rel_height);
     lfw.lfWidth = roundr(textmet.tmAveCharWidth * rel_width);
 
-    pt[0].X = 0.0;
-    pt[0].Y = 0.0;
-    pt[1].X = 1.0;
-    pt[1].Y = 0.0;
-    GdipTransformMatrixPoints(graphics->worldtrans, pt, 2);
-    angle = -gdiplus_atan2((pt[1].Y - pt[0].Y), (pt[1].X - pt[0].X));
-    ang_cos = cos(angle);
-    ang_sin = sin(angle);
     lfw.lfEscapement = lfw.lfOrientation = roundr((angle / M_PI) * 1800.0);
 
     gdifont = CreateFontIndirectW(&lfw);
index b1e831f..5b70918 100644 (file)
@@ -94,36 +94,321 @@ GpStatus WINGDIPAPI GdipBitmapCreateApplyEffect(GpBitmap** inputBitmaps,
     return NotImplemented;
 }
 
+static inline void getpixel_16bppGrayScale(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *r = *g = *b = row[x*2+1];
+    *a = 255;
+}
+
+static inline void getpixel_16bppRGB555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    WORD pixel = *((WORD*)(row)+x);
+    *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
+    *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
+    *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
+    *a = 255;
+}
+
+static inline void getpixel_16bppRGB565(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    WORD pixel = *((WORD*)(row)+x);
+    *r = (pixel>>8&0xf8)|(pixel>>13&0x7);
+    *g = (pixel>>3&0xfc)|(pixel>>9&0x3);
+    *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
+    *a = 255;
+}
+
+static inline void getpixel_16bppARGB1555(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    WORD pixel = *((WORD*)(row)+x);
+    *r = (pixel>>7&0xf8)|(pixel>>12&0x7);
+    *g = (pixel>>2&0xf8)|(pixel>>6&0x7);
+    *b = (pixel<<3&0xf8)|(pixel>>2&0x7);
+    if ((pixel&0x8000) == 0x8000)
+        *a = 255;
+    else
+        *a = 0;
+}
+
+static inline void getpixel_24bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *r = row[x*3+2];
+    *g = row[x*3+1];
+    *b = row[x*3];
+    *a = 255;
+}
+
+static inline void getpixel_32bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *r = row[x*4+2];
+    *g = row[x*4+1];
+    *b = row[x*4];
+    *a = 255;
+}
+
+static inline void getpixel_32bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *r = row[x*4+2];
+    *g = row[x*4+1];
+    *b = row[x*4];
+    *a = row[x*4+3];
+}
+
+static inline void getpixel_32bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *a = row[x*4+3];
+    if (*a == 0)
+        *r = *g = *b = 0;
+    else
+    {
+        *r = row[x*4+2] * 255 / *a;
+        *g = row[x*4+1] * 255 / *a;
+        *b = row[x*4] * 255 / *a;
+    }
+}
+
+static inline void getpixel_48bppRGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *r = row[x*6+5];
+    *g = row[x*6+3];
+    *b = row[x*6+1];
+    *a = 255;
+}
+
+static inline void getpixel_64bppARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *r = row[x*8+5];
+    *g = row[x*8+3];
+    *b = row[x*8+1];
+    *a = row[x*8+7];
+}
+
+static inline void getpixel_64bppPARGB(BYTE *r, BYTE *g, BYTE *b, BYTE *a,
+    const BYTE *row, UINT x)
+{
+    *a = row[x*8+7];
+    if (*a == 0)
+        *r = *g = *b = 0;
+    else
+    {
+        *r = row[x*8+5] * 255 / *a;
+        *g = row[x*8+3] * 255 / *a;
+        *b = row[x*8+1] * 255 / *a;
+    }
+}
+
 GpStatus WINGDIPAPI GdipBitmapGetPixel(GpBitmap* bitmap, INT x, INT y,
     ARGB *color)
 {
-    static int calls;
+    BYTE r, g, b, a;
+    BYTE *row;
     TRACE("%p %d %d %p\n", bitmap, x, y, color);
 
-    if(!bitmap || !color)
+    if(!bitmap || !color ||
+       x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    row = bitmap->bits+bitmap->stride*y;
 
-    *color = 0xdeadbeef;
+    switch (bitmap->format)
+    {
+        case PixelFormat16bppGrayScale:
+            getpixel_16bppGrayScale(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat16bppRGB555:
+            getpixel_16bppRGB555(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat16bppRGB565:
+            getpixel_16bppRGB565(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat16bppARGB1555:
+            getpixel_16bppARGB1555(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat24bppRGB:
+            getpixel_24bppRGB(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat32bppRGB:
+            getpixel_32bppRGB(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat32bppARGB:
+            getpixel_32bppARGB(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat32bppPARGB:
+            getpixel_32bppPARGB(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat48bppRGB:
+            getpixel_48bppRGB(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat64bppARGB:
+            getpixel_64bppARGB(&r,&g,&b,&a,row,x);
+            break;
+        case PixelFormat64bppPARGB:
+            getpixel_64bppPARGB(&r,&g,&b,&a,row,x);
+            break;
+        default:
+            FIXME("not implemented for format 0x%x\n", bitmap->format);
+            return NotImplemented;
+    }
 
-    return NotImplemented;
+    *color = a<<24|r<<16|g<<8|b;
+
+    return Ok;
+}
+
+static inline void setpixel_16bppGrayScale(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    *((WORD*)(row)+x) = (r+g+b)*85;
+}
+
+static inline void setpixel_16bppRGB555(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    *((WORD*)(row)+x) = (r<<7&0x7c00)|
+                        (g<<2&0x03e0)|
+                        (b>>3&0x001f);
+}
+
+static inline void setpixel_16bppRGB565(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    *((WORD*)(row)+x) = (r<<8&0xf800)|
+                         (g<<3&0x07e0)|
+                         (b>>3&0x001f);
+}
+
+static inline void setpixel_16bppARGB1555(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    *((WORD*)(row)+x) = (a<<8&0x8000)|
+                        (r<<7&0x7c00)|
+                        (g<<2&0x03e0)|
+                        (b>>3&0x001f);
+}
+
+static inline void setpixel_24bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    row[x*3+2] = r;
+    row[x*3+1] = g;
+    row[x*3] = b;
+}
+
+static inline void setpixel_32bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    *((DWORD*)(row)+x) = (r<<16)|(g<<8)|b;
+}
+
+static inline void setpixel_32bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+static inline void setpixel_32bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    r = r * a / 255;
+    g = g * a / 255;
+    b = b * a / 255;
+    *((DWORD*)(row)+x) = (a<<24)|(r<<16)|(g<<8)|b;
+}
+
+static inline void setpixel_48bppRGB(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    row[x*6+5] = row[x*6+4] = r;
+    row[x*6+3] = row[x*6+2] = g;
+    row[x*6+1] = row[x*6] = b;
+}
+
+static inline void setpixel_64bppARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    UINT64 a64=a, r64=r, g64=g, b64=b;
+    *((UINT64*)(row)+x) = (a64<<56)|(a64<<48)|(r64<<40)|(r64<<32)|(g64<<24)|(g64<<16)|(b64<<8)|b64;
+}
+
+static inline void setpixel_64bppPARGB(BYTE r, BYTE g, BYTE b, BYTE a,
+    BYTE *row, UINT x)
+{
+    UINT64 a64, r64, g64, b64;
+    a64 = a * 257;
+    r64 = r * a / 255;
+    g64 = g * a / 255;
+    b64 = b * a / 255;
+    *((UINT64*)(row)+x) = (a64<<48)|(r64<<32)|(g64<<16)|b64;
 }
 
 GpStatus WINGDIPAPI GdipBitmapSetPixel(GpBitmap* bitmap, INT x, INT y,
     ARGB color)
 {
-    static int calls;
+    BYTE a, r, g, b;
+    BYTE *row;
     TRACE("bitmap:%p, x:%d, y:%d, color:%08x\n", bitmap, x, y, color);
 
-    if(!bitmap)
+    if(!bitmap || x < 0 || y < 0 || x >= bitmap->width || y >= bitmap->height)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("not implemented\n");
+    a = color>>24;
+    r = color>>16;
+    g = color>>8;
+    b = color;
 
-    return NotImplemented;
+    row = bitmap->bits + bitmap->stride * y;
+
+    switch (bitmap->format)
+    {
+        case PixelFormat16bppGrayScale:
+            setpixel_16bppGrayScale(r,g,b,a,row,x);
+            break;
+        case PixelFormat16bppRGB555:
+            setpixel_16bppRGB555(r,g,b,a,row,x);
+            break;
+        case PixelFormat16bppRGB565:
+            setpixel_16bppRGB565(r,g,b,a,row,x);
+            break;
+        case PixelFormat16bppARGB1555:
+            setpixel_16bppARGB1555(r,g,b,a,row,x);
+            break;
+        case PixelFormat24bppRGB:
+            setpixel_24bppRGB(r,g,b,a,row,x);
+            break;
+        case PixelFormat32bppRGB:
+            setpixel_32bppRGB(r,g,b,a,row,x);
+            break;
+        case PixelFormat32bppARGB:
+            setpixel_32bppARGB(r,g,b,a,row,x);
+            break;
+        case PixelFormat32bppPARGB:
+            setpixel_32bppPARGB(r,g,b,a,row,x);
+            break;
+        case PixelFormat48bppRGB:
+            setpixel_48bppRGB(r,g,b,a,row,x);
+            break;
+        case PixelFormat64bppARGB:
+            setpixel_64bppARGB(r,g,b,a,row,x);
+            break;
+        case PixelFormat64bppPARGB:
+            setpixel_64bppPARGB(r,g,b,a,row,x);
+            break;
+        default:
+            FIXME("not implemented for format 0x%x\n", bitmap->format);
+            return NotImplemented;
+    }
+
+    return Ok;
 }
 
 /* This function returns a pointer to an array of pixels that represents the
@@ -413,6 +698,8 @@ GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
             GdipDisposeImage(*cloneImage);
             *cloneImage = NULL;
         }
+        else memcpy(&(*cloneImage)->format, &image->format, sizeof(GUID));
+
         return stat;
     }
     else
@@ -645,11 +932,7 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromHICON(HICON hicon, GpBitmap** bitmap)
     TRACE("%p, %p\n", hicon, bitmap);
 
     if(!bitmap || !GetIconInfo(hicon, &iinfo))
-    {
-        DeleteObject(iinfo.hbmColor);
-        DeleteObject(iinfo.hbmMask);
         return InvalidParameter;
-    }
 
     /* get the size of the icon */
     ret = GetObjectA(iinfo.hbmColor ? iinfo.hbmColor : iinfo.hbmMask, sizeof(bm), &bm);
@@ -858,6 +1141,7 @@ 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)->width = width;
     (*bitmap)->height = height;
@@ -1144,23 +1428,11 @@ GpStatus WINGDIPAPI GdipGetImagePixelFormat(GpImage *image, PixelFormat *format)
 
 GpStatus WINGDIPAPI GdipGetImageRawFormat(GpImage *image, GUID *format)
 {
-    static int calls;
-
     if(!image || !format)
         return InvalidParameter;
 
-    if(!(calls++))
-        FIXME("stub\n");
+    memcpy(format, &image->format, sizeof(GUID));
 
-    /* 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;
 }
 
@@ -1507,105 +1779,37 @@ static GpStatus decode_image_icon(IStream* stream, REFCLSID clsid, GpImage **ima
     return decode_image_wic(stream, &CLSID_WICIcoDecoder, image);
 }
 
-static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
+static GpStatus decode_image_bmp(IStream* stream, REFCLSID clsid, GpImage **image)
 {
-    return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
-}
-
-static GpStatus decode_image_gif(IStream* stream, REFCLSID clsid, GpImage **image)
-{
-    return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
-}
-
-static GpStatus decode_image_olepicture_bitmap(IStream* stream, REFCLSID clsid, GpImage **image)
-{
-    IPicture *pic;
-    BITMAPINFO *pbmi;
-    BITMAPCOREHEADER* bmch;
-    HBITMAP hbm;
-    HDC hdc;
-
-    TRACE("%p %p\n", stream, image);
-
-    if(!stream || !image)
-        return InvalidParameter;
-
-    if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
-        (LPVOID*) &pic) != S_OK){
-        TRACE("Could not load picture\n");
-        return GenericError;
-    }
-
-    pbmi = GdipAlloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
-    if (!pbmi)
-        return OutOfMemory;
-    *image = GdipAlloc(sizeof(GpBitmap));
-    if(!*image){
-        GdipFree(pbmi);
-        return OutOfMemory;
-    }
-    (*image)->type = ImageTypeBitmap;
-
-    (*((GpBitmap**) image))->width = ipicture_pixel_width(pic);
-    (*((GpBitmap**) image))->height = ipicture_pixel_height(pic);
+    GpStatus status;
+    GpBitmap* bitmap;
 
-    /* get the pixel format */
-    IPicture_get_Handle(pic, (OLE_HANDLE*)&hbm);
-    IPicture_get_CurDC(pic, &hdc);
+    status = decode_image_wic(stream, &CLSID_WICBmpDecoder, image);
 
-    (*((GpBitmap**) image))->hbitmap = hbm;
-    (*((GpBitmap**) image))->hdc = hdc;
-    (*((GpBitmap**) image))->bits = NULL;
+    bitmap = (GpBitmap*)*image;
 
-    bmch = (BITMAPCOREHEADER*) (&pbmi->bmiHeader);
-    bmch->bcSize = sizeof(BITMAPCOREHEADER);
-
-    if(!hdc){
-        HBITMAP old;
-        hdc = CreateCompatibleDC(0);
-        old = SelectObject(hdc, hbm);
-        GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
-        SelectObject(hdc, old);
-        DeleteDC(hdc);
-    }
-    else
-        GetDIBits(hdc, hbm, 0, 0, NULL, pbmi, DIB_RGB_COLORS);
-
-    switch(bmch->bcBitCount)
+    if (status == Ok && bitmap->format == PixelFormat32bppARGB)
     {
-        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;
+        /* WIC supports bmp files with alpha, but gdiplus does not */
+        bitmap->format = PixelFormat32bppRGB;
     }
 
-    GdipFree(pbmi);
+    return status;
+}
 
-    (*image)->picture = pic;
-    (*image)->flags   = ImageFlagsNone;
+static GpStatus decode_image_jpeg(IStream* stream, REFCLSID clsid, GpImage **image)
+{
+    return decode_image_wic(stream, &CLSID_WICJpegDecoder, image);
+}
 
-    return Ok;
+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)
+{
+    return decode_image_wic(stream, &CLSID_WICGifDecoder, image);
 }
 
 static GpStatus decode_image_olepicture_metafile(IStream* stream, REFCLSID clsid, GpImage **image)
@@ -1715,7 +1919,15 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream* stream, GpImage **image)
     if (FAILED(hr)) return hresult_to_status(hr);
 
     /* call on the image decoder to do the real work */
-    return codec->decode_func(stream, &codec->info.Clsid, image);
+    stat = codec->decode_func(stream, &codec->info.Clsid, image);
+
+    /* take note of the original data format */
+    if (stat == Ok)
+    {
+        memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
+    }
+
+    return stat;
 }
 
 /* FIXME: no ICM */
@@ -1915,6 +2127,12 @@ static GpStatus encode_image_BMP(GpImage *image, IStream* stream,
     return encode_image_WIC(image, stream, &CLSID_WICBmpEncoder, params);
 }
 
+static GpStatus encode_image_png(GpImage *image, IStream* stream,
+    GDIPCONST CLSID* clsid, GDIPCONST EncoderParameters* params)
+{
+    return encode_image_WIC(image, stream, &CLSID_WICPngEncoder, params);
+}
+
 /*****************************************************************************
  * GdipSaveImageToStream [GDIPLUS.@]
  */
@@ -2051,7 +2269,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* SigMask */            bmp_sig_mask,
         },
         encode_image_BMP,
-        decode_image_olepicture_bitmap
+        decode_image_bmp
     },
     {
         { /* JPEG */
@@ -2138,15 +2356,15 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* FormatDescription */  png_format,
             /* FilenameExtension */  png_extension,
             /* MimeType */           png_mimetype,
-            /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
+            /* Flags */              ImageCodecFlagsEncoder | ImageCodecFlagsDecoder | ImageCodecFlagsSupportBitmap | ImageCodecFlagsBuiltin,
             /* Version */            1,
             /* SigCount */           1,
             /* SigSize */            8,
             /* SigPattern */         png_sig_pattern,
             /* SigMask */            png_sig_mask,
         },
-        NULL,
-        decode_image_olepicture_bitmap
+        encode_image_png,
+        decode_image_png
     },
     {
         { /* ICO */