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
= heap_alloc_zero(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
= heap_alloc_zero(data_size
);
88 memcpy(new_data
, metafile
->comment_data
, metafile
->comment_data_length
);
90 metafile
->comment_data_size
= data_size
;
91 heap_free(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
)
175 REAL framerect_factor_x
, framerect_factor_y
;
179 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
181 if (!hdc
|| type
< EmfTypeEmfOnly
|| type
> EmfTypeEmfPlusDual
|| !metafile
)
182 return InvalidParameter
;
186 FIXME("not implemented for NULL rect\n");
187 return NotImplemented
;
190 dpix
= (REAL
)GetDeviceCaps(hdc
, HORZRES
) / GetDeviceCaps(hdc
, HORZSIZE
) * 25.4;
191 dpiy
= (REAL
)GetDeviceCaps(hdc
, VERTRES
) / GetDeviceCaps(hdc
, VERTSIZE
) * 25.4;
195 case MetafileFrameUnitPixel
:
196 framerect_factor_x
= 2540.0 / dpix
;
197 framerect_factor_y
= 2540.0 / dpiy
;
199 case MetafileFrameUnitPoint
:
200 framerect_factor_x
= framerect_factor_y
= 2540.0 / 72.0;
202 case MetafileFrameUnitInch
:
203 framerect_factor_x
= framerect_factor_y
= 2540.0;
205 case MetafileFrameUnitDocument
:
206 framerect_factor_x
= framerect_factor_y
= 2540.0 / 300.0;
208 case MetafileFrameUnitMillimeter
:
209 framerect_factor_x
= framerect_factor_y
= 100.0;
211 case MetafileFrameUnitGdi
:
212 framerect_factor_x
= framerect_factor_y
= 1.0;
215 return InvalidParameter
;
218 rc
.left
= framerect_factor_x
* frameRect
->X
;
219 rc
.top
= framerect_factor_y
* frameRect
->Y
;
220 rc
.right
= rc
.left
+ framerect_factor_x
* frameRect
->Width
;
221 rc
.bottom
= rc
.top
+ framerect_factor_y
* frameRect
->Height
;
223 record_dc
= CreateEnhMetaFileW(hdc
, NULL
, &rc
, desc
);
228 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
231 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
235 (*metafile
)->image
.type
= ImageTypeMetafile
;
236 (*metafile
)->image
.picture
= NULL
;
237 (*metafile
)->image
.flags
= ImageFlagsNone
;
238 (*metafile
)->image
.palette
= NULL
;
239 (*metafile
)->image
.xres
= dpix
;
240 (*metafile
)->image
.yres
= dpiy
;
241 (*metafile
)->bounds
= *frameRect
;
242 (*metafile
)->unit
= frameUnit
;
243 (*metafile
)->metafile_type
= type
;
244 (*metafile
)->record_dc
= record_dc
;
245 (*metafile
)->comment_data
= NULL
;
246 (*metafile
)->comment_data_size
= 0;
247 (*metafile
)->comment_data_length
= 0;
248 (*metafile
)->hemf
= NULL
;
250 stat
= METAFILE_WriteHeader(*metafile
, hdc
);
254 DeleteEnhMetaFile(CloseEnhMetaFile(record_dc
));
255 heap_free(*metafile
);
263 /*****************************************************************************
264 * GdipRecordMetafileI [GDIPLUS.@]
266 GpStatus WINGDIPAPI
GdipRecordMetafileI(HDC hdc
, EmfType type
, GDIPCONST GpRect
*frameRect
,
267 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
269 GpRectF frameRectF
, *pFrameRectF
;
271 TRACE("(%p %d %p %d %p %p)\n", hdc
, type
, frameRect
, frameUnit
, desc
, metafile
);
275 frameRectF
.X
= frameRect
->X
;
276 frameRectF
.Y
= frameRect
->Y
;
277 frameRectF
.Width
= frameRect
->Width
;
278 frameRectF
.Height
= frameRect
->Height
;
279 pFrameRectF
= &frameRectF
;
284 return GdipRecordMetafile(hdc
, type
, pFrameRectF
, frameUnit
, desc
, metafile
);
287 GpStatus
METAFILE_GetGraphicsContext(GpMetafile
* metafile
, GpGraphics
**result
)
291 if (!metafile
->record_dc
|| metafile
->record_graphics
)
292 return InvalidParameter
;
294 stat
= graphics_from_image((GpImage
*)metafile
, &metafile
->record_graphics
);
298 *result
= metafile
->record_graphics
;
299 metafile
->record_graphics
->xres
= 96.0;
300 metafile
->record_graphics
->yres
= 96.0;
306 GpStatus
METAFILE_GetDC(GpMetafile
* metafile
, HDC
*hdc
)
308 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
310 EmfPlusRecordHeader
*record
;
313 stat
= METAFILE_AllocateRecord(metafile
, sizeof(EmfPlusRecordHeader
), (void**)&record
);
317 record
->Type
= EmfPlusRecordTypeGetDC
;
320 METAFILE_WriteRecords(metafile
);
323 *hdc
= metafile
->record_dc
;
328 static BOOL
is_integer_rect(const GpRectF
*rect
)
330 SHORT x
, y
, width
, height
;
334 height
= rect
->Height
;
335 if (rect
->X
!= (REAL
)x
|| rect
->Y
!= (REAL
)y
||
336 rect
->Width
!= (REAL
)width
|| rect
->Height
!= (REAL
)height
)
341 GpStatus
METAFILE_FillRectangles(GpMetafile
* metafile
, GpBrush
* brush
,
342 GDIPCONST GpRectF
* rects
, INT count
)
344 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
346 EmfPlusFillRects
*record
;
348 BOOL integer_rects
= TRUE
;
353 if (brush
->bt
== BrushTypeSolidColor
)
356 brushid
= ((GpSolidFill
*)brush
)->color
;
360 FIXME("brush serialization not implemented\n");
361 return NotImplemented
;
364 for (i
=0; i
<count
; i
++)
366 if (!is_integer_rect(&rects
[i
]))
368 integer_rects
= FALSE
;
376 stat
= METAFILE_AllocateRecord(metafile
,
377 sizeof(EmfPlusFillRects
) + count
* (integer_rects
? sizeof(EmfPlusRect
) : sizeof(GpRectF
)),
382 record
->Header
.Type
= EmfPlusRecordTypeFillRects
;
383 record
->Header
.Flags
= flags
;
384 record
->BrushID
= brushid
;
385 record
->Count
= count
;
389 EmfPlusRect
*record_rects
= (EmfPlusRect
*)(record
+1);
390 for (i
=0; i
<count
; i
++)
392 record_rects
[i
].X
= (SHORT
)rects
[i
].X
;
393 record_rects
[i
].Y
= (SHORT
)rects
[i
].Y
;
394 record_rects
[i
].Width
= (SHORT
)rects
[i
].Width
;
395 record_rects
[i
].Height
= (SHORT
)rects
[i
].Height
;
399 memcpy(record
+1, rects
, sizeof(GpRectF
) * count
);
401 METAFILE_WriteRecords(metafile
);
407 GpStatus
METAFILE_SetPageTransform(GpMetafile
* metafile
, GpUnit unit
, REAL scale
)
409 if (metafile
->metafile_type
== MetafileTypeEmfPlusOnly
|| metafile
->metafile_type
== MetafileTypeEmfPlusDual
)
411 EmfPlusSetPageTransform
*record
;
414 stat
= METAFILE_AllocateRecord(metafile
,
415 sizeof(EmfPlusSetPageTransform
),
420 record
->Header
.Type
= EmfPlusRecordTypeSetPageTransform
;
421 record
->Header
.Flags
= unit
;
422 record
->PageScale
= scale
;
424 METAFILE_WriteRecords(metafile
);
430 GpStatus
METAFILE_ReleaseDC(GpMetafile
* metafile
, HDC hdc
)
432 if (hdc
!= metafile
->record_dc
)
433 return InvalidParameter
;
438 GpStatus
METAFILE_GraphicsDeleted(GpMetafile
* metafile
)
442 stat
= METAFILE_WriteEndOfFile(metafile
);
443 metafile
->record_graphics
= NULL
;
445 metafile
->hemf
= CloseEnhMetaFile(metafile
->record_dc
);
446 metafile
->record_dc
= NULL
;
448 heap_free(metafile
->comment_data
);
449 metafile
->comment_data
= NULL
;
450 metafile
->comment_data_size
= 0;
455 GpStatus WINGDIPAPI
GdipGetHemfFromMetafile(GpMetafile
*metafile
, HENHMETAFILE
*hEmf
)
457 TRACE("(%p,%p)\n", metafile
, hEmf
);
459 if (!metafile
|| !hEmf
|| !metafile
->hemf
)
460 return InvalidParameter
;
462 *hEmf
= metafile
->hemf
;
463 metafile
->hemf
= NULL
;
468 static GpStatus
METAFILE_PlaybackGetDC(GpMetafile
*metafile
)
472 stat
= GdipGetDC(metafile
->playback_graphics
, &metafile
->playback_dc
);
476 /* The result of GdipGetDC always expects device co-ordinates, but the
477 * device co-ordinates of the source metafile do not correspond to
478 * device co-ordinates of the destination. Therefore, we set up the DC
479 * so that the metafile's bounds map to the destination points where we
480 * are drawing this metafile. */
481 SetMapMode(metafile
->playback_dc
, MM_ANISOTROPIC
);
483 SetWindowOrgEx(metafile
->playback_dc
, metafile
->bounds
.X
, metafile
->bounds
.Y
, NULL
);
484 SetWindowExtEx(metafile
->playback_dc
, metafile
->bounds
.Width
, metafile
->bounds
.Height
, NULL
);
486 SetViewportOrgEx(metafile
->playback_dc
, metafile
->playback_points
[0].X
, metafile
->playback_points
[0].Y
, NULL
);
487 SetViewportExtEx(metafile
->playback_dc
,
488 metafile
->playback_points
[1].X
- metafile
->playback_points
[0].X
,
489 metafile
->playback_points
[2].Y
- metafile
->playback_points
[0].Y
, NULL
);
495 static void METAFILE_PlaybackReleaseDC(GpMetafile
*metafile
)
497 if (metafile
->playback_dc
)
499 GdipReleaseDC(metafile
->playback_graphics
, metafile
->playback_dc
);
500 metafile
->playback_dc
= NULL
;
504 static GpStatus
METAFILE_PlaybackUpdateWorldTransform(GpMetafile
*metafile
)
506 GpMatrix
*real_transform
;
509 stat
= GdipCreateMatrix3(&metafile
->src_rect
, metafile
->playback_points
, &real_transform
);
513 REAL scale
= units_to_pixels(1.0, metafile
->page_unit
, 96.0);
515 if (metafile
->page_unit
!= UnitDisplay
)
516 scale
*= metafile
->page_scale
;
518 stat
= GdipScaleMatrix(real_transform
, scale
, scale
, MatrixOrderPrepend
);
521 stat
= GdipMultiplyMatrix(real_transform
, metafile
->world_transform
, MatrixOrderPrepend
);
524 stat
= GdipSetWorldTransform(metafile
->playback_graphics
, real_transform
);
526 GdipDeleteMatrix(real_transform
);
532 GpStatus WINGDIPAPI
GdipPlayMetafileRecord(GDIPCONST GpMetafile
*metafile
,
533 EmfPlusRecordType recordType
, UINT flags
, UINT dataSize
, GDIPCONST BYTE
*data
)
536 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
;
538 TRACE("(%p,%x,%x,%d,%p)\n", metafile
, recordType
, flags
, dataSize
, data
);
540 if (!metafile
|| (dataSize
&& !data
) || !metafile
->playback_graphics
)
541 return InvalidParameter
;
543 if (recordType
>= 1 && recordType
<= 0x7a)
545 /* regular EMF record */
546 if (metafile
->playback_dc
)
548 ENHMETARECORD
*record
;
550 record
= heap_alloc_zero(dataSize
+ 8);
554 record
->iType
= recordType
;
555 record
->nSize
= dataSize
+ 8;
556 memcpy(record
->dParm
, data
, dataSize
);
558 PlayEnhMetaFileRecord(metafile
->playback_dc
, metafile
->handle_table
,
559 record
, metafile
->handle_count
);
569 EmfPlusRecordHeader
*header
= (EmfPlusRecordHeader
*)(data
)-1;
571 METAFILE_PlaybackReleaseDC((GpMetafile
*)metafile
);
575 case EmfPlusRecordTypeHeader
:
576 case EmfPlusRecordTypeEndOfFile
:
578 case EmfPlusRecordTypeGetDC
:
579 METAFILE_PlaybackGetDC((GpMetafile
*)metafile
);
581 case EmfPlusRecordTypeFillRects
:
583 EmfPlusFillRects
*record
= (EmfPlusFillRects
*)header
;
584 GpBrush
*brush
, *temp_brush
=NULL
;
585 GpRectF
*rects
, *temp_rects
=NULL
;
587 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
))
588 return InvalidParameter
;
592 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(EmfPlusRect
) * record
->Count
)
593 return InvalidParameter
;
597 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusFillRects
) + sizeof(GpRectF
) * record
->Count
)
598 return InvalidParameter
;
603 stat
= GdipCreateSolidFill((ARGB
)record
->BrushID
, (GpSolidFill
**)&temp_brush
);
608 FIXME("brush deserialization not implemented\n");
609 return NotImplemented
;
616 EmfPlusRect
*int_rects
= (EmfPlusRect
*)(record
+1);
619 rects
= temp_rects
= heap_alloc_zero(sizeof(GpRectF
) * record
->Count
);
622 for (i
=0; i
<record
->Count
; i
++)
624 rects
[i
].X
= int_rects
[i
].X
;
625 rects
[i
].Y
= int_rects
[i
].Y
;
626 rects
[i
].Width
= int_rects
[i
].Width
;
627 rects
[i
].Height
= int_rects
[i
].Height
;
634 rects
= (GpRectF
*)(record
+1);
639 stat
= GdipFillRectangles(metafile
->playback_graphics
, brush
, rects
, record
->Count
);
642 GdipDeleteBrush(temp_brush
);
643 heap_free(temp_rects
);
647 case EmfPlusRecordTypeSetPageTransform
:
649 EmfPlusSetPageTransform
*record
= (EmfPlusSetPageTransform
*)header
;
650 GpUnit unit
= (GpUnit
)flags
;
652 if (dataSize
+ sizeof(EmfPlusRecordHeader
) < sizeof(EmfPlusSetPageTransform
))
653 return InvalidParameter
;
655 real_metafile
->page_unit
= unit
;
656 real_metafile
->page_scale
= record
->PageScale
;
658 return METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
661 FIXME("Not implemented for record type %x\n", recordType
);
662 return NotImplemented
;
669 struct enum_metafile_data
671 EnumerateMetafileProc callback
;
673 GpMetafile
*metafile
;
676 static int CALLBACK
enum_metafile_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
677 int nObj
, LPARAM lpData
)
680 struct enum_metafile_data
*data
= (struct enum_metafile_data
*)lpData
;
683 data
->metafile
->handle_table
= lpHTable
;
684 data
->metafile
->handle_count
= nObj
;
686 /* First check for an EMF+ record. */
687 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
689 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
691 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
695 while (offset
+ sizeof(EmfPlusRecordHeader
) <= comment
->cbData
)
697 const EmfPlusRecordHeader
*record
= (const EmfPlusRecordHeader
*)&comment
->Data
[offset
];
699 if (record
->DataSize
)
700 pStr
= (const BYTE
*)(record
+1);
704 ret
= data
->callback(record
->Type
, record
->Flags
, record
->DataSize
,
705 pStr
, data
->callback_data
);
710 offset
+= record
->Size
;
717 if (lpEMFR
->nSize
!= 8)
718 pStr
= (const BYTE
*)lpEMFR
->dParm
;
722 return data
->callback(lpEMFR
->iType
, 0, lpEMFR
->nSize
-8,
723 pStr
, data
->callback_data
);
726 GpStatus WINGDIPAPI
GdipEnumerateMetafileSrcRectDestPoints(GpGraphics
*graphics
,
727 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*destPoints
, INT count
,
728 GDIPCONST GpRectF
*srcRect
, Unit srcUnit
, EnumerateMetafileProc callback
,
729 VOID
*callbackData
, GDIPCONST GpImageAttributes
*imageAttributes
)
731 struct enum_metafile_data data
;
733 GpMetafile
*real_metafile
= (GpMetafile
*)metafile
; /* whoever made this const was joking */
734 GraphicsContainer state
;
736 TRACE("(%p,%p,%p,%i,%p,%i,%p,%p,%p)\n", graphics
, metafile
,
737 destPoints
, count
, srcRect
, srcUnit
, callback
, callbackData
,
740 if (!graphics
|| !metafile
|| !destPoints
|| count
!= 3 || !srcRect
)
741 return InvalidParameter
;
744 return InvalidParameter
;
746 if (metafile
->playback_graphics
)
749 TRACE("%s %i -> %s %s %s\n", debugstr_rectf(srcRect
), srcUnit
,
750 debugstr_pointf(&destPoints
[0]), debugstr_pointf(&destPoints
[1]),
751 debugstr_pointf(&destPoints
[2]));
753 data
.callback
= callback
;
754 data
.callback_data
= callbackData
;
755 data
.metafile
= real_metafile
;
757 real_metafile
->playback_graphics
= graphics
;
758 real_metafile
->playback_dc
= NULL
;
759 real_metafile
->src_rect
= *srcRect
;
761 memcpy(real_metafile
->playback_points
, destPoints
, sizeof(PointF
) * 3);
762 stat
= GdipTransformPoints(graphics
, CoordinateSpaceDevice
, CoordinateSpaceWorld
, real_metafile
->playback_points
, 3);
765 stat
= GdipBeginContainer2(graphics
, &state
);
769 stat
= GdipSetPageScale(graphics
, 1.0);
772 stat
= GdipSetPageUnit(graphics
, UnitPixel
);
775 stat
= GdipCreateMatrix(&real_metafile
->world_transform
);
779 real_metafile
->page_unit
= UnitDisplay
;
780 real_metafile
->page_scale
= 1.0;
781 stat
= METAFILE_PlaybackUpdateWorldTransform(real_metafile
);
784 if (stat
== Ok
&& (metafile
->metafile_type
== MetafileTypeEmf
||
785 metafile
->metafile_type
== MetafileTypeWmfPlaceable
||
786 metafile
->metafile_type
== MetafileTypeWmf
))
787 stat
= METAFILE_PlaybackGetDC(real_metafile
);
790 EnumEnhMetaFile(0, metafile
->hemf
, enum_metafile_proc
, &data
, NULL
);
792 METAFILE_PlaybackReleaseDC(real_metafile
);
794 GdipDeleteMatrix(real_metafile
->world_transform
);
795 real_metafile
->world_transform
= NULL
;
797 GdipEndContainer(graphics
, state
);
800 real_metafile
->playback_graphics
= NULL
;
805 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRect(GpGraphics
*graphics
,
806 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRectF
*dest
,
807 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
811 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
813 points
[0].X
= points
[2].X
= dest
->X
;
814 points
[0].Y
= points
[1].Y
= dest
->Y
;
815 points
[1].X
= dest
->X
+ dest
->Width
;
816 points
[2].Y
= dest
->Y
+ dest
->Height
;
818 return GdipEnumerateMetafileSrcRectDestPoints(graphics
, metafile
, points
, 3,
819 &metafile
->bounds
, metafile
->unit
, callback
, cb_data
, attrs
);
822 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestRectI(GpGraphics
*graphics
,
823 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpRect
*dest
,
824 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
828 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
832 destf
.Width
= dest
->Width
;
833 destf
.Height
= dest
->Height
;
835 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
838 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPoint(GpGraphics
*graphics
,
839 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPointF
*dest
,
840 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
844 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
848 destf
.Width
= units_to_pixels(metafile
->bounds
.Width
, metafile
->unit
, metafile
->image
.xres
);
849 destf
.Height
= units_to_pixels(metafile
->bounds
.Height
, metafile
->unit
, metafile
->image
.yres
);
851 return GdipEnumerateMetafileDestRect(graphics
, metafile
, &destf
, callback
, cb_data
, attrs
);
854 GpStatus WINGDIPAPI
GdipEnumerateMetafileDestPointI(GpGraphics
*graphics
,
855 GDIPCONST GpMetafile
*metafile
, GDIPCONST GpPoint
*dest
,
856 EnumerateMetafileProc callback
, VOID
*cb_data
, GDIPCONST GpImageAttributes
*attrs
)
860 if (!graphics
|| !metafile
|| !dest
) return InvalidParameter
;
865 return GdipEnumerateMetafileDestPoint(graphics
, metafile
, &ptf
, callback
, cb_data
, attrs
);
868 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromMetafile(GpMetafile
* metafile
,
869 MetafileHeader
* header
)
873 TRACE("(%p, %p)\n", metafile
, header
);
875 if(!metafile
|| !header
)
876 return InvalidParameter
;
879 FIXME("not implemented\n");
881 memset(header
, 0, sizeof(MetafileHeader
));
886 static int CALLBACK
get_emfplus_header_proc(HDC hDC
, HANDLETABLE
*lpHTable
, const ENHMETARECORD
*lpEMFR
,
887 int nObj
, LPARAM lpData
)
889 EmfPlusHeader
*dst_header
= (EmfPlusHeader
*)lpData
;
891 if (lpEMFR
->iType
== EMR_GDICOMMENT
)
893 const EMRGDICOMMENT
*comment
= (const EMRGDICOMMENT
*)lpEMFR
;
895 if (comment
->cbData
>= 4 && memcmp(comment
->Data
, "EMF+", 4) == 0)
897 const EmfPlusRecordHeader
*header
= (const EmfPlusRecordHeader
*)&comment
->Data
[4];
899 if (4 + sizeof(EmfPlusHeader
) <= comment
->cbData
&&
900 header
->Type
== EmfPlusRecordTypeHeader
)
902 memcpy(dst_header
, header
, sizeof(*dst_header
));
906 else if (lpEMFR
->iType
== EMR_HEADER
)
912 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromEmf(HENHMETAFILE hemf
,
913 MetafileHeader
*header
)
915 ENHMETAHEADER3 emfheader
;
916 EmfPlusHeader emfplusheader
;
917 MetafileType metafile_type
;
919 TRACE("(%p,%p)\n", hemf
, header
);
922 return InvalidParameter
;
924 if (GetEnhMetaFileHeader(hemf
, sizeof(emfheader
), (ENHMETAHEADER
*)&emfheader
) == 0)
927 emfplusheader
.Header
.Type
= 0;
929 EnumEnhMetaFile(NULL
, hemf
, get_emfplus_header_proc
, &emfplusheader
, NULL
);
931 if (emfplusheader
.Header
.Type
== EmfPlusRecordTypeHeader
)
933 if ((emfplusheader
.Header
.Flags
& 1) == 1)
934 metafile_type
= MetafileTypeEmfPlusDual
;
936 metafile_type
= MetafileTypeEmfPlusOnly
;
939 metafile_type
= MetafileTypeEmf
;
941 header
->Type
= metafile_type
;
942 header
->Size
= emfheader
.nBytes
;
943 header
->DpiX
= (REAL
)emfheader
.szlDevice
.cx
* 25.4 / emfheader
.szlMillimeters
.cx
;
944 header
->DpiY
= (REAL
)emfheader
.szlDevice
.cy
* 25.4 / emfheader
.szlMillimeters
.cy
;
945 header
->X
= gdip_round((REAL
)emfheader
.rclFrame
.left
/ 2540.0 * header
->DpiX
);
946 header
->Y
= gdip_round((REAL
)emfheader
.rclFrame
.top
/ 2540.0 * header
->DpiY
);
947 header
->Width
= gdip_round((REAL
)(emfheader
.rclFrame
.right
- emfheader
.rclFrame
.left
) / 2540.0 * header
->DpiX
);
948 header
->Height
= gdip_round((REAL
)(emfheader
.rclFrame
.bottom
- emfheader
.rclFrame
.top
) / 2540.0 * header
->DpiY
);
949 header
->u
.EmfHeader
= emfheader
;
951 if (metafile_type
== MetafileTypeEmfPlusDual
|| metafile_type
== MetafileTypeEmfPlusOnly
)
953 header
->Version
= emfplusheader
.Version
;
954 header
->EmfPlusFlags
= emfplusheader
.EmfPlusFlags
;
955 header
->EmfPlusHeaderSize
= emfplusheader
.Header
.Size
;
956 header
->LogicalDpiX
= emfplusheader
.LogicalDpiX
;
957 header
->LogicalDpiY
= emfplusheader
.LogicalDpiY
;
961 header
->Version
= emfheader
.nVersion
;
962 header
->EmfPlusFlags
= 0;
963 header
->EmfPlusHeaderSize
= 0;
964 header
->LogicalDpiX
= 0;
965 header
->LogicalDpiY
= 0;
971 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromFile(GDIPCONST WCHAR
*filename
,
972 MetafileHeader
*header
)
976 TRACE("(%s,%p)\n", debugstr_w(filename
), header
);
978 if(!filename
|| !header
)
979 return InvalidParameter
;
982 FIXME("not implemented\n");
984 memset(header
, 0, sizeof(MetafileHeader
));
989 GpStatus WINGDIPAPI
GdipGetMetafileHeaderFromStream(IStream
*stream
,
990 MetafileHeader
*header
)
994 TRACE("(%p,%p)\n", stream
, header
);
996 if(!stream
|| !header
)
997 return InvalidParameter
;
1000 FIXME("not implemented\n");
1002 memset(header
, 0, sizeof(MetafileHeader
));
1007 GpStatus WINGDIPAPI
GdipCreateMetafileFromEmf(HENHMETAFILE hemf
, BOOL
delete,
1008 GpMetafile
**metafile
)
1011 MetafileHeader header
;
1013 TRACE("(%p,%i,%p)\n", hemf
, delete, metafile
);
1015 if(!hemf
|| !metafile
)
1016 return InvalidParameter
;
1018 stat
= GdipGetMetafileHeaderFromEmf(hemf
, &header
);
1022 *metafile
= heap_alloc_zero(sizeof(GpMetafile
));
1026 (*metafile
)->image
.type
= ImageTypeMetafile
;
1027 (*metafile
)->image
.format
= ImageFormatEMF
;
1028 (*metafile
)->image
.frame_count
= 1;
1029 (*metafile
)->image
.xres
= header
.DpiX
;
1030 (*metafile
)->image
.yres
= header
.DpiY
;
1031 (*metafile
)->bounds
.X
= (REAL
)header
.u
.EmfHeader
.rclFrame
.left
/ 2540.0 * header
.DpiX
;
1032 (*metafile
)->bounds
.Y
= (REAL
)header
.u
.EmfHeader
.rclFrame
.top
/ 2540.0 * header
.DpiY
;
1033 (*metafile
)->bounds
.Width
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.right
- header
.u
.EmfHeader
.rclFrame
.left
)
1034 / 2540.0 * header
.DpiX
;
1035 (*metafile
)->bounds
.Height
= (REAL
)(header
.u
.EmfHeader
.rclFrame
.bottom
- header
.u
.EmfHeader
.rclFrame
.top
)
1036 / 2540.0 * header
.DpiY
;
1037 (*metafile
)->unit
= UnitPixel
;
1038 (*metafile
)->metafile_type
= header
.Type
;
1039 (*metafile
)->hemf
= hemf
;
1040 (*metafile
)->preserve_hemf
= !delete;
1042 TRACE("<-- %p\n", *metafile
);
1047 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmf(HMETAFILE hwmf
, BOOL
delete,
1048 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1053 GpStatus retval
= Ok
;
1055 TRACE("(%p, %d, %p, %p)\n", hwmf
, delete, placeable
, metafile
);
1057 if(!hwmf
|| !metafile
)
1058 return InvalidParameter
;
1061 read
= GetMetaFileBitsEx(hwmf
, 0, NULL
);
1063 return GenericError
;
1064 copy
= heap_alloc_zero(read
);
1065 GetMetaFileBitsEx(hwmf
, read
, copy
);
1067 hemf
= SetWinMetaFileBits(read
, copy
, NULL
, NULL
);
1070 /* FIXME: We should store and use hwmf instead of converting to hemf */
1071 retval
= GdipCreateMetafileFromEmf(hemf
, TRUE
, metafile
);
1077 (*metafile
)->image
.xres
= (REAL
)placeable
->Inch
;
1078 (*metafile
)->image
.yres
= (REAL
)placeable
->Inch
;
1079 (*metafile
)->bounds
.X
= ((REAL
)placeable
->BoundingBox
.Left
) / ((REAL
)placeable
->Inch
);
1080 (*metafile
)->bounds
.Y
= ((REAL
)placeable
->BoundingBox
.Top
) / ((REAL
)placeable
->Inch
);
1081 (*metafile
)->bounds
.Width
= (REAL
)(placeable
->BoundingBox
.Right
-
1082 placeable
->BoundingBox
.Left
);
1083 (*metafile
)->bounds
.Height
= (REAL
)(placeable
->BoundingBox
.Bottom
-
1084 placeable
->BoundingBox
.Top
);
1085 (*metafile
)->metafile_type
= MetafileTypeWmfPlaceable
;
1088 (*metafile
)->metafile_type
= MetafileTypeWmf
;
1089 (*metafile
)->image
.format
= ImageFormatWMF
;
1091 if (delete) DeleteMetaFile(hwmf
);
1094 DeleteEnhMetaFile(hemf
);
1098 GpStatus WINGDIPAPI
GdipCreateMetafileFromWmfFile(GDIPCONST WCHAR
*file
,
1099 GDIPCONST WmfPlaceableFileHeader
* placeable
, GpMetafile
**metafile
)
1101 HMETAFILE hmf
= GetMetaFileW(file
);
1103 TRACE("(%s, %p, %p)\n", debugstr_w(file
), placeable
, metafile
);
1105 if(!hmf
) return InvalidParameter
;
1107 return GdipCreateMetafileFromWmf(hmf
, TRUE
, placeable
, metafile
);
1110 GpStatus WINGDIPAPI
GdipCreateMetafileFromFile(GDIPCONST WCHAR
*file
,
1111 GpMetafile
**metafile
)
1113 FIXME("(%p, %p): stub\n", file
, metafile
);
1114 return NotImplemented
;
1117 GpStatus WINGDIPAPI
GdipCreateMetafileFromStream(IStream
*stream
,
1118 GpMetafile
**metafile
)
1120 FIXME("(%p, %p): stub\n", stream
, metafile
);
1121 return NotImplemented
;
1124 GpStatus WINGDIPAPI
GdipSetMetafileDownLevelRasterizationLimit(GpMetafile
*metafile
,
1127 TRACE("(%p,%u)\n", metafile
, limitDpi
);
1132 GpStatus WINGDIPAPI
GdipConvertToEmfPlus(const GpGraphics
* ref
,
1133 GpMetafile
* metafile
, BOOL
* succ
, EmfType emfType
,
1134 const WCHAR
* description
, GpMetafile
** out_metafile
)
1138 TRACE("(%p,%p,%p,%u,%s,%p)\n", ref
, metafile
, succ
, emfType
,
1139 debugstr_w(description
), out_metafile
);
1141 if(!ref
|| !metafile
|| !out_metafile
|| emfType
< EmfTypeEmfOnly
|| emfType
> EmfTypeEmfPlusDual
)
1142 return InvalidParameter
;
1146 *out_metafile
= NULL
;
1149 FIXME("not implemented\n");
1151 return NotImplemented
;
1154 GpStatus WINGDIPAPI
GdipEmfToWmfBits(HENHMETAFILE hemf
, UINT cbData16
,
1155 LPBYTE pData16
, INT iMapMode
, INT eFlags
)
1157 FIXME("(%p, %d, %p, %d, %d): stub\n", hemf
, cbData16
, pData16
, iMapMode
, eFlags
);
1158 return NotImplemented
;
1161 GpStatus WINGDIPAPI
GdipRecordMetafileFileName(GDIPCONST WCHAR
* fileName
,
1162 HDC hdc
, EmfType type
, GDIPCONST GpRectF
*pFrameRect
,
1163 MetafileFrameUnit frameUnit
, GDIPCONST WCHAR
*desc
,
1164 GpMetafile
**metafile
)
1166 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1167 frameUnit
, debugstr_w(desc
), metafile
);
1169 return NotImplemented
;
1172 GpStatus WINGDIPAPI
GdipRecordMetafileFileNameI(GDIPCONST WCHAR
* fileName
, HDC hdc
, EmfType type
,
1173 GDIPCONST GpRect
*pFrameRect
, MetafileFrameUnit frameUnit
,
1174 GDIPCONST WCHAR
*desc
, GpMetafile
**metafile
)
1176 FIXME("%s %p %d %p %d %s %p stub!\n", debugstr_w(fileName
), hdc
, type
, pFrameRect
,
1177 frameUnit
, debugstr_w(desc
), metafile
);
1179 return NotImplemented
;
1182 /*****************************************************************************
1183 * GdipConvertToEmfPlusToFile [GDIPLUS.@]
1186 GpStatus WINGDIPAPI
GdipConvertToEmfPlusToFile(const GpGraphics
* refGraphics
,
1187 GpMetafile
* metafile
, BOOL
* conversionSuccess
,
1188 const WCHAR
* filename
, EmfType emfType
,
1189 const WCHAR
* description
, GpMetafile
** out_metafile
)
1191 FIXME("stub: %p, %p, %p, %p, %u, %p, %p\n", refGraphics
, metafile
, conversionSuccess
, filename
, emfType
, description
, out_metafile
);
1192 return NotImplemented
;