1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <emfreader.hxx>
21 #include <osl/endian.h>
22 #include <basegfx/matrix/b2dhommatrix.hxx>
23 #include <vcl/dibtools.hxx>
24 #include <o3tl/make_unique.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <tools/stream.hxx>
30 #include <vcl/pngwrite.hxx>
38 #define EMR_POLYBEZIER 2
40 #define EMR_POLYLINE 4
41 #define EMR_POLYBEZIERTO 5
42 #define EMR_POLYLINETO 6
43 #define EMR_POLYPOLYLINE 7
44 #define EMR_POLYPOLYGON 8
45 #define EMR_SETWINDOWEXTEX 9
46 #define EMR_SETWINDOWORGEX 10
47 #define EMR_SETVIEWPORTEXTEX 11
48 #define EMR_SETVIEWPORTORGEX 12
49 #define EMR_SETBRUSHORGEX 13
51 #define EMR_SETPIXELV 15
52 #define EMR_SETMAPPERFLAGS 16
53 #define EMR_SETMAPMODE 17
54 #define EMR_SETBKMODE 18
55 #define EMR_SETPOLYFILLMODE 19
56 #define EMR_SETROP2 20
57 #define EMR_SETSTRETCHBLTMODE 21
58 #define EMR_SETTEXTALIGN 22
59 #define EMR_SETCOLORADJUSTMENT 23
60 #define EMR_SETTEXTCOLOR 24
61 #define EMR_SETBKCOLOR 25
62 #define EMR_OFFSETCLIPRGN 26
63 #define EMR_MOVETOEX 27
64 #define EMR_SETMETARGN 28
65 #define EMR_EXCLUDECLIPRECT 29
66 #define EMR_INTERSECTCLIPRECT 30
67 #define EMR_SCALEVIEWPORTEXTEX 31
68 #define EMR_SCALEWINDOWEXTEX 32
70 #define EMR_RESTOREDC 34
71 #define EMR_SETWORLDTRANSFORM 35
72 #define EMR_MODIFYWORLDTRANSFORM 36
73 #define EMR_SELECTOBJECT 37
74 #define EMR_CREATEPEN 38
75 #define EMR_CREATEBRUSHINDIRECT 39
76 #define EMR_DELETEOBJECT 40
77 #define EMR_ANGLEARC 41
78 #define EMR_ELLIPSE 42
79 #define EMR_RECTANGLE 43
80 #define EMR_ROUNDRECT 44
84 #define EMR_SELECTPALETTE 48
85 #define EMR_CREATEPALETTE 49
86 #define EMR_SETPALETTEENTRIES 50
87 #define EMR_RESIZEPALETTE 51
88 #define EMR_REALIZEPALETTE 52
89 #define EMR_EXTFLOODFILL 53
92 #define EMR_POLYDRAW 56
93 #define EMR_SETARCDIRECTION 57
94 #define EMR_SETMITERLIMIT 58
95 #define EMR_BEGINPATH 59
96 #define EMR_ENDPATH 60
97 #define EMR_CLOSEFIGURE 61
98 #define EMR_FILLPATH 62
99 #define EMR_STROKEANDFILLPATH 63
100 #define EMR_STROKEPATH 64
101 #define EMR_FLATTENPATH 65
102 #define EMR_WIDENPATH 66
103 #define EMR_SELECTCLIPPATH 67
104 #define EMR_ABORTPATH 68
106 #define EMR_COMMENT 70 // Contains arbitrary private data.
107 // Comment Identifiers:
108 #define EMR_COMMENT_EMFPLUS 0x2B464D45 // Contains embedded EMF+ records.
109 #define EMR_COMMENT_EMFSPOOL 0x00000000 // Contains embedded EMFSPOOL records.
110 #define EMR_COMMENT_PUBLIC 0x43494447 // Specify extensions to EMF processing.
112 #define EMR_FILLRGN 71
113 #define EMR_FRAMERGN 72
114 #define EMR_INVERTRGN 73
115 #define EMR_PAINTRGN 74
116 #define EMR_EXTSELECTCLIPRGN 75
117 #define EMR_BITBLT 76
118 #define EMR_STRETCHBLT 77
119 #define EMR_MASKBLT 78
120 #define EMR_PLGBLT 79
121 #define EMR_SETDIBITSTODEVICE 80
122 #define EMR_STRETCHDIBITS 81
123 #define EMR_EXTCREATEFONTINDIRECTW 82
124 #define EMR_EXTTEXTOUTA 83
125 #define EMR_EXTTEXTOUTW 84
126 #define EMR_POLYBEZIER16 85
127 #define EMR_POLYGON16 86
128 #define EMR_POLYLINE16 87
129 #define EMR_POLYBEZIERTO16 88
130 #define EMR_POLYLINETO16 89
131 #define EMR_POLYPOLYLINE16 90
132 #define EMR_POLYPOLYGON16 91
133 #define EMR_POLYDRAW16 92
134 #define EMR_CREATEMONOBRUSH 93
135 #define EMR_CREATEDIBPATTERNBRUSHPT 94
136 #define EMR_EXTCREATEPEN 95
137 #define EMR_POLYTEXTOUTA 96
138 #define EMR_POLYTEXTOUTW 97
140 // WINDOWS VERSION >= 0x400
141 #define EMR_SETICMMODE 98
142 #define EMR_CREATECOLORSPACE 99
143 #define EMR_SETCOLORSPACE 100
144 #define EMR_DELETECOLORSPACE 101
145 #define EMR_GLSRECORD 102
146 #define EMR_GLSBOUNDEDRECORD 103
147 #define EMR_PIXELFORMAT 104
149 // WINDOWS VERSION >= 0x500
150 #define EMR_DRAWESCAPE 105
151 #define EMR_EXTESCAPE 106
152 #define EMR_STARTDOC 107
153 #define EMR_SMALLTEXTOUT 108
154 #define EMR_FORCEUFIMAPPING 109
155 #define EMR_NAMEDESCAPE 110
156 #define EMR_COLORCORRECTPALETTE 111
157 #define EMR_SETICMPROFILEA 112
158 #define EMR_SETICMPROFILEW 113
159 #define EMR_ALPHABLEND 114
160 #define EMR_ALPHADIBBLEND 115
161 #define EMR_TRANSPARENTBLT 116
162 #define EMR_TRANSPARENTDIB 117
163 #define EMR_GRADIENTFILL 118
164 #define EMR_SETLINKEDUFIS 119
165 #define EMR_SETTEXTJUSTIFICATION 120
171 record_type_name(sal_uInt32 nRecType
)
179 case EMR_HEADER
: return "HEADER";
180 case EMR_POLYBEZIER
: return "POLYBEZIER";
181 case EMR_POLYGON
: return "POLYGON";
182 case EMR_POLYLINE
: return "POLYLINE";
183 case EMR_POLYBEZIERTO
: return "POLYBEZIERTO";
184 case EMR_POLYLINETO
: return "POLYLINETO";
185 case EMR_POLYPOLYLINE
: return "POLYPOLYLINE";
186 case EMR_POLYPOLYGON
: return "POLYPOLYGON";
187 case EMR_SETWINDOWEXTEX
: return "SETWINDOWEXTEX";
188 case EMR_SETWINDOWORGEX
: return "SETWINDOWORGEX";
189 case EMR_SETVIEWPORTEXTEX
: return "SETVIEWPORTEXTEX";
190 case EMR_SETVIEWPORTORGEX
: return "SETVIEWPORTORGEX";
191 case EMR_SETBRUSHORGEX
: return "SETBRUSHORGEX";
192 case EMR_EOF
: return "EOF";
193 case EMR_SETPIXELV
: return "SETPIXELV";
194 case EMR_SETMAPPERFLAGS
: return "SETMAPPERFLAGS";
195 case EMR_SETMAPMODE
: return "SETMAPMODE";
196 case EMR_SETBKMODE
: return "SETBKMODE";
197 case EMR_SETPOLYFILLMODE
: return "SETPOLYFILLMODE";
198 case EMR_SETROP2
: return "SETROP2";
199 case EMR_SETSTRETCHBLTMODE
: return "SETSTRETCHBLTMODE";
200 case EMR_SETTEXTALIGN
: return "SETTEXTALIGN";
201 case EMR_SETCOLORADJUSTMENT
: return "SETCOLORADJUSTMENT";
202 case EMR_SETTEXTCOLOR
: return "SETTEXTCOLOR";
203 case EMR_SETBKCOLOR
: return "SETBKCOLOR";
204 case EMR_OFFSETCLIPRGN
: return "OFFSETCLIPRGN";
205 case EMR_MOVETOEX
: return "MOVETOEX";
206 case EMR_SETMETARGN
: return "SETMETARGN";
207 case EMR_EXCLUDECLIPRECT
: return "EXCLUDECLIPRECT";
208 case EMR_INTERSECTCLIPRECT
: return "INTERSECTCLIPRECT";
209 case EMR_SCALEVIEWPORTEXTEX
: return "SCALEVIEWPORTEXTEX";
210 case EMR_SCALEWINDOWEXTEX
: return "SCALEWINDOWEXTEX";
211 case EMR_SAVEDC
: return "SAVEDC";
212 case EMR_RESTOREDC
: return "RESTOREDC";
213 case EMR_SETWORLDTRANSFORM
: return "SETWORLDTRANSFORM";
214 case EMR_MODIFYWORLDTRANSFORM
: return "MODIFYWORLDTRANSFORM";
215 case EMR_SELECTOBJECT
: return "SELECTOBJECT";
216 case EMR_CREATEPEN
: return "CREATEPEN";
217 case EMR_CREATEBRUSHINDIRECT
: return "CREATEBRUSHINDIRECT";
218 case EMR_DELETEOBJECT
: return "DELETEOBJECT";
219 case EMR_ANGLEARC
: return "ANGLEARC";
220 case EMR_ELLIPSE
: return "ELLIPSE";
221 case EMR_RECTANGLE
: return "RECTANGLE";
222 case EMR_ROUNDRECT
: return "ROUNDRECT";
223 case EMR_ARC
: return "ARC";
224 case EMR_CHORD
: return "CHORD";
225 case EMR_PIE
: return "PIE";
226 case EMR_SELECTPALETTE
: return "SELECTPALETTE";
227 case EMR_CREATEPALETTE
: return "CREATEPALETTE";
228 case EMR_SETPALETTEENTRIES
: return "SETPALETTEENTRIES";
229 case EMR_RESIZEPALETTE
: return "RESIZEPALETTE";
230 case EMR_REALIZEPALETTE
: return "REALIZEPALETTE";
231 case EMR_EXTFLOODFILL
: return "EXTFLOODFILL";
232 case EMR_LINETO
: return "LINETO";
233 case EMR_ARCTO
: return "ARCTO";
234 case EMR_POLYDRAW
: return "POLYDRAW";
235 case EMR_SETARCDIRECTION
: return "SETARCDIRECTION";
236 case EMR_SETMITERLIMIT
: return "SETMITERLIMIT";
237 case EMR_BEGINPATH
: return "BEGINPATH";
238 case EMR_ENDPATH
: return "ENDPATH";
239 case EMR_CLOSEFIGURE
: return "CLOSEFIGURE";
240 case EMR_FILLPATH
: return "FILLPATH";
241 case EMR_STROKEANDFILLPATH
: return "STROKEANDFILLPATH";
242 case EMR_STROKEPATH
: return "STROKEPATH";
243 case EMR_FLATTENPATH
: return "FLATTENPATH";
244 case EMR_WIDENPATH
: return "WIDENPATH";
245 case EMR_SELECTCLIPPATH
: return "SELECTCLIPPATH";
246 case EMR_ABORTPATH
: return "ABORTPATH";
247 case EMR_COMMENT
: return "COMMENT";
248 case EMR_FILLRGN
: return "FILLRGN";
249 case EMR_FRAMERGN
: return "FRAMERGN";
250 case EMR_INVERTRGN
: return "INVERTRGN";
251 case EMR_PAINTRGN
: return "PAINTRGN";
252 case EMR_EXTSELECTCLIPRGN
: return "EXTSELECTCLIPRGN";
253 case EMR_BITBLT
: return "BITBLT";
254 case EMR_STRETCHBLT
: return "STRETCHBLT";
255 case EMR_MASKBLT
: return "MASKBLT";
256 case EMR_PLGBLT
: return "PLGBLT";
257 case EMR_SETDIBITSTODEVICE
: return "SETDIBITSTODEVICE";
258 case EMR_STRETCHDIBITS
: return "STRETCHDIBITS";
259 case EMR_EXTCREATEFONTINDIRECTW
: return "EXTCREATEFONTINDIRECTW";
260 case EMR_EXTTEXTOUTA
: return "EXTTEXTOUTA";
261 case EMR_EXTTEXTOUTW
: return "EXTTEXTOUTW";
262 case EMR_POLYBEZIER16
: return "POLYBEZIER16";
263 case EMR_POLYGON16
: return "POLYGON16";
264 case EMR_POLYLINE16
: return "POLYLINE16";
265 case EMR_POLYBEZIERTO16
: return "POLYBEZIERTO16";
266 case EMR_POLYLINETO16
: return "POLYLINETO16";
267 case EMR_POLYPOLYLINE16
: return "POLYPOLYLINE16";
268 case EMR_POLYPOLYGON16
: return "POLYPOLYGON16";
269 case EMR_POLYDRAW16
: return "POLYDRAW16";
270 case EMR_CREATEMONOBRUSH
: return "CREATEMONOBRUSH";
271 case EMR_CREATEDIBPATTERNBRUSHPT
: return "CREATEDIBPATTERNBRUSHPT";
272 case EMR_EXTCREATEPEN
: return "EXTCREATEPEN";
273 case EMR_POLYTEXTOUTA
: return "POLYTEXTOUTA";
274 case EMR_POLYTEXTOUTW
: return "POLYTEXTOUTW";
275 case EMR_SETICMMODE
: return "SETICMMODE";
276 case EMR_CREATECOLORSPACE
: return "CREATECOLORSPACE";
277 case EMR_SETCOLORSPACE
: return "SETCOLORSPACE";
278 case EMR_DELETECOLORSPACE
: return "DELETECOLORSPACE";
279 case EMR_GLSRECORD
: return "GLSRECORD";
280 case EMR_GLSBOUNDEDRECORD
: return "GLSBOUNDEDRECORD";
281 case EMR_PIXELFORMAT
: return "PIXELFORMAT";
282 case EMR_DRAWESCAPE
: return "DRAWESCAPE";
283 case EMR_EXTESCAPE
: return "EXTESCAPE";
284 case EMR_STARTDOC
: return "STARTDOC";
285 case EMR_SMALLTEXTOUT
: return "SMALLTEXTOUT";
286 case EMR_FORCEUFIMAPPING
: return "FORCEUFIMAPPING";
287 case EMR_NAMEDESCAPE
: return "NAMEDESCAPE";
288 case EMR_COLORCORRECTPALETTE
: return "COLORCORRECTPALETTE";
289 case EMR_SETICMPROFILEA
: return "SETICMPROFILEA";
290 case EMR_SETICMPROFILEW
: return "SETICMPROFILEW";
291 case EMR_ALPHABLEND
: return "ALPHABLEND";
292 case EMR_ALPHADIBBLEND
: return "ALPHADIBBLEND";
293 case EMR_TRANSPARENTBLT
: return "TRANSPARENTBLT";
294 case EMR_TRANSPARENTDIB
: return "TRANSPARENTDIB";
295 case EMR_GRADIENTFILL
: return "GRADIENTFILL";
296 case EMR_SETLINKEDUFIS
: return "SETLINKEDUFIS";
297 case EMR_SETTEXTJUSTIFICATION
: return "SETTEXTJUSTIFICATION";
299 // Yes, return a pointer to a static buffer. This is a very
300 // local debugging output function, so no big deal.
301 static char buffer
[11];
302 sprintf(buffer
, "0x%08" SAL_PRIxUINT32
, nRecType
);
310 unsigned char aBlendOperation
;
311 unsigned char aBlendFlags
;
312 unsigned char aSrcConstantAlpha
;
313 unsigned char aAlphaFormat
;
315 friend SvStream
& operator>>(SvStream
& rInStream
, BLENDFUNCTION
& rBlendFun
);
318 SvStream
& operator>>(SvStream
& rInStream
, BLENDFUNCTION
& rBlendFun
)
320 rInStream
.ReadUChar(rBlendFun
.aBlendOperation
);
321 rInStream
.ReadUChar(rBlendFun
.aBlendFlags
);
322 rInStream
.ReadUChar(rBlendFun
.aSrcConstantAlpha
);
323 rInStream
.ReadUChar(rBlendFun
.aAlphaFormat
);
327 bool ImplReadRegion( tools::PolyPolygon
& rPolyPoly
, SvStream
& rStream
, sal_uInt32 nLen
)
332 sal_uInt32 nHdSize
, nType
, nCount
, nRgnSize
, i
;
333 rStream
.ReadUInt32(nHdSize
);
334 rStream
.ReadUInt32(nType
);
335 rStream
.ReadUInt32(nCount
);
336 rStream
.ReadUInt32(nRgnSize
);
338 if (!rStream
.good() || nCount
== 0 || nType
!= RDH_RECTANGLES
)
342 if (o3tl::checked_multiply
<sal_uInt32
>(nCount
, 16, nSize
))
344 if (o3tl::checked_add
<sal_uInt32
>(nSize
, nHdSize
- 16, nSize
))
349 sal_Int32 nx1
, ny1
, nx2
, ny2
;
350 for (i
= 0; i
< nCount
; i
++)
352 rStream
.ReadInt32(nx1
);
353 rStream
.ReadInt32(ny1
);
354 rStream
.ReadInt32(nx2
);
355 rStream
.ReadInt32(ny2
);
357 tools::Rectangle
aRectangle(Point(nx1
, ny1
), Point(nx2
, ny2
));
359 tools::Polygon
aPolygon(aRectangle
);
360 tools::PolyPolygon
aPolyPolyOr1(aPolygon
);
361 tools::PolyPolygon
aPolyPolyOr2(rPolyPoly
);
362 rPolyPoly
.GetUnion(aPolyPolyOr1
, aPolyPolyOr2
);
363 rPolyPoly
= aPolyPolyOr2
;
368 } // anonymous namespace
372 EmfReader::EmfReader(SvStream
& rStream
,GDIMetaFile
& rGDIMetaFile
)
373 : MtfTools(rGDIMetaFile
, rStream
)
375 , mbRecordPath(false)
377 ,mbEMFPlusDualMode(false)
381 EmfReader::~EmfReader()
385 void EmfReader::ReadEMFPlusComment(sal_uInt32 length
, bool& bHaveDC
)
389 PassEMFPlusHeaderInfo();
391 #if OSL_DEBUG_LEVEL > 1
392 // debug code - write the stream to debug file /tmp/emf-stream.emf
393 sal_uInt64
const pos
= mpInputStream
->Tell();
394 mpInputStream
->Seek(0);
395 SvFileStream
file( OUString( "/tmp/emf-stream.emf" ), StreamMode::WRITE
| StreamMode::TRUNC
);
397 mpInputStream
->WriteStream(file
);
401 mpInputStream
->Seek( pos
);
407 sal_uInt64
const pos
= mpInputStream
->Tell();
408 void *buffer
= malloc( length
);
409 PassEMFPlus( buffer
, mpInputStream
->ReadBytes(buffer
, length
) );
411 mpInputStream
->Seek( pos
);
415 // skip in SeekRel if impossibly unavailable
416 sal_uInt32 nRemainder
= length
;
418 const size_t nRequiredHeaderSize
= 12;
419 while (nRemainder
>= nRequiredHeaderSize
)
421 sal_uInt16
type(0), flags(0);
422 sal_uInt32
size(0), dataSize(0);
424 mpInputStream
->ReadUInt16( type
).ReadUInt16( flags
).ReadUInt32( size
).ReadUInt32( dataSize
);
425 nRemainder
-= nRequiredHeaderSize
;
427 SAL_INFO ("emfio", "\t\tEMF+ record type: " << std::hex
<< type
<< std::dec
);
429 // Get Device Context
430 // TODO We should use EmfPlusRecordType::GetDC instead
434 SAL_INFO ("emfio", "\t\tEMF+ lock DC (device context)");
437 // look for the "dual mode" in header
438 // it indicates that either EMF or EMF+ records should be processed
439 // 0x4001 = EMF+ header
440 // flags & 1 = dual mode active
441 if ( type
== 0x4001 && flags
& 1 )
443 mbEMFPlusDualMode
= true;
446 // Get the length of the remaining data of this record based
447 // on the alleged size
448 sal_uInt32 nRemainingRecordData
= size
>= nRequiredHeaderSize
?
449 size
-nRequiredHeaderSize
: 0;
450 // clip to available size
451 nRemainingRecordData
= std::min(nRemainingRecordData
, nRemainder
);
452 mpInputStream
->SeekRel(nRemainingRecordData
);
453 nRemainder
-= nRemainingRecordData
;
455 mpInputStream
->SeekRel(nRemainder
);
458 // these are referenced from inside the templates
459 SvStream
& operator >> (SvStream
& rStream
, sal_Int16
&n
)
461 return rStream
.ReadInt16(n
);
464 SvStream
& operator >> (SvStream
& rStream
, sal_Int32
&n
)
466 return rStream
.ReadInt32(n
);
470 * Reads polygons from the stream.
471 * The \<class T> parameter is for the type of the points (sal_uInt32 or sal_uInt16).
472 * skipFirst: if the first point read is the 0th point or the 1st point in the array.
475 tools::Polygon
EmfReader::ReadPolygonWithSkip(const bool skipFirst
, sal_uInt32 nNextPos
)
477 sal_uInt32
nPoints(0), nStartIndex(0);
478 mpInputStream
->SeekRel( 16 );
479 mpInputStream
->ReadUInt32( nPoints
);
486 return ReadPolygon
<T
>(nStartIndex
, nPoints
, nNextPos
);
490 * Reads polygons from the stream.
491 * The \<class T> parameter is for the type of the points
492 * nStartIndex: which is the starting index in the polygon of the first point read
493 * nPoints: number of points
494 * mpInputStream: the stream containing the polygons
497 tools::Polygon
EmfReader::ReadPolygon(sal_uInt32 nStartIndex
, sal_uInt32 nPoints
, sal_uInt32 nNextPos
)
499 bool bRecordOk
= nPoints
<= SAL_MAX_UINT16
;
500 SAL_WARN_IF(!bRecordOk
, "emfio", "polygon record has more polygons than we can handle");
501 if (!bRecordOk
|| !nPoints
)
502 return tools::Polygon();
504 auto nRemainingSize
= std::min(nNextPos
- mpInputStream
->Tell(), mpInputStream
->remainingSize());
505 auto nMaxPossiblePoints
= nRemainingSize
/ (sizeof(T
) * 2);
506 auto nPointCount
= nPoints
- nStartIndex
;
507 if (nPointCount
> nMaxPossiblePoints
)
509 SAL_WARN("emfio", "polygon claims more points than record can provide, truncating");
510 nPoints
= nMaxPossiblePoints
+ nStartIndex
;
513 tools::Polygon
aPolygon(nPoints
);
514 for (sal_uInt32 i
= nStartIndex
; i
< nPoints
&& mpInputStream
->good(); i
++ )
517 *mpInputStream
>> nX
>> nY
;
518 if (!mpInputStream
->good())
520 SAL_WARN("emfio", "short read on polygon, truncating");
524 aPolygon
[ i
] = Point( nX
, nY
);
531 * Reads a polyline from the WMF file and draws it
532 * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
535 void EmfReader::ReadAndDrawPolyLine(sal_uInt32 nNextPos
)
538 sal_uInt32 i
, nNumberOfPolylines( 0 ), nCount( 0 );
539 mpInputStream
->SeekRel( 0x10 ); // TODO Skipping Bounds. A 128-bit WMF RectL object (specifies the bounding rectangle in device units.)
540 mpInputStream
->ReadUInt32( nNumberOfPolylines
);
541 mpInputStream
->ReadUInt32( nCount
); // total number of points in all polylines
542 const auto nEndPos
= std::min(nNextPos
, mnEndPos
);
543 if (mpInputStream
->Tell() >= nEndPos
)
546 // taking the amount of points of each polygon, retrieving the total number of points
547 if ( mpInputStream
->good() &&
548 ( nNumberOfPolylines
< SAL_MAX_UINT32
/ sizeof( sal_uInt16
) ) &&
549 ( nNumberOfPolylines
* sizeof( sal_uInt16
) ) <= ( nEndPos
- mpInputStream
->Tell() )
552 std::unique_ptr
< sal_uInt32
[] > pnPolylinePointCount( new sal_uInt32
[ nNumberOfPolylines
] );
553 for ( i
= 0; i
< nNumberOfPolylines
&& mpInputStream
->good(); i
++ )
555 mpInputStream
->ReadUInt32( nPoints
);
556 pnPolylinePointCount
[ i
] = nPoints
;
558 // Get polyline points:
559 for ( i
= 0; ( i
< nNumberOfPolylines
) && mpInputStream
->good(); i
++ )
561 tools::Polygon aPolygon
= ReadPolygon
<T
>(0, pnPolylinePointCount
[i
], nNextPos
);
562 DrawPolyLine(aPolygon
, false, mbRecordPath
);
568 * Reads a poly polygon from the WMF file and draws it.
569 * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
572 void EmfReader::ReadAndDrawPolyPolygon(sal_uInt32 nNextPos
)
574 sal_uInt32
nPoly(0), nGesPoints(0), nReadPoints(0);
575 mpInputStream
->SeekRel( 0x10 );
576 // Number of polygons
577 mpInputStream
->ReadUInt32( nPoly
).ReadUInt32( nGesPoints
);
578 const auto nEndPos
= std::min(nNextPos
, mnEndPos
);
579 if (mpInputStream
->Tell() >= nEndPos
)
581 if (!mpInputStream
->good())
583 //check against numeric overflowing
584 if (nGesPoints
>= SAL_MAX_UINT32
/ sizeof(Point
))
586 if (nPoly
>= SAL_MAX_UINT32
/ sizeof(sal_uInt16
))
588 if (nPoly
* sizeof(sal_uInt16
) > nEndPos
- mpInputStream
->Tell())
591 // Get number of points in each polygon
592 std::vector
<sal_uInt16
> aPoints(nPoly
);
593 for (sal_uInt32 i
= 0; i
< nPoly
&& mpInputStream
->good(); ++i
)
595 sal_uInt32
nPoints(0);
596 mpInputStream
->ReadUInt32( nPoints
);
597 aPoints
[i
] = static_cast<sal_uInt16
>(nPoints
);
599 if ( mpInputStream
->good() && ( nGesPoints
* (sizeof(T
)+sizeof(T
)) ) <= ( nEndPos
- mpInputStream
->Tell() ) )
601 // Get polygon points
602 tools::PolyPolygon
aPolyPoly(nPoly
);
603 for (sal_uInt32 i
= 0; i
< nPoly
&& mpInputStream
->good(); ++i
)
605 const sal_uInt16
nPointCount(aPoints
[i
]);
606 std::vector
<Point
> aPtAry(nPointCount
);
607 for (sal_uInt16 j
= 0; j
< nPointCount
&& mpInputStream
->good(); ++j
)
610 *mpInputStream
>> nX
>> nY
;
611 aPtAry
[j
] = Point( nX
, nY
);
615 aPolyPoly
.Insert(tools::Polygon(aPtAry
.size(), aPtAry
.data()));
618 DrawPolyPolygon(aPolyPoly
, mbRecordPath
);
621 OSL_ENSURE(nReadPoints
== nGesPoints
, "The number Points processed from EMR_POLYPOLYGON is unequal imported number (!)");
624 bool EmfReader::ReadEnhWMF()
626 sal_uInt32 nStretchBltMode
= 0;
627 sal_uInt32
nNextPos(0),
628 nW(0), nH(0), nColor(0), nIndex(0),
629 nDat32(0), nNom1(0), nDen1(0), nNom2(0), nDen2(0);
630 sal_Int32
nX32(0), nY32(0), nx32(0), ny32(0);
632 bool bStatus
= ReadHeader();
633 bool bHaveDC
= false;
635 static bool bEnableEMFPlus
= ( getenv( "EMF_PLUS_DISABLE" ) == nullptr );
637 while( bStatus
&& mnRecordCount
-- && mpInputStream
->good())
639 sal_uInt32
nRecType(0), nRecSize(0);
640 mpInputStream
->ReadUInt32(nRecType
).ReadUInt32(nRecSize
);
642 if ( !mpInputStream
->good() || ( nRecSize
< 8 ) || ( nRecSize
& 3 ) ) // Parameters are always divisible by 4
648 auto nCurPos
= mpInputStream
->Tell();
650 if (mnEndPos
< nCurPos
- 8)
656 const sal_uInt32 nMaxPossibleRecSize
= mnEndPos
- (nCurPos
- 8);
657 if (nRecSize
> nMaxPossibleRecSize
)
663 nNextPos
= nCurPos
+ (nRecSize
- 8);
665 if( !maBmpSaveList
.empty()
666 && ( nRecType
!= EMR_STRETCHBLT
)
667 && ( nRecType
!= EMR_STRETCHDIBITS
)
669 ResolveBitmapActions( maBmpSaveList
);
674 SAL_INFO ("emfio", "0x" << std::hex
<< (nNextPos
- nRecSize
) << "-0x" << nNextPos
<< " " << record_type_name(nRecType
) << " size: " << nRecSize
<< std::dec
);
676 if( bEnableEMFPlus
&& nRecType
== EMR_COMMENT
) {
679 mpInputStream
->ReadUInt32( length
);
681 SAL_INFO("emfio", "\tGDI comment, length: " << length
);
683 if( mpInputStream
->good() && length
>= 4 && length
<= mpInputStream
->remainingSize() ) {
684 sal_uInt32 nCommentId
;
686 mpInputStream
->ReadUInt32( nCommentId
);
688 SAL_INFO ("emfio", "\t\tbegin " << static_cast<char>(nCommentId
& 0xff) << static_cast<char>((nCommentId
& 0xff00) >> 8) << static_cast<char>((nCommentId
& 0xff0000) >> 16) << static_cast<char>((nCommentId
& 0xff000000) >> 24) << " id: 0x" << std::hex
<< nCommentId
<< std::dec
);
690 if( nCommentId
== EMR_COMMENT_EMFPLUS
&& nRecSize
>= 12 )
692 // [MS-EMF] 2.3.3: DataSize includes both CommentIdentifier and CommentRecordParm fields.
693 // We have already read 4-byte CommentIdentifier, so reduce length appropriately
694 ReadEMFPlusComment( length
-4, bHaveDC
);
696 else if( nCommentId
== EMR_COMMENT_PUBLIC
&& nRecSize
>= 12 )
698 // TODO: ReadGDIComment()
700 else if( nCommentId
== EMR_COMMENT_EMFSPOOL
&& nRecSize
>= 12 )
702 // TODO Implement reading EMFSPOOL comment
707 SAL_INFO ("emfio", "\t\tunknown id: 0x" << std::hex
<< nCommentId
<< std::dec
);
711 else if ( !bHaveDC
&& mbEMFPlusDualMode
&& nRecType
!= EMR_HEADER
&& nRecType
!= EMR_EOF
)
713 // skip content (EMF record) in dual mode
714 // we process only EMR_COMMENT (see above) to access EMF+ data
715 // with 2 exceptions, according to EMF+ specification:
716 // EMR_HEADER and EMR_EOF
717 // if a device context is given (bHaveDC) process the following EMF record, too.
719 else if( !mbEMFPlus
|| bHaveDC
|| nRecType
== EMR_EOF
)
723 case EMR_POLYBEZIERTO
:
724 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int32
>(true, nNextPos
), true, mbRecordPath
);
726 case EMR_POLYBEZIER
:
727 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int32
>(false, nNextPos
), false, mbRecordPath
);
731 DrawPolygon(ReadPolygonWithSkip
<sal_Int32
>(false, nNextPos
), mbRecordPath
);
734 case EMR_POLYLINETO
:
735 DrawPolyLine(ReadPolygonWithSkip
<sal_Int32
>(true, nNextPos
), true, mbRecordPath
);
739 DrawPolyLine(ReadPolygonWithSkip
<sal_Int32
>(false, nNextPos
), false, mbRecordPath
);
742 case EMR_POLYPOLYLINE
:
743 ReadAndDrawPolyLine
<sal_Int32
>(nNextPos
);
746 case EMR_POLYPOLYGON
:
747 ReadAndDrawPolyPolygon
<sal_Int32
>(nNextPos
);
750 case EMR_SETWINDOWEXTEX
:
752 mpInputStream
->ReadUInt32( nW
).ReadUInt32( nH
);
753 SetWinExt( Size( nW
, nH
), true);
757 case EMR_SETWINDOWORGEX
:
759 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
760 SetWinOrg( Point( nX32
, nY32
), true);
764 case EMR_SCALEWINDOWEXTEX
:
766 mpInputStream
->ReadUInt32( nNom1
).ReadUInt32( nDen1
).ReadUInt32( nNom2
).ReadUInt32( nDen2
);
767 if (nDen1
!= 0 && nDen2
!= 0)
768 ScaleWinExt( static_cast<double>(nNom1
) / nDen1
, static_cast<double>(nNom2
) / nDen2
);
770 SAL_WARN("vcl.emf", "ignoring bogus divide by zero");
774 case EMR_SETVIEWPORTORGEX
:
776 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
777 SetDevOrg( Point( nX32
, nY32
) );
781 case EMR_SCALEVIEWPORTEXTEX
:
783 mpInputStream
->ReadUInt32( nNom1
).ReadUInt32( nDen1
).ReadUInt32( nNom2
).ReadUInt32( nDen2
);
784 if (nDen1
!= 0 && nDen2
!= 0)
785 ScaleDevExt( static_cast<double>(nNom1
) / nDen1
, static_cast<double>(nNom2
) / nDen2
);
787 SAL_WARN("vcl.emf", "ignoring bogus divide by zero");
791 case EMR_SETVIEWPORTEXTEX
:
793 mpInputStream
->ReadUInt32( nW
).ReadUInt32( nH
);
794 SetDevExt( Size( nW
, nH
) );
804 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
805 DrawPixel( Point( nX32
, nY32
), ReadColor() );
809 case EMR_SETMAPMODE
:
812 mpInputStream
->ReadUInt32( nMapMode
);
813 SetMapMode( nMapMode
);
819 mpInputStream
->ReadUInt32( nDat32
);
820 SetBkMode( static_cast<BkMode
>(nDat32
) );
824 case EMR_SETPOLYFILLMODE
:
829 mpInputStream
->ReadUInt32( nDat32
);
830 SetRasterOp( static_cast<WMFRasterOp
>(nDat32
) );
834 case EMR_SETSTRETCHBLTMODE
:
836 mpInputStream
->ReadUInt32( nStretchBltMode
);
840 case EMR_SETTEXTALIGN
:
842 mpInputStream
->ReadUInt32( nDat32
);
843 SetTextAlign( nDat32
);
847 case EMR_SETTEXTCOLOR
:
849 SetTextColor( ReadColor() );
853 case EMR_SETBKCOLOR
:
855 SetBkColor( ReadColor() );
859 case EMR_OFFSETCLIPRGN
:
861 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
862 MoveClipRegion( Size( nX32
, nY32
) );
868 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
869 MoveTo( Point( nX32
, nY32
), mbRecordPath
);
873 case EMR_INTERSECTCLIPRECT
:
875 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
);
876 IntersectClipRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
) );
892 case EMR_SETWORLDTRANSFORM
:
895 *mpInputStream
>> aTempXForm
;
896 SetWorldTransform( aTempXForm
);
900 case EMR_MODIFYWORLDTRANSFORM
:
904 *mpInputStream
>> aTempXForm
;
905 mpInputStream
->ReadUInt32( nMode
);
906 ModifyWorldTransform( aTempXForm
, nMode
);
910 case EMR_SELECTOBJECT
:
912 mpInputStream
->ReadUInt32( nIndex
);
913 SelectObject( nIndex
);
919 mpInputStream
->ReadUInt32( nIndex
);
920 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
926 // #fdo39428 Remove SvStream operator>>(long&)
927 sal_Int32
nTmpW(0), nTmpH(0);
929 mpInputStream
->ReadUInt32( nStyle
).ReadInt32( nTmpW
).ReadInt32( nTmpH
);
930 aSize
.setWidth( nTmpW
);
931 aSize
.setHeight( nTmpH
);
934 aLineInfo
.SetWidth( aSize
.Width() );
936 bool bTransparent
= false;
937 switch( nStyle
& PS_STYLE_MASK
)
940 aLineInfo
.SetStyle( LineStyle::Dash
);
941 aLineInfo
.SetDashCount( 1 );
942 aLineInfo
.SetDotCount( 2 );
945 aLineInfo
.SetStyle( LineStyle::Dash
);
946 aLineInfo
.SetDashCount( 1 );
947 aLineInfo
.SetDotCount( 1 );
950 aLineInfo
.SetStyle( LineStyle::Dash
);
951 aLineInfo
.SetDashCount( 0 );
952 aLineInfo
.SetDotCount( 1 );
955 aLineInfo
.SetStyle( LineStyle::Dash
);
956 aLineInfo
.SetDashCount( 1 );
957 aLineInfo
.SetDotCount( 0 );
961 aLineInfo
.SetStyle( LineStyle::NONE
);
963 case PS_INSIDEFRAME
:
966 aLineInfo
.SetStyle( LineStyle::Solid
);
968 switch( nStyle
& PS_ENDCAP_STYLE_MASK
)
970 case PS_ENDCAP_ROUND
:
973 aLineInfo
.SetLineCap( css::drawing::LineCap_ROUND
);
977 case PS_ENDCAP_SQUARE
:
980 aLineInfo
.SetLineCap( css::drawing::LineCap_SQUARE
);
984 case PS_ENDCAP_FLAT
:
986 aLineInfo
.SetLineCap( css::drawing::LineCap_BUTT
);
988 switch( nStyle
& PS_JOIN_STYLE_MASK
)
991 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Round
);
994 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Miter
);
997 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Bevel
);
1000 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::NONE
);
1002 CreateObjectIndexed(nIndex
, o3tl::make_unique
<WinMtfLineStyle
>( ReadColor(), aLineInfo
, bTransparent
));
1007 case EMR_EXTCREATEPEN
:
1010 sal_uInt32 offBmi
, cbBmi
, offBits
, cbBits
, nStyle
, nWidth
, nBrushStyle
, elpNumEntries
;
1013 mpInputStream
->ReadUInt32( nIndex
);
1014 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1016 mpInputStream
->ReadUInt32( offBmi
).ReadUInt32( cbBmi
).ReadUInt32( offBits
).ReadUInt32( cbBits
). ReadUInt32( nStyle
).ReadUInt32( nWidth
).ReadUInt32( nBrushStyle
);
1017 aColorRef
= ReadColor();
1018 mpInputStream
->ReadInt32( elpHatch
).ReadUInt32( elpNumEntries
);
1022 aLineInfo
.SetWidth( nWidth
);
1024 bool bTransparent
= false;
1026 switch( nStyle
& PS_STYLE_MASK
)
1028 case PS_DASHDOTDOT
:
1029 aLineInfo
.SetStyle( LineStyle::Dash
);
1030 aLineInfo
.SetDashCount( 1 );
1031 aLineInfo
.SetDotCount( 2 );
1034 aLineInfo
.SetStyle( LineStyle::Dash
);
1035 aLineInfo
.SetDashCount( 1 );
1036 aLineInfo
.SetDotCount( 1 );
1039 aLineInfo
.SetStyle( LineStyle::Dash
);
1040 aLineInfo
.SetDashCount( 0 );
1041 aLineInfo
.SetDotCount( 1 );
1044 aLineInfo
.SetStyle( LineStyle::Dash
);
1045 aLineInfo
.SetDashCount( 1 );
1046 aLineInfo
.SetDotCount( 0 );
1049 bTransparent
= true;
1050 aLineInfo
.SetStyle( LineStyle::NONE
);
1053 case PS_INSIDEFRAME
:
1056 aLineInfo
.SetStyle( LineStyle::Solid
);
1058 switch( nStyle
& PS_ENDCAP_STYLE_MASK
)
1060 case PS_ENDCAP_ROUND
:
1061 if ( aLineInfo
.GetWidth() )
1063 aLineInfo
.SetLineCap( css::drawing::LineCap_ROUND
);
1067 case PS_ENDCAP_SQUARE
:
1068 if ( aLineInfo
.GetWidth() )
1070 aLineInfo
.SetLineCap( css::drawing::LineCap_SQUARE
);
1074 case PS_ENDCAP_FLAT
:
1076 aLineInfo
.SetLineCap( css::drawing::LineCap_BUTT
);
1078 switch( nStyle
& PS_JOIN_STYLE_MASK
)
1080 case PS_JOIN_ROUND
:
1081 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Round
);
1083 case PS_JOIN_MITER
:
1084 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Miter
);
1086 case PS_JOIN_BEVEL
:
1087 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Bevel
);
1090 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::NONE
);
1092 CreateObjectIndexed(nIndex
, o3tl::make_unique
<WinMtfLineStyle
>( aColorRef
, aLineInfo
, bTransparent
));
1097 case EMR_CREATEBRUSHINDIRECT
:
1100 mpInputStream
->ReadUInt32( nIndex
);
1101 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1103 mpInputStream
->ReadUInt32( nStyle
);
1104 CreateObjectIndexed(nIndex
, o3tl::make_unique
<WinMtfFillStyle
>( ReadColor(), ( nStyle
== BS_HOLLOW
) ));
1109 case EMR_DELETEOBJECT
:
1111 mpInputStream
->ReadUInt32( nIndex
);
1112 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1113 DeleteObject( nIndex
);
1119 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
);
1120 DrawEllipse( ReadRectangle( nX32
, nY32
, nx32
, ny32
) );
1124 case EMR_RECTANGLE
:
1126 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
);
1127 DrawRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
) );
1131 case EMR_ROUNDRECT
:
1133 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nW
).ReadUInt32( nH
);
1134 Size
aSize( Size( nW
, nH
) );
1135 DrawRoundRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
), aSize
);
1141 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1142 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1143 DrawArc( ReadRectangle( nX32
, nY32
, nx32
, ny32
), Point( nStartX
, nStartY
), Point( nEndX
, nEndY
) );
1149 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1150 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1151 DrawChord( ReadRectangle( nX32
, nY32
, nx32
, ny32
), Point( nStartX
, nStartY
), Point( nEndX
, nEndY
) );
1157 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1158 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1159 const tools::Rectangle
aRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
));
1161 // #i73608# OutputDevice deviates from WMF
1162 // semantics. start==end means full ellipse here.
1163 if( nStartX
== nEndX
&& nStartY
== nEndY
)
1164 DrawEllipse( aRect
);
1166 DrawPie( aRect
, Point( nStartX
, nStartY
), Point( nEndX
, nEndY
) );
1172 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
1173 LineTo( Point( nX32
, nY32
), mbRecordPath
);
1179 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1180 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1181 DrawArc( ReadRectangle( nX32
, nY32
, nx32
, ny32
), Point( nStartX
, nStartY
), Point( nEndX
, nEndY
), true );
1185 case EMR_BEGINPATH
:
1188 mbRecordPath
= true;
1192 case EMR_ABORTPATH
:
1196 mbRecordPath
= false;
1199 case EMR_CLOSEFIGURE
:
1204 StrokeAndFillPath( false, true );
1207 case EMR_STROKEANDFILLPATH
:
1208 StrokeAndFillPath( true, true );
1211 case EMR_STROKEPATH
:
1212 StrokeAndFillPath( true, false );
1215 case EMR_SELECTCLIPPATH
:
1217 sal_Int32
nClippingMode(0);
1218 mpInputStream
->ReadInt32(nClippingMode
);
1219 SetClipPath(GetPathObj(), nClippingMode
, true);
1223 case EMR_EXTSELECTCLIPRGN
:
1225 sal_Int32
nClippingMode(0), cbRgnData(0);
1226 mpInputStream
->ReadInt32(cbRgnData
);
1227 mpInputStream
->ReadInt32(nClippingMode
);
1229 // This record's region data should be ignored if mode
1230 // is RGN_COPY - see EMF spec section 2.3.2.2
1231 if (nClippingMode
== RGN_COPY
)
1233 SetDefaultClipPath();
1237 tools::PolyPolygon aPolyPoly
;
1239 ImplReadRegion(aPolyPoly
, *mpInputStream
, nRecSize
);
1240 SetClipPath(aPolyPoly
, nClippingMode
, false);
1246 case EMR_ALPHABLEND
:
1248 sal_Int32
xDest(0), yDest(0), cxDest(0), cyDest(0);
1250 BLENDFUNCTION aFunc
;
1251 sal_Int32
xSrc(0), ySrc(0), cxSrc(0), cySrc(0);
1253 sal_uInt32
BkColorSrc(0), iUsageSrc(0), offBmiSrc(0);
1254 sal_uInt32
cbBmiSrc(0), offBitsSrc(0), cbBitsSrc(0);
1256 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1257 mpInputStream
->SeekRel( 0x10 );
1259 mpInputStream
->ReadInt32( xDest
).ReadInt32( yDest
).ReadInt32( cxDest
).ReadInt32( cyDest
);
1260 *mpInputStream
>> aFunc
;
1261 mpInputStream
->ReadInt32( xSrc
).ReadInt32( ySrc
);
1262 *mpInputStream
>> xformSrc
;
1263 mpInputStream
->ReadUInt32( BkColorSrc
).ReadUInt32( iUsageSrc
).ReadUInt32( offBmiSrc
).ReadUInt32( cbBmiSrc
)
1264 .ReadUInt32( offBitsSrc
).ReadUInt32( cbBitsSrc
).ReadInt32( cxSrc
).ReadInt32( cySrc
) ;
1266 if ( (cbBitsSrc
> (SAL_MAX_UINT32
- 14)) || ((SAL_MAX_UINT32
- 14) - cbBitsSrc
< cbBmiSrc
) ||
1267 cxDest
== SAL_MAX_INT32
|| cyDest
== SAL_MAX_INT32
)
1273 tools::Rectangle
aRect(Point(xDest
, yDest
), Size(cxDest
+ 1, cyDest
+ 1));
1275 const sal_uInt32 nSourceSize
= cbBmiSrc
+ cbBitsSrc
+ 14;
1276 bool bSafeRead
= nSourceSize
<= (mnEndPos
- mnStartPos
);
1277 sal_uInt32
nDeltaToDIB5HeaderSize(0);
1278 const bool bReadAlpha(0x01 == aFunc
.aAlphaFormat
);
1279 if (bSafeRead
&& bReadAlpha
)
1281 // we need to read alpha channel data if AlphaFormat of BLENDFUNCTION is
1282 // AC_SRC_ALPHA (==0x01). To read it, create a temp DIB-File which is ready
1284 const sal_uInt32 nHeaderSize
= getDIBV5HeaderSize();
1285 if (cbBmiSrc
> nHeaderSize
)
1288 nDeltaToDIB5HeaderSize
= nHeaderSize
- cbBmiSrc
;
1292 const sal_uInt32
nTargetSize(cbBmiSrc
+ nDeltaToDIB5HeaderSize
+ cbBitsSrc
+ 14);
1293 char* pBuf
= new char[ nTargetSize
];
1294 SvMemoryStream
aTmp( pBuf
, nTargetSize
, StreamMode::READ
| StreamMode::WRITE
);
1296 aTmp
.ObjectOwnsMemory( true );
1298 // write BM-Header (14 bytes)
1299 aTmp
.WriteUChar( 'B' )
1301 .WriteUInt32( cbBitsSrc
)
1304 .WriteUInt32( cbBmiSrc
+ nDeltaToDIB5HeaderSize
+ 14 );
1306 // copy DIBInfoHeader from source (cbBmiSrc bytes)
1307 mpInputStream
->Seek( nStart
+ offBmiSrc
);
1308 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmiSrc
);
1312 // need to add values for all stuff that DIBV5Header is bigger
1313 // than DIBInfoHeader, all values are correctly initialized to zero,
1314 // so we can use memset here
1315 memset(pBuf
+ cbBmiSrc
+ 14, 0, nDeltaToDIB5HeaderSize
);
1318 // copy bitmap data from source (offBitsSrc bytes)
1319 mpInputStream
->Seek( nStart
+ offBitsSrc
);
1320 mpInputStream
->ReadBytes(pBuf
+ 14 + nDeltaToDIB5HeaderSize
+ cbBmiSrc
, cbBitsSrc
);
1323 // prepare to read and fill BitmapEx
1331 if(ReadDIBV5(aBitmap
, aAlpha
, aTmp
))
1333 aBitmapEx
= BitmapEx(aBitmap
, aAlpha
);
1340 if(ReadDIB(aBitmap
, aTmp
, true))
1342 if(0xff != aFunc
.aSrcConstantAlpha
)
1344 // add const alpha channel
1345 aBitmapEx
= BitmapEx(
1347 AlphaMask(aBitmap
.GetSizePixel(), &aFunc
.aSrcConstantAlpha
));
1352 aBitmapEx
= BitmapEx(aBitmap
);
1357 if(!aBitmapEx
.IsEmpty())
1359 // test if it is sensible to crop
1360 if ( ( cxSrc
> 0 ) && ( cySrc
> 0 ) &&
1361 ( xSrc
>= 0 ) && ( ySrc
>= 0 ) &&
1362 ( xSrc
+ cxSrc
< aBitmapEx
.GetSizePixel().Width() ) &&
1363 ( ySrc
+ cySrc
< aBitmapEx
.GetSizePixel().Height() ) )
1365 const tools::Rectangle
aCropRect( Point( xSrc
, ySrc
), Size( cxSrc
, cySrc
) );
1367 aBitmapEx
.Crop( aCropRect
);
1371 static bool bDoSaveForVisualControl(false);
1373 if(bDoSaveForVisualControl
)
1375 SvFileStream
aNew("c:\\metafile_content.png", StreamMode::WRITE
|StreamMode::TRUNC
);
1376 vcl::PNGWriter
aPNGWriter(aBitmapEx
);
1377 aPNGWriter
.Write(aNew
);
1380 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmapEx
, aRect
, SRCAND
|SRCINVERT
));
1387 case EMR_BITBLT
: // PASSTHROUGH INTENDED
1388 case EMR_STRETCHBLT
:
1390 sal_Int32 xDest
, yDest
, cxDest
, cyDest
, xSrc
, ySrc
, cxSrc
, cySrc
;
1391 sal_uInt32 dwRop
, iUsageSrc
, offBmiSrc
, cbBmiSrc
, offBitsSrc
, cbBitsSrc
;
1394 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1396 mpInputStream
->SeekRel( 0x10 );
1397 mpInputStream
->ReadInt32( xDest
).ReadInt32( yDest
).ReadInt32( cxDest
).ReadInt32( cyDest
).ReadUInt32( dwRop
).ReadInt32( xSrc
).ReadInt32( ySrc
)
1399 mpInputStream
->ReadUInt32( nColor
).ReadUInt32( iUsageSrc
).ReadUInt32( offBmiSrc
).ReadUInt32( cbBmiSrc
)
1400 .ReadUInt32( offBitsSrc
).ReadUInt32( cbBitsSrc
);
1402 if ( nRecType
== EMR_STRETCHBLT
)
1403 mpInputStream
->ReadInt32( cxSrc
).ReadInt32( cySrc
);
1408 tools::Rectangle
aRect( Point( xDest
, yDest
), Size( cxDest
, cyDest
) );
1410 if (!mpInputStream
->good() || (cbBitsSrc
> (SAL_MAX_UINT32
- 14)) || ((SAL_MAX_UINT32
- 14) - cbBitsSrc
< cbBmiSrc
))
1414 sal_uInt32 nSize
= cbBmiSrc
+ cbBitsSrc
+ 14;
1415 if ( nSize
<= ( mnEndPos
- mnStartPos
) )
1417 char* pBuf
= new char[ nSize
];
1418 SvMemoryStream
aTmp( pBuf
, nSize
, StreamMode::READ
| StreamMode::WRITE
);
1419 aTmp
.ObjectOwnsMemory( true );
1420 aTmp
.WriteUChar( 'B' )
1422 .WriteUInt32( cbBitsSrc
)
1425 .WriteUInt32( cbBmiSrc
+ 14 );
1426 mpInputStream
->Seek( nStart
+ offBmiSrc
);
1427 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmiSrc
);
1428 mpInputStream
->Seek( nStart
+ offBitsSrc
);
1429 mpInputStream
->ReadBytes(pBuf
+ 14 + cbBmiSrc
, cbBitsSrc
);
1431 ReadDIB(aBitmap
, aTmp
, true);
1433 // test if it is sensible to crop
1434 if ( (cxSrc
> 0) && (cySrc
> 0) &&
1435 (xSrc
>= 0) && (ySrc
>= 0) &&
1436 (aBitmap
.GetSizePixel().Width() >= cxSrc
) &&
1437 (xSrc
<= aBitmap
.GetSizePixel().Width() - cxSrc
) &&
1438 (aBitmap
.GetSizePixel().Height() >= cySrc
) &&
1439 (ySrc
<= aBitmap
.GetSizePixel().Height() - cySrc
) )
1441 tools::Rectangle
aCropRect( Point( xSrc
, ySrc
), Size( cxSrc
, cySrc
) );
1442 aBitmap
.Crop( aCropRect
);
1445 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmap
, aRect
, dwRop
));
1451 case EMR_STRETCHDIBITS
:
1453 sal_Int32 xDest
, yDest
, xSrc
, ySrc
, cxSrc
, cySrc
, cxDest
, cyDest
;
1454 sal_uInt32 offBmiSrc
, cbBmiSrc
, offBitsSrc
, cbBitsSrc
, iUsageSrc
, dwRop
;
1455 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1457 mpInputStream
->SeekRel( 0x10 );
1458 mpInputStream
->ReadInt32( xDest
)
1464 .ReadUInt32( offBmiSrc
)
1465 .ReadUInt32( cbBmiSrc
)
1466 .ReadUInt32( offBitsSrc
)
1467 .ReadUInt32( cbBitsSrc
)
1468 .ReadUInt32( iUsageSrc
)
1469 .ReadUInt32( dwRop
)
1470 .ReadInt32( cxDest
)
1471 .ReadInt32( cyDest
);
1473 if (!mpInputStream
->good() ||
1474 ((SAL_MAX_UINT32
- 14) < cbBitsSrc
) ||
1475 ((SAL_MAX_UINT32
- 14) - cbBitsSrc
< cbBmiSrc
))
1482 tools::Rectangle
aRect(xDest
, yDest
);
1483 aRect
.SaturatingSetSize(Size(cxDest
, cyDest
));
1485 sal_uInt32 nSize
= cbBmiSrc
+ cbBitsSrc
+ 14;
1486 if ( nSize
<= ( mnEndPos
- mnStartPos
) )
1488 char* pBuf
= new char[ nSize
];
1489 SvMemoryStream
aTmp( pBuf
, nSize
, StreamMode::READ
| StreamMode::WRITE
);
1490 aTmp
.ObjectOwnsMemory( true );
1491 aTmp
.WriteUChar( 'B' )
1493 .WriteUInt32( cbBitsSrc
)
1496 .WriteUInt32( cbBmiSrc
+ 14 );
1497 mpInputStream
->Seek( nStart
+ offBmiSrc
);
1498 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmiSrc
);
1499 mpInputStream
->Seek( nStart
+ offBitsSrc
);
1500 mpInputStream
->ReadBytes(pBuf
+ 14 + cbBmiSrc
, cbBitsSrc
);
1502 ReadDIB(aBitmap
, aTmp
, true);
1504 // test if it is sensible to crop
1505 if ( (cxSrc
> 0) && (cySrc
> 0) &&
1506 (xSrc
>= 0) && (ySrc
>= 0) &&
1507 (aBitmap
.GetSizePixel().Width() >= cxSrc
) &&
1508 (xSrc
<= aBitmap
.GetSizePixel().Width() - cxSrc
) &&
1509 (aBitmap
.GetSizePixel().Height() >= cySrc
) &&
1510 (ySrc
<= aBitmap
.GetSizePixel().Height() - cySrc
) )
1512 tools::Rectangle
aCropRect( Point( xSrc
, ySrc
), Size( cxSrc
, cySrc
) );
1513 aBitmap
.Crop( aCropRect
);
1515 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmap
, aRect
, dwRop
));
1521 case EMR_EXTCREATEFONTINDIRECTW
:
1523 mpInputStream
->ReadUInt32( nIndex
);
1524 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1527 mpInputStream
->ReadInt32( aLogFont
.lfHeight
)
1528 .ReadInt32( aLogFont
.lfWidth
)
1529 .ReadInt32( aLogFont
.lfEscapement
)
1530 .ReadInt32( aLogFont
.lfOrientation
)
1531 .ReadInt32( aLogFont
.lfWeight
)
1532 .ReadUChar( aLogFont
.lfItalic
)
1533 .ReadUChar( aLogFont
.lfUnderline
)
1534 .ReadUChar( aLogFont
.lfStrikeOut
)
1535 .ReadUChar( aLogFont
.lfCharSet
)
1536 .ReadUChar( aLogFont
.lfOutPrecision
)
1537 .ReadUChar( aLogFont
.lfClipPrecision
)
1538 .ReadUChar( aLogFont
.lfQuality
)
1539 .ReadUChar( aLogFont
.lfPitchAndFamily
);
1541 sal_Unicode lfFaceName
[LF_FACESIZE
+1];
1542 lfFaceName
[LF_FACESIZE
] = 0;
1543 for (int i
= 0; i
< LF_FACESIZE
; ++i
)
1545 sal_uInt16
nChar(0);
1546 mpInputStream
->ReadUInt16(nChar
);
1547 lfFaceName
[i
] = nChar
;
1549 aLogFont
.alfFaceName
= OUString( lfFaceName
);
1551 // #i123216# Not used in the test case of #121382# (always identity in XForm), also
1552 // no hints in ms docu if FontSize should be scaled with WT. Using with the example
1553 // from #i123216# creates errors, so removing.
1555 // // #i121382# Need to apply WorldTransform to FontHeight/Width; this should be completely
1556 // // changed to basegfx::B2DHomMatrix instead of 'struct XForm', but not now due to time
1557 // // constraints and dangers
1558 // const XForm& rXF = GetWorldTransform();
1559 // const basegfx::B2DHomMatrix aWT(rXF.eM11, rXF.eM21, rXF.eDx, rXF.eM12, rXF.eM22, rXF.eDy);
1560 // const basegfx::B2DVector aTransVec(aWT * basegfx::B2DVector(aLogFont.lfWidth, aLogFont.lfHeight));
1561 // aLogFont.lfWidth = aTransVec.getX();
1562 // aLogFont.lfHeight = aTransVec.getY();
1563 if (mpInputStream
->good() && aLogFont
.lfHeight
!= SAL_MIN_INT32
&& aLogFont
.lfWidth
!= SAL_MIN_INT32
)
1565 CreateObjectIndexed(nIndex
, o3tl::make_unique
<WinMtfFontStyle
>( aLogFont
));
1571 case EMR_EXTTEXTOUTA
:
1574 case EMR_EXTTEXTOUTW
:
1576 sal_Int32 nLeft
, nTop
, nRight
, nBottom
, ptlReferenceX
, ptlReferenceY
, nGfxMode
, nXScale
, nYScale
;
1577 sal_uInt32 nOffString
, nOptions
, offDx
;
1580 nCurPos
= mpInputStream
->Tell() - 8;
1582 mpInputStream
->ReadInt32( nLeft
).ReadInt32( nTop
).ReadInt32( nRight
).ReadInt32( nBottom
).ReadInt32( nGfxMode
).ReadInt32( nXScale
).ReadInt32( nYScale
)
1583 .ReadInt32( ptlReferenceX
).ReadInt32( ptlReferenceY
).ReadInt32( nLen
).ReadUInt32( nOffString
).ReadUInt32( nOptions
);
1585 mpInputStream
->SeekRel( 0x10 );
1586 mpInputStream
->ReadUInt32( offDx
);
1588 ComplexTextLayoutFlags nTextLayoutMode
= ComplexTextLayoutFlags::Default
;
1589 if ( nOptions
& ETO_RTLREADING
)
1590 nTextLayoutMode
= ComplexTextLayoutFlags::BiDiRtl
| ComplexTextLayoutFlags::TextOriginLeft
;
1591 SetTextLayoutMode( nTextLayoutMode
);
1592 SAL_WARN_IF( ( nOptions
& ( ETO_PDY
| ETO_GLYPH_INDEX
) ) != 0, "emfio", "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" );
1594 Point
aPos( ptlReferenceX
, ptlReferenceY
);
1595 bool bLenSane
= nLen
> 0 && nLen
< static_cast<sal_Int32
>( SAL_MAX_UINT32
/ sizeof(sal_Int32
) );
1596 bool bOffStringSane
= nOffString
<= mnEndPos
- nCurPos
;
1597 if (bLenSane
&& bOffStringSane
)
1599 mpInputStream
->Seek( nCurPos
+ nOffString
);
1603 if ( nLen
<= static_cast<sal_Int32
>( mnEndPos
- mpInputStream
->Tell() ) )
1605 std::unique_ptr
<sal_Char
[]> pBuf(new sal_Char
[ nLen
]);
1606 mpInputStream
->ReadBytes(pBuf
.get(), nLen
);
1607 aText
= OUString(pBuf
.get(), nLen
, GetCharSet());
1612 if ( ( nLen
* sizeof(sal_Unicode
) ) <= ( mnEndPos
- mpInputStream
->Tell() ) )
1614 aText
= read_uInt16s_ToOUString(*mpInputStream
, nLen
);
1618 std::unique_ptr
<long[]> pDXAry
, pDYAry
;
1621 bool bOverflow
= o3tl::checked_multiply
<sal_Int32
>(nLen
, (nOptions
& ETO_PDY
) ? 8 : 4, nDxSize
);
1622 if (!bOverflow
&& offDx
&& ((nCurPos
+ offDx
+ nDxSize
) <= nNextPos
) && nNextPos
<= mnEndPos
)
1624 mpInputStream
->Seek( nCurPos
+ offDx
);
1625 pDXAry
.reset( new long[aText
.getLength()] );
1626 if (nOptions
& ETO_PDY
)
1628 pDYAry
.reset( new long[aText
.getLength()] );
1631 for (sal_Int32 i
= 0; i
< aText
.getLength(); ++i
)
1633 sal_Int32 nDxCount
= 1;
1634 if (aText
.getLength() != nLen
)
1636 sal_Unicode cUniChar
= aText
[i
];
1637 OString
aTmp(&cUniChar
, 1, GetCharSet());
1638 if (aTmp
.getLength() > 1)
1640 nDxCount
= aTmp
.getLength();
1644 sal_Int32 nDx
= 0, nDy
= 0;
1647 sal_Int32 nDxTmp
= 0;
1648 mpInputStream
->ReadInt32(nDxTmp
);
1650 if (nOptions
& ETO_PDY
)
1652 sal_Int32 nDyTmp
= 0;
1653 mpInputStream
->ReadInt32(nDyTmp
);
1659 if (nOptions
& ETO_PDY
)
1665 DrawText(aPos
, aText
, pDXAry
.get(), pDYAry
.get(), mbRecordPath
, nGfxMode
);
1670 case EMR_POLYBEZIERTO16
:
1671 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int16
>(true, nNextPos
), true, mbRecordPath
);
1674 case EMR_POLYBEZIER16
:
1675 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int16
>(false, nNextPos
), false, mbRecordPath
);
1678 case EMR_POLYGON16
:
1679 DrawPolygon(ReadPolygonWithSkip
<sal_Int16
>(false, nNextPos
), mbRecordPath
);
1682 case EMR_POLYLINETO16
:
1683 DrawPolyLine(ReadPolygonWithSkip
<sal_Int16
>(true, nNextPos
), true, mbRecordPath
);
1686 case EMR_POLYLINE16
:
1687 DrawPolyLine(ReadPolygonWithSkip
<sal_Int16
>(false, nNextPos
), false, mbRecordPath
);
1690 case EMR_POLYPOLYLINE16
:
1691 ReadAndDrawPolyLine
<sal_Int16
>(nNextPos
);
1694 case EMR_POLYPOLYGON16
:
1695 ReadAndDrawPolyPolygon
<sal_Int16
>(nNextPos
);
1701 tools::PolyPolygon aPolyPoly
;
1702 mpInputStream
->SeekRel( 0x10 );
1703 mpInputStream
->ReadUInt32( nLen
).ReadUInt32( nIndex
);
1705 if ( ImplReadRegion( aPolyPoly
, *mpInputStream
, nRecSize
) )
1708 SelectObject( nIndex
);
1709 DrawPolyPolygon( aPolyPoly
);
1715 case EMR_CREATEDIBPATTERNBRUSHPT
:
1717 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1720 mpInputStream
->ReadUInt32( nIndex
);
1722 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1724 sal_uInt32 usage
, offBmi
, cbBmi
, offBits
, cbBits
;
1726 mpInputStream
->ReadUInt32( usage
);
1727 mpInputStream
->ReadUInt32( offBmi
);
1728 mpInputStream
->ReadUInt32( cbBmi
);
1729 mpInputStream
->ReadUInt32( offBits
);
1730 mpInputStream
->ReadUInt32( cbBits
);
1732 if ( (cbBits
> (SAL_MAX_UINT32
- 14)) || ((SAL_MAX_UINT32
- 14) - cbBits
< cbBmi
) )
1736 sal_uInt32 nSize
= cbBmi
+ cbBits
+ 14;
1737 if ( nSize
<= ( mnEndPos
- mnStartPos
) )
1739 char* pBuf
= new char[ nSize
];
1741 SvMemoryStream
aTmp( pBuf
, nSize
, StreamMode::READ
| StreamMode::WRITE
);
1742 aTmp
.ObjectOwnsMemory( true );
1743 aTmp
.WriteUChar( 'B' )
1745 .WriteUInt32( cbBits
)
1748 .WriteUInt32( cbBmi
+ 14 );
1749 mpInputStream
->Seek( nStart
+ offBmi
);
1750 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmi
);
1751 mpInputStream
->Seek( nStart
+ offBits
);
1752 mpInputStream
->ReadBytes(pBuf
+ 14 + cbBmi
, cbBits
);
1754 ReadDIB(aBitmap
, aTmp
, true);
1759 CreateObjectIndexed(nIndex
, o3tl::make_unique
<WinMtfFillStyle
>( aBitmap
));
1763 case EMR_MASKBLT
: SAL_INFO("emfio", "not implemented 'MaskBlt'"); break;
1764 case EMR_PLGBLT
: SAL_INFO("emfio", "not implemented 'PlgBlt'"); break;
1765 case EMR_SETDIBITSTODEVICE
: SAL_INFO("emfio", "not implemented 'SetDIBitsToDevice'"); break;
1766 case EMR_FRAMERGN
: SAL_INFO("emfio", "not implemented 'FrameRgn'"); break;
1767 case EMR_INVERTRGN
: SAL_INFO("emfio", "not implemented 'InvertRgn'"); break;
1768 case EMR_PAINTRGN
: SAL_INFO("emfio", "not implemented 'PaintRgn'"); break;
1769 case EMR_FLATTENPATH
: SAL_INFO("emfio", "not implemented 'FlattenPath'"); break;
1770 case EMR_WIDENPATH
: SAL_INFO("emfio", "not implemented 'WidenPath'"); break;
1771 case EMR_POLYDRAW
: SAL_INFO("emfio", "not implemented 'Polydraw'"); break;
1772 case EMR_SETARCDIRECTION
: SAL_INFO("emfio", "not implemented 'SetArcDirection'"); break;
1773 case EMR_SETPALETTEENTRIES
: SAL_INFO("emfio", "not implemented 'SetPaletteEntries'"); break;
1774 case EMR_RESIZEPALETTE
: SAL_INFO("emfio", "not implemented 'ResizePalette'"); break;
1775 case EMR_EXTFLOODFILL
: SAL_INFO("emfio", "not implemented 'ExtFloodFill'"); break;
1776 case EMR_ANGLEARC
: SAL_INFO("emfio", "not implemented 'AngleArc'"); break;
1777 case EMR_SETCOLORADJUSTMENT
: SAL_INFO("emfio", "not implemented 'SetColorAdjustment'"); break;
1778 case EMR_POLYDRAW16
: SAL_INFO("emfio", "not implemented 'PolyDraw16'"); break;
1779 case EMR_POLYTEXTOUTA
: SAL_INFO("emfio", "not implemented 'PolyTextOutA'"); break;
1780 case EMR_POLYTEXTOUTW
: SAL_INFO("emfio", "not implemented 'PolyTextOutW'"); break;
1781 case EMR_CREATECOLORSPACE
: SAL_INFO("emfio", "not implemented 'CreateColorSpace'"); break;
1782 case EMR_SETCOLORSPACE
: SAL_INFO("emfio", "not implemented 'SetColorSpace'"); break;
1783 case EMR_DELETECOLORSPACE
: SAL_INFO("emfio", "not implemented 'DeleteColorSpace'"); break;
1784 case EMR_GLSRECORD
: SAL_INFO("emfio", "not implemented 'GlsRecord'"); break;
1785 case EMR_GLSBOUNDEDRECORD
: SAL_INFO("emfio", "not implemented 'GlsBoundRecord'"); break;
1786 case EMR_PIXELFORMAT
: SAL_INFO("emfio", "not implemented 'PixelFormat'"); break;
1787 case EMR_DRAWESCAPE
: SAL_INFO("emfio", "not implemented 'DrawEscape'"); break;
1788 case EMR_EXTESCAPE
: SAL_INFO("emfio", "not implemented 'ExtEscape'"); break;
1789 case EMR_STARTDOC
: SAL_INFO("emfio", "not implemented 'StartDoc'"); break;
1790 case EMR_SMALLTEXTOUT
: SAL_INFO("emfio", "not implemented 'SmallTextOut'"); break;
1791 case EMR_FORCEUFIMAPPING
: SAL_INFO("emfio", "not implemented 'ForceUFIMapping'"); break;
1792 case EMR_NAMEDESCAPE
: SAL_INFO("emfio", "not implemented 'NamedEscape'"); break;
1793 case EMR_COLORCORRECTPALETTE
: SAL_INFO("emfio", "not implemented 'ColorCorrectPalette'"); break;
1794 case EMR_SETICMPROFILEA
: SAL_INFO("emfio", "not implemented 'SetICMProfileA'"); break;
1795 case EMR_SETICMPROFILEW
: SAL_INFO("emfio", "not implemented 'SetICMProfileW'"); break;
1796 case EMR_TRANSPARENTBLT
: SAL_INFO("emfio", "not implemented 'TransparenBlt'"); break;
1797 case EMR_TRANSPARENTDIB
: SAL_INFO("emfio", "not implemented 'TransparenDib'"); break;
1798 case EMR_GRADIENTFILL
: SAL_INFO("emfio", "not implemented 'GradientFill'"); break;
1799 case EMR_SETLINKEDUFIS
: SAL_INFO("emfio", "not implemented 'SetLinkedUFIS'"); break;
1801 case EMR_SETMAPPERFLAGS
: SAL_INFO("emfio", "not implemented 'SetMapperFlags'"); break;
1802 case EMR_SETICMMODE
: SAL_INFO("emfio", "not implemented 'SetICMMode'"); break;
1803 case EMR_CREATEMONOBRUSH
: SAL_INFO("emfio", "not implemented 'CreateMonoBrush'"); break;
1804 case EMR_SETBRUSHORGEX
: SAL_INFO("emfio", "not implemented 'SetBrushOrgEx'"); break;
1805 case EMR_SETMETARGN
: SAL_INFO("emfio", "not implemented 'SetMetArgn'"); break;
1806 case EMR_SETMITERLIMIT
: SAL_INFO("emfio", "not implemented 'SetMiterLimit'"); break;
1807 case EMR_EXCLUDECLIPRECT
: SAL_INFO("emfio", "not implemented 'ExcludeClipRect'"); break;
1808 case EMR_REALIZEPALETTE
: SAL_INFO("emfio", "not implemented 'RealizePalette'"); break;
1809 case EMR_SELECTPALETTE
: SAL_INFO("emfio", "not implemented 'SelectPalette'"); break;
1810 case EMR_CREATEPALETTE
: SAL_INFO("emfio", "not implemented 'CreatePalette'"); break;
1811 case EMR_ALPHADIBBLEND
: SAL_INFO("emfio", "not implemented 'AlphaDibBlend'"); break;
1812 case EMR_SETTEXTJUSTIFICATION
: SAL_INFO("emfio", "not implemented 'SetTextJustification'"); break;
1815 case EMR_HEADER
: // has already been read at ReadHeader()
1818 default : SAL_INFO("emfio", "Unknown Meta Action"); break;
1821 mpInputStream
->Seek( nNextPos
);
1823 if( !maBmpSaveList
.empty() )
1824 ResolveBitmapActions( maBmpSaveList
);
1827 mpInputStream
->Seek(mnEndPos
);
1832 bool EmfReader::ReadHeader()
1834 // Spare me the METAFILEHEADER here
1835 // Reading the METAHEADER - EMR_HEADER ([MS-EMF] section 2.3.4.2 EMR_HEADER Record Types)
1836 sal_uInt32
nType(0), nHeaderSize(0);
1837 mpInputStream
->ReadUInt32(nType
).ReadUInt32(nHeaderSize
);
1838 if (nType
!= 0x00000001)
1840 // per [MS-EMF] 2.3.4.2 EMF Header Record Types, type MUST be 0x00000001
1841 SAL_WARN("emfio", "EMF header type is not set to 0x00000001 - possibly corrupted file?");
1845 // Start reading the EMR_HEADER Header object
1847 // bound size (RectL object, see [MS-WMF] section 2.2.2.19)
1848 tools::Rectangle rclBounds
= ReadRectangle(); // rectangle in logical units
1850 // picture frame size (RectL object)
1851 tools::Rectangle rclFrame
= ReadRectangle(); // rectangle in device units 1/100th mm
1853 sal_uInt32
nSignature(0);
1854 mpInputStream
->ReadUInt32(nSignature
);
1856 // nSignature MUST be the ASCII characters "FME", see [WS-EMF] 2.2.9 Header Object
1857 // and 2.1.14 FormatSignature Enumeration
1858 if (nSignature
!= 0x464d4520)
1860 SAL_WARN("emfio", "EMF\t\tSignature is not 0x464d4520 (\"FME\") - possibly corrupted file?");
1864 sal_uInt32
nVersion(0);
1865 mpInputStream
->ReadUInt32(nVersion
); // according to [WS-EMF] 2.2.9, this SHOULD be 0x0001000, however
1866 // Microsoft note that not even Windows checks this...
1867 if (nVersion
!= 0x00010000)
1869 SAL_WARN("emfio", "EMF\t\tThis really should be 0x00010000, though not absolutely essential...");
1872 mpInputStream
->ReadUInt32(mnEndPos
); // size of metafile
1873 mnEndPos
+= mnStartPos
;
1875 sal_uInt32 nStrmPos
= mpInputStream
->Tell(); // checking if mnEndPos is valid
1876 sal_uInt32 nActualFileSize
= nStrmPos
+ mpInputStream
->remainingSize();
1878 if ( nActualFileSize
< mnEndPos
)
1880 SAL_WARN("emfio", "EMF\t\tEMF Header object records number of bytes as " << mnEndPos
1881 << ", however the file size is actually " << nActualFileSize
1882 << " bytes. Possible file corruption?");
1883 mnEndPos
= nActualFileSize
;
1886 mpInputStream
->ReadInt32(mnRecordCount
);
1888 if (mnRecordCount
<= 0)
1890 SAL_WARN("emfio", "EMF\t\tEMF Header object shows record counter as <= 0! This shouldn't "
1891 "be possible... indicator of possible file corruption?");
1895 // the number of "handles", or graphics objects used in the metafile
1897 sal_uInt16 nHandlesCount
;
1898 mpInputStream
->ReadUInt16(nHandlesCount
);
1900 // the next 2 bytes are reserved, but according to [MS-EMF] section 2.2.9
1901 // it MUST be 0x000 and MUST be ignored... the thing is, having such a specific
1902 // value is actually pretty useful in checking if there is possible corruption
1904 sal_uInt16
nReserved(0);
1905 mpInputStream
->ReadUInt16(nReserved
);
1907 if ( nReserved
!= 0x0000 )
1909 SAL_WARN("emfio", "EMF\t\tEMF Header object's reserved field is NOT 0x0000... possible "
1913 // The next 4 bytes specifies the number of characters in the metafile description.
1914 // The 4 bytes after that specific the offset from this record that contains the
1915 // metafile description... zero means no description string.
1916 // For now, we ignore it.
1918 mpInputStream
->SeekRel(0x8);
1920 sal_uInt32
nPalEntries(0);
1921 mpInputStream
->ReadUInt32(nPalEntries
);
1922 sal_Int32
nPixX(0), nPixY(0), nMillX(0), nMillY(0);
1923 mpInputStream
->ReadInt32(nPixX
);
1924 mpInputStream
->ReadInt32(nPixY
);
1925 mpInputStream
->ReadInt32(nMillX
);
1926 mpInputStream
->ReadInt32(nMillY
);
1928 SetrclFrame(rclFrame
);
1929 SetrclBounds(rclBounds
);
1930 SetRefPix(Size( nPixX
, nPixY
) );
1931 SetRefMill(Size( nMillX
, nMillY
) );
1933 return checkSeek(*mpInputStream
, mnStartPos
+ nHeaderSize
);
1936 tools::Rectangle
EmfReader::ReadRectangle()
1938 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
1939 mpInputStream
->ReadInt32(nLeft
);
1940 mpInputStream
->ReadInt32(nTop
);
1941 mpInputStream
->ReadInt32(nRight
);
1942 mpInputStream
->ReadInt32(nBottom
);
1943 return tools::Rectangle(nLeft
, nTop
, nRight
, nBottom
);
1946 tools::Rectangle
EmfReader::ReadRectangle( sal_Int32 x1
, sal_Int32 y1
, sal_Int32 x2
, sal_Int32 y2
)
1949 Point
aBR(o3tl::saturating_add
<sal_Int32
>(x2
, -1), o3tl::saturating_add
<sal_Int32
>(y2
, -1));
1950 return tools::Rectangle(aTL
, aBR
);
1954 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */