[PATCH 1/5] gdiplus/metafile: Implement EmfPlusImage deserialization for bitmaps

Nikolay Sivov nsivov at codeweavers.com
Mon Oct 16 02:12:21 CDT 2017


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/gdiplus/gdiplus_private.h |   1 +
 dlls/gdiplus/metafile.c        | 117 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+)

diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 95445e879a..f659ccf1c1 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -394,6 +394,7 @@ struct emfplus_object {
     EmfPlusObjectType type;
     union {
         GpBrush *brush;
+        GpImage *image;
         GpImageAttributes *image_attributes;
         void *object;
     } u;
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index de208a8bd2..2fc741e742 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -43,6 +43,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
 
+HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
+
 typedef struct EmfPlusARGB
 {
     BYTE Blue;
@@ -246,6 +248,13 @@ typedef struct EmfPlusRegion
     BYTE RegionNode[1];
 } EmfPlusRegion;
 
+typedef struct EmfPlusPalette
+{
+    DWORD PaletteStyleFlags;
+    DWORD PaletteCount;
+    BYTE PaletteEntries[1];
+} EmfPlusPalette;
+
 typedef enum
 {
     BitmapDataTypePixel,
@@ -367,6 +376,9 @@ static void metafile_free_object_table_entry(GpMetafile *metafile, BYTE id)
     case ObjectTypeBrush:
         GdipDeleteBrush(object->u.brush);
         break;
+    case ObjectTypeImage:
+        GdipDisposeImage(object->u.image);
+        break;
     case ObjectTypeImageAttributes:
         GdipDisposeImageAttributes(object->u.image_attributes);
         break;
@@ -1446,6 +1458,108 @@ static void metafile_set_object_table_entry(GpMetafile *metafile, BYTE id, BYTE
     metafile->objtable[id].u.object = object;
 }
 
+static GpStatus metafile_deserialize_image(const BYTE *record_data, UINT data_size, GpImage **image)
+{
+    EmfPlusImage *data = (EmfPlusImage *)record_data;
+    GpStatus status;
+
+    *image = NULL;
+
+    if (data_size < FIELD_OFFSET(EmfPlusImage, ImageData))
+        return InvalidParameter;
+    data_size -= FIELD_OFFSET(EmfPlusImage, ImageData);
+
+    switch (data->Type)
+    {
+    case ImageDataTypeBitmap:
+    {
+        EmfPlusBitmap *bitmapdata = &data->ImageData.bitmap;
+
+        if (data_size <= FIELD_OFFSET(EmfPlusBitmap, BitmapData))
+            return InvalidParameter;
+        data_size -= FIELD_OFFSET(EmfPlusBitmap, BitmapData);
+
+        switch (bitmapdata->Type)
+        {
+        case BitmapDataTypePixel:
+        {
+            ColorPalette *palette;
+            BYTE *scan0;
+
+            if (bitmapdata->PixelFormat & PixelFormatIndexed)
+            {
+                EmfPlusPalette *palette_obj = (EmfPlusPalette *)bitmapdata->BitmapData;
+                UINT palette_size = FIELD_OFFSET(EmfPlusPalette, PaletteEntries);
+
+                if (data_size <= palette_size)
+                    return InvalidParameter;
+                palette_size += palette_obj->PaletteCount * sizeof(EmfPlusARGB);
+
+                if (data_size < palette_size)
+                    return InvalidParameter;
+                data_size -= palette_size;
+
+                palette = (ColorPalette *)bitmapdata->BitmapData;
+                scan0 = (BYTE *)bitmapdata->BitmapData + palette_size;
+            }
+            else
+            {
+                palette = NULL;
+                scan0 = bitmapdata->BitmapData;
+            }
+
+            if (data_size < bitmapdata->Height * bitmapdata->Stride)
+                return InvalidParameter;
+
+            status = GdipCreateBitmapFromScan0(bitmapdata->Width, bitmapdata->Height, bitmapdata->Stride,
+                bitmapdata->PixelFormat, scan0, (GpBitmap **)image);
+            if (status == Ok && palette)
+            {
+                status = GdipSetImagePalette(*image, palette);
+                if (status != Ok)
+                {
+                    GdipDisposeImage(*image);
+                    *image = NULL;
+                }
+            }
+            break;
+        }
+        case BitmapDataTypeCompressed:
+        {
+            IWICImagingFactory *factory;
+            IWICStream *stream;
+            HRESULT hr;
+
+            if (WICCreateImagingFactory_Proxy(WINCODEC_SDK_VERSION, &factory) != S_OK)
+                return GenericError;
+
+            hr = IWICImagingFactory_CreateStream(factory, &stream);
+            IWICImagingFactory_Release(factory);
+            if (hr != S_OK)
+                return GenericError;
+
+            if (IWICStream_InitializeFromMemory(stream, bitmapdata->BitmapData, data_size) == S_OK)
+                status = GdipCreateBitmapFromStream((IStream *)stream, (GpBitmap **)image);
+            else
+                status = GenericError;
+
+            IWICStream_Release(stream);
+            break;
+        }
+        default:
+            WARN("Invalid bitmap type %d.\n", bitmapdata->Type);
+            return InvalidParameter;
+        }
+        break;
+    }
+    default:
+        FIXME("image type %d not supported.\n", data->Type);
+        return NotImplemented;
+    }
+
+    return status;
+}
+
 static GpStatus metafile_deserialize_brush(const BYTE *record_data, UINT data_size, GpBrush **brush)
 {
     static const UINT header_size = FIELD_OFFSET(EmfPlusBrush, BrushData);
@@ -1488,6 +1602,9 @@ static GpStatus METAFILE_PlaybackObject(GpMetafile *metafile, UINT flags, UINT d
     case ObjectTypeBrush:
         status = metafile_deserialize_brush(record_data, data_size, (GpBrush **)&object);
         break;
+    case ObjectTypeImage:
+        status = metafile_deserialize_image(record_data, data_size, (GpImage **)&object);
+        break;
     case ObjectTypeImageAttributes:
     {
         EmfPlusImageAttributes *data = (EmfPlusImageAttributes *)record_data;
-- 
2.14.2




More information about the wine-patches mailing list