diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 53f978c098b..13a63e6ff90 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -58,6 +58,7 @@ extern GpStatus METAFILE_GetGraphicsContext(GpMetafile* metafile, GpGraphics **r extern GpStatus METAFILE_GetDC(GpMetafile* metafile, HDC *hdc) DECLSPEC_HIDDEN; extern GpStatus METAFILE_ReleaseDC(GpMetafile* metafile, HDC hdc) DECLSPEC_HIDDEN; extern GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile) DECLSPEC_HIDDEN; +extern MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf) DECLSPEC_HIDDEN; extern void calc_curve_bezier(CONST GpPointF *pts, REAL tension, REAL *x1, REAL *y1, REAL *x2, REAL *y2) DECLSPEC_HIDDEN; @@ -280,6 +281,7 @@ struct GpMetafile{ GpUnit unit; MetafileType metafile_type; HENHMETAFILE hemf; + int preserve_hemf; /* if true, hemf belongs to the app and should not be deleted */ /* recording */ HDC record_dc; diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 7380c5d0b11..b3eaa86dc68 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -2350,62 +2350,43 @@ GpStatus WINGDIPAPI GdipCreateFromHWNDICM(HWND hwnd, GpGraphics **graphics) GpStatus WINGDIPAPI GdipCreateMetafileFromEmf(HENHMETAFILE hemf, BOOL delete, GpMetafile **metafile) { - IStream *stream = NULL; - UINT read; - ENHMETAHEADER *copy; - GpStatus retval = Ok; + ENHMETAHEADER header; + MetafileType metafile_type; TRACE("(%p,%i,%p)\n", hemf, delete, metafile); if(!hemf || !metafile) return InvalidParameter; - read = GetEnhMetaFileBits(hemf, 0, NULL); - copy = GdipAlloc(read); - GetEnhMetaFileBits(hemf, read, (BYTE *)copy); + if (GetEnhMetaFileHeader(hemf, sizeof(header), &header) == 0) + return GenericError; - if(CreateStreamOnHGlobal(copy, TRUE, &stream) != S_OK){ - ERR("could not make stream\n"); - GdipFree(copy); - retval = GenericError; - goto err; - } + metafile_type = METAFILE_GetEmfType(hemf); + + if (metafile_type == MetafileTypeInvalid) + return GenericError; *metafile = GdipAlloc(sizeof(GpMetafile)); - if(!*metafile){ - retval = OutOfMemory; - goto err; - } - - if(OleLoadPicture(stream, 0, FALSE, &IID_IPicture, - (LPVOID*) &((*metafile)->image.picture)) != S_OK) - { - retval = GenericError; - goto err; - } - + if (!*metafile) + return OutOfMemory; (*metafile)->image.type = ImageTypeMetafile; - memcpy(&(*metafile)->image.format, &ImageFormatWMF, sizeof(GUID)); - (*metafile)->image.palette = NULL; - (*metafile)->image.xres = (REAL)copy->szlDevice.cx; - (*metafile)->image.yres = (REAL)copy->szlDevice.cy; - (*metafile)->bounds.X = (REAL)copy->rclBounds.left; - (*metafile)->bounds.Y = (REAL)copy->rclBounds.top; - (*metafile)->bounds.Width = (REAL)(copy->rclBounds.right - copy->rclBounds.left); - (*metafile)->bounds.Height = (REAL)(copy->rclBounds.bottom - copy->rclBounds.top); + (*metafile)->image.format = ImageFormatEMF; + (*metafile)->image.frame_count = 1; + (*metafile)->image.xres = (REAL)header.szlDevice.cx; + (*metafile)->image.yres = (REAL)header.szlDevice.cy; + (*metafile)->bounds.X = (REAL)header.rclBounds.left; + (*metafile)->bounds.Y = (REAL)header.rclBounds.top; + (*metafile)->bounds.Width = (REAL)(header.rclBounds.right - header.rclBounds.left); + (*metafile)->bounds.Height = (REAL)(header.rclBounds.bottom - header.rclBounds.top); (*metafile)->unit = UnitPixel; - - if(delete) - DeleteEnhMetaFile(hemf); + (*metafile)->metafile_type = metafile_type; + (*metafile)->hemf = hemf; + (*metafile)->preserve_hemf = !delete; TRACE("<-- %p\n", *metafile); -err: - if (retval != Ok) - GdipFree(*metafile); - IStream_Release(stream); - return retval; + return Ok; } GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete, @@ -2431,7 +2412,8 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete, hemf = SetWinMetaFileBits(read, copy, NULL, NULL); GdipFree(copy); - retval = GdipCreateMetafileFromEmf(hemf, FALSE, metafile); + /* FIXME: We should store and use hwmf instead of converting to hemf */ + retval = GdipCreateMetafileFromEmf(hemf, TRUE, metafile); if (retval == Ok) { @@ -2443,9 +2425,13 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete, placeable->BoundingBox.Left); (*metafile)->bounds.Height = (REAL)(placeable->BoundingBox.Bottom - placeable->BoundingBox.Top); + (*metafile)->metafile_type = MetafileTypeWmfPlaceable; + (*metafile)->image.format = ImageFormatWMF; if (delete) DeleteMetaFile(hwmf); } + else + DeleteEnhMetaFile(hemf); return retval; } diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c index 391830149a7..73f08b942b9 100644 --- a/dlls/gdiplus/image.c +++ b/dlls/gdiplus/image.c @@ -2189,7 +2189,8 @@ static GpStatus free_image_data(GpImage *image) GpMetafile *metafile = (GpMetafile*)image; GdipFree(metafile->comment_data); DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc)); - DeleteEnhMetaFile(metafile->hemf); + if (!metafile->preserve_hemf) + DeleteEnhMetaFile(metafile->hemf); if (metafile->record_graphics) { WARN("metafile closed while recording\n"); diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c index 030b2a2e827..4345ece9b90 100644 --- a/dlls/gdiplus/metafile.c +++ b/dlls/gdiplus/metafile.c @@ -548,3 +548,41 @@ GpStatus WINGDIPAPI GdipEnumerateMetafileSrcRectDestPoints(GpGraphics *graphics, return stat; } + +static int CALLBACK get_metafile_type_proc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, + int nObj, LPARAM lpData) +{ + MetafileType *result = (MetafileType*)lpData; + + if (lpEMFR->iType == EMR_GDICOMMENT) + { + const EMRGDICOMMENT *comment = (const EMRGDICOMMENT*)lpEMFR; + + if (comment->cbData >= 4 && memcmp(comment->Data, "EMF+", 4) == 0) + { + const EmfPlusRecordHeader *header = (const EmfPlusRecordHeader*)&comment->Data[4]; + + if (4 + sizeof(EmfPlusRecordHeader) <= comment->cbData && + header->Type == EmfPlusRecordTypeHeader) + { + if ((header->Flags & 1) == 1) + *result = MetafileTypeEmfPlusDual; + else + *result = MetafileTypeEmfPlusOnly; + } + } + else + *result = MetafileTypeEmf; + } + else + *result = MetafileTypeEmf; + + return FALSE; +} + +MetafileType METAFILE_GetEmfType(HENHMETAFILE hemf) +{ + MetafileType result = MetafileTypeInvalid; + EnumEnhMetaFile(NULL, hemf, get_metafile_type_proc, &result, NULL); + return result; +}