2 * Copyright (C) 2011 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "gdiplus_private.h"
21 typedef struct EmfPlusRecordHeader
27 } EmfPlusRecordHeader
;
29 typedef struct EmfPlusHeader
31 EmfPlusRecordHeader Header
;
38 typedef struct EmfPlusFillRects
40 EmfPlusRecordHeader Header
;
45 typedef struct EmfPlusSetPageTransform
47 EmfPlusRecordHeader Header
;
49 } EmfPlusSetPageTransform
;
51 typedef struct EmfPlusRect
59 static GpStatus
METAFILE_AllocateRecord(GpMetafile
*metafile
, DWORD size
, void **result
)
62 EmfPlusRecordHeader
*record
;
64 if (!metafile
->comment_data_size
)
66 DWORD data_size
= max(256, size
* 2 + 4);
67 metafile
->comment_data
= GdipAlloc(data_size
);
69 if (!metafile
->comment_data
)
72 memcpy(metafile
->comment_data
, "EMF+", 4);
74 metafile
->comment_data_size
= data_size
;
75 metafile
->comment_data_length
= 4;
78 size_needed
= size
+ metafile
->comment_data_length
;
80 if (size_needed
> metafile
->comment_data_size
)
82 DWORD data_size
= size_needed
* 2;
83 BYTE
*new_data
= GdipAlloc(data_size
);
88 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
90 metafile
->comment_data_size
= data_size
;
91 GdipFree(metafile
->comment_data
);
92 metafile
->comment_data
= new_data
;
95 *result
= metafile
->comment_data
+ metafile
->comment_data_length
;
96 metafile
->comment_data_length
+= size
;
98 record
= (EmfPlusRecordHeader
*)*result
;
100 record
->DataSize
= size
- sizeof(EmfPlusRecordHeader
);
105 static void METAFILE_WriteRecords(GpMetafile
*metafile
)
107 if (metafile
->comment_data_length
> 4)
109 GdiComment(metafile
->record_dc
, metafile
->comment_data_length
, metafile
->comment_data
);
110 metafile
->comment_data_length
= 4;
114 static GpStatus
METAFILE_WriteHeader(GpMetafile
*metafile
, HDC hdc
)
118 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
120 EmfPlusHeader
*header
;
122 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusHeader
), (void**)&header
);
126 header
->Header
.Type
= EmfPlusRecordTypeHeader
;
128 if (metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
129 header
->Header
.Flags
= 1;
131 header
->Header
.Flags
= 0;
133 header
->Version
= 0xDBC01002;
135 if (GetDeviceCaps(hdc
, TECHNOLOGY
) == DT_RASDISPLAY
)
136 header
->EmfPlusFlags
= 1;
138 header
->EmfPlusFlags
= 0;
140 header
->LogicalDpiX
= GetDeviceCaps(hdc
, LOGPIXELSX
);
141 header
->LogicalDpiY
= GetDeviceCaps(hdc
, LOGPIXELSY
);
143 METAFILE_WriteRecords(metafile
);
149 static GpStatus
METAFILE_WriteEndOfFile(GpMetafile
*metafile
)
153 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
155 EmfPlusRecordHeader
*record
;
157 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
161 record
->Type
= EmfPlusRecordTypeEndOfFile
;
164 METAFILE_WriteRecords(metafile
);
170 GpStatus WINGDIPAPI
GdipRecordMetafile(HDC hdc
, EmfType type
, GDIPCONST GpRectF
*frameRect
,
171 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
174 REAL framerect_factor_x
, framerect_factor_y
;
178 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
180 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
181 return InvalidParameter
;
185 FIXME("not implemented for NULL rect\n");
186 return NotImplemented
;
191 case MetafileFrameUnitPixel
:
192 framerect_factor_x
= 2540.0 / GetDeviceCaps(hdc
, LOGPIXELSX
);
193 framerect_factor_y
= 2540.0 / GetDeviceCaps(hdc
, LOGPIXELSY
);
195 case MetafileFrameUnitPoint
:
196 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
198 case MetafileFrameUnitInch
:
199 framerect_factor_x
= framerect_factor_y
= 2540.0;
201 case MetafileFrameUnitDocument
:
202 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
204 case MetafileFrameUnitMillimeter
:
205 framerect_factor_x
= framerect_factor_y
= 100.0;
207 case MetafileFrameUnitGdi
:
208 framerect_factor_x
= framerect_factor_y
= 1.0;
211 return InvalidParameter
;
214 rc
.left
= framerect_factor_x
* frameRect
->X
;
215 rc
.top
= framerect_factor_y
* frameRect
->Y
;
216 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
217 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
219 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, &rc
, desc
);
224 *metafile
= GdipAlloc(sizeof(GpMetafile
));
227 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
231 (*metafile
)->image
.type
= ImageTypeMetafile
;
232 (*metafile
)->image
.picture
= NULL
;
233 (*metafile
)->image
.flags
= ImageFlagsNone
;
234 (*metafile
)->image
.palette
= NULL
;
235 (*metafile
)->image
.xres
= 72.0;
236 (*metafile
)->image
.yres
= 72.0;
237 (*metafile
)->bounds
= *frameRect
;
238 (*metafile
)->unit
= frameUnit
;
239 (*metafile
)->metafile_type
= type
;
240 (*metafile
)->record_dc
= record_dc
;
241 (*metafile
)->comment_data
= NULL
;
242 (*metafile
)->comment_data_size
= 0;
243 (*metafile
)->comment_data_length
= 0;
244 (*metafile
)->hemf
= NULL
;
246 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
250 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
259 /*****************************************************************************
260 * GdipRecordMetafileI [GDIPLUS.@]
262 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
263 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
265 GpRectF frameRectF
, *pFrameRectF
;
267 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
271 frameRectF
.X
= frameRect
->X
;
272 frameRectF
.Y
= frameRect
->Y
;
273 frameRectF
.Width
= frameRect
->Width
;
274 frameRectF
.Height
= frameRect
->Height
;
275 pFrameRectF
= &frameRectF
;
280 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
283 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
287 if (!metafile
->record_dc
|| metafile
->record_graphics
)
288 return InvalidParameter
;
290 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
294 *result
= metafile
->record_graphics
;
295 metafile
->record_graphics
->xres
= 96.0;
296 metafile
->record_graphics
->yres
= 96.0;
302 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
304 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
306 EmfPlusRecordHeader
*record
;
309 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
313 record
->Type
= EmfPlusRecordTypeGetDC
;
316 METAFILE_WriteRecords(metafile
);
319 *hdc
= metafile
->record_dc
;
324 static BOOL
is_integer_rect(const GpRectF
*rect
)
326 SHORT x
, y
, width
, height
;
330 height
= rect
->Height
;
331 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
332 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
337 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
338 GDIPCONST GpRectF
* rects
, INT count
)
340 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
342 EmfPlusFillRects
*record
;
344 BOOL integer_rects
= TRUE
;
349 if (brush
->bt
== BrushTypeSolidColor
)
352 brushid
= ((GpSolidFill
*)brush
)->color
;
356 FIXME("brush serialization not implemented\n");
357 return NotImplemented
;
360 for (i
=0; i
<count
; i
++)
362 if (!is_integer_rect(&rects
[i
]))
364 integer_rects
= FALSE
;
372 stat
= METAFILE_AllocateRecord(metafile
,
373 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
378 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
379 record
->Header
.Flags
= flags
;
380 record
->BrushID
= brushid
;
381 record
->Count
= count
;
385 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
386 for (i
=0; i
<count
; i
++)
388 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
389 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
390 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
391 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
395 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
397 METAFILE_WriteRecords(metafile
);
403 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
405 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
407 EmfPlusSetPageTransform
*record
;
410 stat
= METAFILE_AllocateRecord(metafile
,
411 sizeof(EmfPlusSetPageTransform
),
416 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
417 record
->Header
.Flags
= unit
;
418 record
->PageScale
= scale
;
420 METAFILE_WriteRecords(metafile
);
426 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
428 if (hdc
!= metafile
->record_dc
)
429 return InvalidParameter
;
434 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
438 stat
= METAFILE_WriteEndOfFile(metafile
);
439 metafile
->record_graphics
= NULL
;
441 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
442 metafile
->record_dc
= NULL
;
444 GdipFree(metafile
->comment_data
);
445 metafile
->comment_data
= NULL
;
446 metafile
->comment_data_size
= 0;
451 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
453 TRACE("(%p,%p)\n", metafile
, hEmf
);
455 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
456 return InvalidParameter
;
458 *hEmf
= metafile
->hemf
;
459 metafile
->hemf
= NULL
;
464 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
468 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
472 /* The result of GdipGetDC always expects device co-ordinates, but the
473 * device co-ordinates of the source metafile do not correspond to
474 * device co-ordinates of the destination. Therefore, we set up the DC
475 * so that the metafile's bounds map to the destination points where we
476 * are drawing this metafile. */
477 SetMapMode(metafile
->playback_dc
, MM_ANISOTROPIC
);
479 SetWindowOrgEx(metafile
->playback_dc
, metafile
->bounds
.X
, metafile
->bounds
.Y
, NULL
);
480 SetWindowExtEx(metafile
->playback_dc
, metafile
->bounds
.Width
, metafile
->bounds
.Height
, NULL
);
482 SetViewportOrgEx(metafile
->playback_dc
, metafile
->playback_points
[0].X
, metafile
->playback_points
[0].Y
, NULL
);
483 SetViewportExtEx(metafile
->playback_dc
,
484 metafile
->playback_points
[1].X
- metafile
->playback_points
[0].X
,
485 metafile
->playback_points
[2].Y
- metafile
->playback_points
[0].Y
, NULL
);
491 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
493 if (metafile
->playback_dc
)
495 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
496 metafile
->playback_dc
= NULL
;
500 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
502 GpMatrix
*real_transform
;
505 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
509 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
511 if (metafile
->page_unit
!= UnitDisplay
)
512 scale
*= metafile
->page_scale
;
514 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
517 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
520 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
522 GdipDeleteMatrix(real_transform
);
528 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
529 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
532 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
534 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
536 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
537 return InvalidParameter
;
539 if (recordType
>= 1 && recordType
<= 0x7a)
541 /* regular EMF record */
542 if (metafile
->playback_dc
)
544 ENHMETARECORD
*record
;
546 record
= GdipAlloc(dataSize
+ 8);
550 record
->iType
= recordType
;
551 record
->nSize
= dataSize
+ 8;
552 memcpy(record
->dParm
, data
, dataSize
);
554 PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
555 record
, metafile
->handle_count
);
565 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
567 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
571 case EmfPlusRecordTypeHeader
:
572 case EmfPlusRecordTypeEndOfFile
:
574 case EmfPlusRecordTypeGetDC
:
575 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
577 case EmfPlusRecordTypeFillRects
:
579 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
580 GpBrush
*brush
, *temp_brush
=NULL
;
581 GpRectF
*rects
, *temp_rects
=NULL
;
583 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
584 return InvalidParameter
;
588 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
589 return InvalidParameter
;
593 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
594 return InvalidParameter
;
599 stat
= GdipCreateSolidFill((ARGB
)record
->BrushID
, (GpSolidFill
**)&temp_brush
);
604 FIXME("brush deserialization not implemented\n");
605 return NotImplemented
;
612 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
615 rects
= temp_rects
= GdipAlloc(sizeof(GpRectF
) * record
->Count
);
618 for (i
=0; i
<record
->Count
; i
++)
620 rects
[i
].X
= int_rects
[i
].X
;
621 rects
[i
].Y
= int_rects
[i
].Y
;
622 rects
[i
].Width
= int_rects
[i
].Width
;
623 rects
[i
].Height
= int_rects
[i
].Height
;
630 rects
= (GpRectF
*)(record
+1);
635 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
638 GdipDeleteBrush(temp_brush
);
639 GdipFree(temp_rects
);
643 case EmfPlusRecordTypeSetPageTransform
:
645 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
646 GpUnit unit
= (GpUnit
)flags
;
648 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
649 return InvalidParameter
;
651 real_metafile
->page_unit
= unit
;
652 real_metafile
->page_scale
= record
->PageScale
;
654 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
657 FIXME("Not implemented for record type %x\n", recordType
);
658 return NotImplemented
;
665 struct enum_metafile_data
667 EnumerateMetafileProc callback
;
669 GpMetafile
*metafile
;
672 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
673 int nObj
, LPARAM lpData
)
676 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
679 data
->metafile
->handle_table
= lpHTable
;
680 data
->metafile
->handle_count
= nObj
;
682 /* First check for an EMF+ record. */
683 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
685 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
687 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
691 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
693 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
695 if (record
->DataSize
)
696 pStr
= (const BYTE
*)(record
+1);
700 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
701 pStr
, data
->callback_data
);
706 offset
+= record
->Size
;
713 if (lpEMFR
->nSize
!= 8)
714 pStr
= (const BYTE
*)lpEMFR
->dParm
;
718 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
719 pStr
, data
->callback_data
);
722 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
723 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
724 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
725 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
727 struct enum_metafile_data data
;
729 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
730 GraphicsContainer state
;
732 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
733 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
736 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
737 return InvalidParameter
;
740 return InvalidParameter
;
742 if (metafile
->playback_graphics
)
745 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
746 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
747 debugstr_pointf(&destPoints
[2]));
749 data
.callback
= callback
;
750 data
.callback_data
= callbackData
;
751 data
.metafile
= real_metafile
;
753 real_metafile
->playback_graphics
= graphics
;
754 real_metafile
->playback_dc
= NULL
;
755 real_metafile
->src_rect
= *srcRect
;
757 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
758 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
761 stat
= GdipBeginContainer2(graphics
, &state
);
765 stat
= GdipSetPageScale(graphics
, 1.0);
768 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
771 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
775 real_metafile
->page_unit
= UnitDisplay
;
776 real_metafile
->page_scale
= 1.0;
777 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
780 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
781 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
782 metafile
->metafile_type
== MetafileTypeWmf
))
783 stat
= METAFILE_PlaybackGetDC(real_metafile
);
786 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
788 METAFILE_PlaybackReleaseDC(real_metafile
);
790 GdipDeleteMatrix(real_metafile
->world_transform
);
791 real_metafile
->world_transform
= NULL
;
793 GdipEndContainer(graphics
, state
);
796 real_metafile
->playback_graphics
= NULL
;
801 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
802 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
803 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
807 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
809 points
[0].X
= points
[2].X
= dest
->X
;
810 points
[0].Y
= points
[1].Y
= dest
->Y
;
811 points
[1].X
= dest
->X
+ dest
->Width
;
812 points
[2].Y
= dest
->Y
+ dest
->Height
;
814 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
815 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
818 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
819 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
820 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
824 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
828 destf
.Width
= dest
->Width
;
829 destf
.Height
= dest
->Height
;
831 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
834 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
835 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
836 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
840 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
844 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
845 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
847 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
850 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
851 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
852 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
856 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
861 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
864 static int CALLBACK
get_metafile_type_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
865 int nObj
, LPARAM lpData
)
867 MetafileType
*result
= (MetafileType
*)lpData
;
869 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
871 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
873 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
875 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
877 if (4 + sizeof(EmfPlusRecordHeader
) <= comment
->cbData
&&
878 header
->Type
== EmfPlusRecordTypeHeader
)
880 if ((header
->Flags
& 1) == 1)
881 *result
= MetafileTypeEmfPlusDual
;
883 *result
= MetafileTypeEmfPlusOnly
;
887 *result
= MetafileTypeEmf
;
890 *result
= MetafileTypeEmf
;
895 static MetafileType
METAFILE_GetEmfType(HENHMETAFILE hemf
)
897 MetafileType result
= MetafileTypeInvalid
;
898 EnumEnhMetaFile(NULL
, hemf
, get_metafile_type_proc
, &result
, NULL
);
902 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
903 MetafileHeader
* header
)
907 TRACE("(%p, %p)\n", metafile
, header
);
909 if(!metafile
|| !header
)
910 return InvalidParameter
;
913 FIXME("not implemented\n");
915 memset(header
, 0, sizeof(MetafileHeader
));
920 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hEmf
,
921 MetafileHeader
*header
)
926 return InvalidParameter
;
929 FIXME("not implemented\n");
931 memset(header
, 0, sizeof(MetafileHeader
));
936 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
937 MetafileHeader
*header
)
941 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
943 if(!filename
|| !header
)
944 return InvalidParameter
;
947 FIXME("not implemented\n");
949 memset(header
, 0, sizeof(MetafileHeader
));
954 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
955 MetafileHeader
*header
)
959 TRACE("(%p,%p)\n", stream
, header
);
961 if(!stream
|| !header
)
962 return InvalidParameter
;
965 FIXME("not implemented\n");
967 memset(header
, 0, sizeof(MetafileHeader
));
972 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
973 GpMetafile
**metafile
)
975 ENHMETAHEADER header
;
976 MetafileType metafile_type
;
978 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
980 if(!hemf
|| !metafile
)
981 return InvalidParameter
;
983 if (GetEnhMetaFileHeader(hemf
, sizeof(header
), &header
) == 0)
986 metafile_type
= METAFILE_GetEmfType(hemf
);
988 if (metafile_type
== MetafileTypeInvalid
)
991 *metafile
= GdipAlloc(sizeof(GpMetafile
));
995 (*metafile
)->image
.type
= ImageTypeMetafile
;
996 (*metafile
)->image
.format
= ImageFormatEMF
;
997 (*metafile
)->image
.frame_count
= 1;
998 (*metafile
)->image
.xres
= (REAL
)header
.szlDevice
.cx
;
999 (*metafile
)->image
.yres
= (REAL
)header
.szlDevice
.cy
;
1000 (*metafile
)->bounds
.X
= (REAL
)header
.rclBounds
.left
;
1001 (*metafile
)->bounds
.Y
= (REAL
)header
.rclBounds
.top
;
1002 (*metafile
)->bounds
.Width
= (REAL
)(header
.rclBounds
.right
- header
.rclBounds
.left
);
1003 (*metafile
)->bounds
.Height
= (REAL
)(header
.rclBounds
.bottom
- header
.rclBounds
.top
);
1004 (*metafile
)->unit
= UnitPixel
;
1005 (*metafile
)->metafile_type
= metafile_type
;
1006 (*metafile
)->hemf
= hemf
;
1007 (*metafile
)->preserve_hemf
= !delete;
1009 TRACE("<-- %p\n", *metafile
);
1014 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
1015 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1020 GpStatus retval
= Ok
;
1022 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
1024 if(!hwmf
|| !metafile
|| !placeable
)
1025 return InvalidParameter
;
1028 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
1030 return GenericError
;
1031 copy
= GdipAlloc(read
);
1032 GetMetaFileBitsEx(hwmf
, read
, copy
);
1034 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
1037 /* FIXME: We should store and use hwmf instead of converting to hemf */
1038 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
1042 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
1043 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
1044 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
1045 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
1046 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
1047 placeable
->BoundingBox
.Left
);
1048 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
1049 placeable
->BoundingBox
.Top
);
1050 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
1051 (*metafile
)->image
.format
= ImageFormatWMF
;
1053 if (delete) DeleteMetaFile(hwmf
);
1056 DeleteEnhMetaFile(hemf
);
1060 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
1061 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1063 HMETAFILE hmf
= GetMetaFileW(file
);
1065 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
1067 if(!hmf
) return InvalidParameter
;
1069 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
1072 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
1073 GpMetafile
**metafile
)
1075 FIXME("(%p, %p): stub\n", file
, metafile
);
1076 return NotImplemented
;
1079 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
1080 GpMetafile
**metafile
)
1082 FIXME("(%p, %p): stub\n", stream
, metafile
);
1083 return NotImplemented
;
1086 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
1091 TRACE("(%p,%u)\n", metafile
, limitDpi
);
1094 FIXME("not implemented\n");
1096 return NotImplemented
;
1099 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
1100 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
1101 const WCHAR
* description
, GpMetafile
** out_metafile
)
1105 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
1106 debugstr_w(description
), out_metafile
);
1108 if(!ref
|| !metafile
|| !out_metafile
)
1109 return InvalidParameter
;
1112 *out_metafile
= NULL
;
1115 FIXME("not implemented\n");
1117 return NotImplemented
;
1120 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
1121 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
1123 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
1124 return NotImplemented
;
1127 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
1128 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
1129 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
1130 GpMetafile
**metafile
)
1132 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1133 frameUnit
, debugstr_w(desc
), metafile
);
1135 return NotImplemented
;
1138 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
1139 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
1140 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
1142 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1143 frameUnit
, debugstr_w(desc
), metafile
);
1145 return NotImplemented
;
1148 /*****************************************************************************
1149 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
1152 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
1153 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
1154 const WCHAR
* filename
, EmfType emfType
,
1155 const WCHAR
* description
, GpMetafile
** out_metafile
)
1157 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
1158 return NotImplemented
;