gdiplus: Reimplement metafile loading using gdi32 instead of IPicture. (v3)
Sebastian Lackner
sebastian at fds-team.de
Thu Aug 18 14:22:02 CDT 2016
From: Dmitry Timoshkov <dmitry at baikal.ru>
Signed-off-by: Dmitry Timoshkov <dmitry at baikal.ru>
Signed-off-by: Sebastian Lackner <sebastian at fds-team.de>
---
Changes in v3:
* Remove second part of WARN messages. (thanks Vincent)
dlls/gdiplus/Makefile.in | 2
dlls/gdiplus/gdiplus_private.h | 1
dlls/gdiplus/graphics.c | 18 ---
dlls/gdiplus/image.c | 238 ++++++++++++++++++++++++-----------------
dlls/gdiplus/metafile.c | 1
dlls/gdiplus/tests/image.c | 10 -
6 files changed, 152 insertions(+), 118 deletions(-)
diff --git a/dlls/gdiplus/Makefile.in b/dlls/gdiplus/Makefile.in
index 6495eb7..ac12bd1 100644
--- a/dlls/gdiplus/Makefile.in
+++ b/dlls/gdiplus/Makefile.in
@@ -1,6 +1,6 @@
MODULE = gdiplus.dll
IMPORTLIB = gdiplus
-IMPORTS = uuid shlwapi oleaut32 ole32 user32 gdi32
+IMPORTS = uuid shlwapi ole32 user32 gdi32
DELAYIMPORTS = windowscodecs
C_SRCS = \
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 678daed..216dd4a 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -338,7 +338,6 @@ struct GpAdjustableArrowCap{
};
struct GpImage{
- IPicture *picture;
IWICBitmapDecoder *decoder;
ImageType type;
GUID format;
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 84afee1..14b9db9 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -2901,23 +2901,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
srcheight = units_to_pixels(srcheight, srcUnit, image->yres);
TRACE("src pixels: %f,%f %fx%f\n", srcx, srcy, srcwidth, srcheight);
- if (image->picture)
- {
- if (!graphics->hdc)
- {
- FIXME("graphics object has no HDC\n");
- }
-
- 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, srcy, srcwidth, srcheight, NULL) != S_OK)
- {
- if(callback)
- callback(callbackData);
- return GenericError;
- }
- }
- else if (image->type == ImageTypeBitmap)
+ if (image->type == ImageTypeBitmap)
{
GpBitmap* bitmap = (GpBitmap*)image;
BOOL do_resampling = FALSE;
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index c3f6a5e..74fad29 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Google (Evan Stade)
- * Copyright (C) 2012 Dmitry Timoshkov
+ * Copyright (C) 2012,2016 Dmitry Timoshkov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -43,6 +43,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(gdiplus);
HRESULT WINAPI WICCreateImagingFactory_Proxy(UINT, IWICImagingFactory**);
#define PIXELFORMATBPP(x) ((x) ? ((x) >> 8) & 255 : 24)
+#define WMF_PLACEABLE_KEY 0x9ac6cdd7
static const struct
{
@@ -124,34 +125,6 @@ static ColorPalette *get_palette(IWICBitmapFrameDecode *frame, WICBitmapPaletteT
return palette;
}
-static INT ipicture_pixel_height(IPicture *pic)
-{
- HDC hdcref;
- OLE_YSIZE_HIMETRIC y;
-
- IPicture_get_Height(pic, &y);
-
- hdcref = CreateCompatibleDC(0);
- y = MulDiv(y, GetDeviceCaps(hdcref, LOGPIXELSY), INCH_HIMETRIC);
- DeleteDC(hdcref);
-
- return y;
-}
-
-static INT ipicture_pixel_width(IPicture *pic)
-{
- HDC hdcref;
- OLE_XSIZE_HIMETRIC x;
-
- IPicture_get_Width(pic, &x);
-
- hdcref = CreateCompatibleDC(0);
- x = MulDiv(x, GetDeviceCaps(hdcref, LOGPIXELSX), INCH_HIMETRIC);
- DeleteDC(hdcref);
-
- return x;
-}
-
GpStatus WINGDIPAPI GdipBitmapApplyEffect(GpBitmap* bitmap, CGpEffect* effect,
RECT* roi, BOOL useAuxData, VOID** auxData, INT* auxDataSize)
{
@@ -1309,45 +1282,12 @@ GpStatus WINGDIPAPI GdipCloneBitmapAreaI(INT x, INT y, INT width, INT height,
GpStatus WINGDIPAPI GdipCloneImage(GpImage *image, GpImage **cloneImage)
{
- GpStatus stat = GenericError;
-
TRACE("%p, %p\n", image, cloneImage);
if (!image || !cloneImage)
return InvalidParameter;
- if (image->picture)
- {
- IStream* stream;
- HRESULT hr;
- INT size;
- LARGE_INTEGER move;
-
- hr = CreateStreamOnHGlobal(0, TRUE, &stream);
- if (FAILED(hr))
- return GenericError;
-
- hr = IPicture_SaveAsFile(image->picture, stream, FALSE, &size);
- if(FAILED(hr))
- {
- WARN("Failed to save image on stream\n");
- goto out;
- }
-
- /* Set seek pointer back to the beginning of the picture */
- move.QuadPart = 0;
- hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL);
- if (FAILED(hr))
- goto out;
-
- stat = GdipLoadImageFromStream(stream, cloneImage);
- if (stat != Ok) WARN("Failed to load image from stream\n");
-
- out:
- IStream_Release(stream);
- return stat;
- }
- else if (image->type == ImageTypeBitmap)
+ if (image->type == ImageTypeBitmap)
{
GpBitmap *bitmap = (GpBitmap *)image;
@@ -1884,7 +1824,6 @@ GpStatus WINGDIPAPI GdipCreateBitmapFromScan0(INT width, INT height, INT stride,
(*bitmap)->width = width;
(*bitmap)->height = height;
(*bitmap)->format = format;
- (*bitmap)->image.picture = NULL;
(*bitmap)->image.decoder = NULL;
(*bitmap)->hbitmap = hbitmap;
(*bitmap)->hdc = NULL;
@@ -2152,8 +2091,6 @@ static GpStatus free_image_data(GpImage *image)
WARN("invalid image: %p\n", image);
return ObjectBusy;
}
- if (image->picture)
- IPicture_Release(image->picture);
if (image->decoder)
IWICBitmapDecoder_Release(image->decoder);
heap_free(image->palette);
@@ -2220,10 +2157,8 @@ GpStatus WINGDIPAPI GdipGetImageBounds(GpImage *image, GpRectF *srcRect,
*srcUnit = UnitPixel;
}
else{
- srcRect->X = srcRect->Y = 0.0;
- srcRect->Width = ipicture_pixel_width(image->picture);
- srcRect->Height = ipicture_pixel_height(image->picture);
- *srcUnit = UnitPixel;
+ WARN("GpImage with no image data\n");
+ return InvalidParameter;
}
TRACE("returning (%f, %f) (%f, %f) unit type %d\n", srcRect->X, srcRect->Y,
@@ -2249,8 +2184,8 @@ GpStatus WINGDIPAPI GdipGetImageDimension(GpImage *image, REAL *width,
*width = ((GpBitmap*)image)->width;
}
else{
- *height = ipicture_pixel_height(image->picture);
- *width = ipicture_pixel_width(image->picture);
+ WARN("GpImage with no image data\n");
+ return InvalidParameter;
}
TRACE("returning (%f, %f)\n", *height, *width);
@@ -2307,7 +2242,10 @@ GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
else if(image->type == ImageTypeBitmap)
*height = ((GpBitmap*)image)->height;
else
- *height = ipicture_pixel_height(image->picture);
+ {
+ WARN("GpImage with no image data\n");
+ return InvalidParameter;
+ }
TRACE("returning %d\n", *height);
@@ -2407,7 +2345,10 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
else if(image->type == ImageTypeBitmap)
*width = ((GpBitmap*)image)->width;
else
- *width = ipicture_pixel_width(image->picture);
+ {
+ WARN("GpImage with no image data\n");
+ return InvalidParameter;
+ }
TRACE("returning %d\n", *width);
@@ -4037,33 +3978,144 @@ static GpStatus decode_image_tiff(IStream* stream, GpImage **image)
return decode_image_wic(stream, &GUID_ContainerFormatTiff, NULL, image);
}
-static GpStatus decode_image_olepicture_metafile(IStream* stream, GpImage **image)
+static GpStatus load_wmf(IStream *stream, GpMetafile **metafile)
+{
+ WmfPlaceableFileHeader pfh;
+ BOOL is_placeable = FALSE;
+ LARGE_INTEGER seek;
+ GpStatus status;
+ METAHEADER mh;
+ HMETAFILE hmf;
+ HRESULT hr;
+ UINT size;
+ void *buf;
+
+ hr = IStream_Read(stream, &mh, sizeof(mh), &size);
+ if (hr != S_OK || size != sizeof(mh))
+ return GenericError;
+
+ if (((WmfPlaceableFileHeader *)&mh)->Key == WMF_PLACEABLE_KEY)
+ {
+ seek.QuadPart = 0;
+ hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ hr = IStream_Read(stream, &pfh, sizeof(pfh), &size);
+ if (hr != S_OK || size != sizeof(pfh))
+ return GenericError;
+
+ hr = IStream_Read(stream, &mh, sizeof(mh), &size);
+ if (hr != S_OK || size != sizeof(mh))
+ return GenericError;
+
+ is_placeable = TRUE;
+ }
+
+ seek.QuadPart = is_placeable ? sizeof(pfh) : 0;
+ hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ buf = heap_alloc(mh.mtSize * 2);
+ if (!buf) return OutOfMemory;
+
+ hr = IStream_Read(stream, buf, mh.mtSize * 2, &size);
+ if (hr != S_OK || size != mh.mtSize * 2)
+ {
+ heap_free(buf);
+ return GenericError;
+ }
+
+ hmf = SetMetaFileBitsEx(mh.mtSize * 2, buf);
+ heap_free(buf);
+ if (!hmf)
+ return GenericError;
+
+ status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile);
+ if (status != Ok)
+ DeleteMetaFile(hmf);
+ return status;
+}
+
+static GpStatus decode_image_wmf(IStream *stream, GpImage **image)
{
- IPicture *pic;
+ GpMetafile *metafile;
+ GpStatus status;
TRACE("%p %p\n", stream, image);
- if(!stream || !image)
+ if (!stream || !image)
return InvalidParameter;
- if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture,
- (LPVOID*) &pic) != S_OK){
- TRACE("Could not load picture\n");
+ status = load_wmf(stream, &metafile);
+ if (status != Ok)
+ {
+ TRACE("Could not load metafile\n");
+ return status;
+ }
+
+ *image = (GpImage *)metafile;
+ TRACE("<-- %p\n", *image);
+
+ return Ok;
+}
+
+static GpStatus load_emf(IStream *stream, GpMetafile **metafile)
+{
+ LARGE_INTEGER seek;
+ ENHMETAHEADER emh;
+ HENHMETAFILE hemf;
+ GpStatus status;
+ HRESULT hr;
+ UINT size;
+ void *buf;
+
+ hr = IStream_Read(stream, &emh, sizeof(emh), &size);
+ if (hr != S_OK || size != sizeof(emh) || emh.dSignature != ENHMETA_SIGNATURE)
+ return GenericError;
+
+ seek.QuadPart = 0;
+ hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
+ if (FAILED(hr)) return hresult_to_status(hr);
+
+ buf = heap_alloc(emh.nBytes);
+ if (!buf) return OutOfMemory;
+
+ hr = IStream_Read(stream, buf, emh.nBytes, &size);
+ if (hr != S_OK || size != emh.nBytes)
+ {
+ heap_free(buf);
return GenericError;
}
- /* FIXME: missing initialization code */
- *image = heap_alloc_zero(sizeof(GpMetafile));
- if(!*image) return OutOfMemory;
- (*image)->type = ImageTypeMetafile;
- (*image)->decoder = NULL;
- (*image)->picture = pic;
- (*image)->flags = ImageFlagsNone;
- (*image)->frame_count = 1;
- (*image)->current_frame = 0;
- (*image)->palette = NULL;
- list_init(&(*(GpMetafile**)image)->containers);
+ hemf = SetEnhMetaFileBits(emh.nBytes, buf);
+ heap_free(buf);
+ if (!hemf)
+ return GenericError;
+
+ status = GdipCreateMetafileFromEmf(hemf, TRUE, metafile);
+ if (status != Ok)
+ DeleteEnhMetaFile(hemf);
+ return status;
+}
+
+static GpStatus decode_image_emf(IStream *stream, GpImage **image)
+{
+ GpMetafile *metafile;
+ GpStatus status;
+
+ TRACE("%p %p\n", stream, image);
+
+ if (!stream || !image)
+ return InvalidParameter;
+
+ status = load_emf(stream, &metafile);
+ if (status != Ok)
+ {
+ TRACE("Could not load metafile\n");
+ return status;
+ }
+ *image = (GpImage *)metafile;
TRACE("<-- %p\n", *image);
return Ok;
@@ -4721,7 +4773,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
/* SigMask */ emf_sig_mask,
},
NULL,
- decode_image_olepicture_metafile,
+ decode_image_emf,
NULL
},
{
@@ -4741,7 +4793,7 @@ static const struct image_codec codecs[NUM_CODECS] = {
/* SigMask */ wmf_sig_mask,
},
NULL,
- decode_image_olepicture_metafile,
+ decode_image_wmf,
NULL
},
{
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index 02cacb2..71d89ae 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -324,7 +324,6 @@ GpStatus WINGDIPAPI GdipRecordMetafile(HDC hdc, EmfType type, GDIPCONST GpRectF
}
(*metafile)->image.type = ImageTypeMetafile;
- (*metafile)->image.picture = NULL;
(*metafile)->image.flags = ImageFlagsNone;
(*metafile)->image.palette = NULL;
(*metafile)->image.xres = dpix;
diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c
index ad84feb..cabd2fce 100644
--- a/dlls/gdiplus/tests/image.c
+++ b/dlls/gdiplus/tests/image.c
@@ -1446,19 +1446,19 @@ static void test_loadwmf(void)
stat = GdipGetImageBounds(img, &bounds, &unit);
expect(Ok, stat);
- todo_wine expect(UnitPixel, unit);
+ expect(UnitPixel, unit);
expectf(0.0, bounds.X);
expectf(0.0, bounds.Y);
- todo_wine expectf(320.0, bounds.Width);
- todo_wine expectf(320.0, bounds.Height);
+ expectf(320.0, bounds.Width);
+ expectf(320.0, bounds.Height);
stat = GdipGetImageHorizontalResolution(img, &res);
expect(Ok, stat);
- todo_wine expectf(1440.0, res);
+ expectf(1440.0, res);
stat = GdipGetImageVerticalResolution(img, &res);
expect(Ok, stat);
- todo_wine expectf(1440.0, res);
+ expectf(1440.0, res);
memset(&header, 0, sizeof(header));
stat = GdipGetMetafileHeaderFromMetafile((GpMetafile*)img, &header);
--
2.9.0
More information about the wine-patches
mailing list