From 2f7a2fdea3e832c31ca247948867bfe65df6dd39 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov <dmitry@baikal.ru> Date: Thu, 18 Aug 2016 21:22:02 +0200 Subject: [PATCH] gdiplus: Reimplement metafile loading using gdi32 instead of IPicture. Signed-off-by: Dmitry Timoshkov <dmitry@baikal.ru> Signed-off-by: Sebastian Lackner <sebastian@fds-team.de> Signed-off-by: Vincent Povirk <vincent@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org> --- 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 6495eb70b72..ac12bd1c613 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 678daed5154..216dd4ae1eb 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 84afee11367..14b9db94f37 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 c3f6a5e73d3..74fad29e3a9 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 02cacb2dd48..71d89ae9999 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 ad84feb5772..cabd2fce45e 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); -- GitLab