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 <sal/log.hxx>
23 #include <osl/diagnose.h>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <vcl/dibtools.hxx>
26 #include <o3tl/safeint.hxx>
27 #include <tools/stream.hxx>
31 #include <vcl/pngwrite.hxx>
39 #define EMR_POLYBEZIER 2
41 #define EMR_POLYLINE 4
42 #define EMR_POLYBEZIERTO 5
43 #define EMR_POLYLINETO 6
44 #define EMR_POLYPOLYLINE 7
45 #define EMR_POLYPOLYGON 8
46 #define EMR_SETWINDOWEXTEX 9
47 #define EMR_SETWINDOWORGEX 10
48 #define EMR_SETVIEWPORTEXTEX 11
49 #define EMR_SETVIEWPORTORGEX 12
50 #define EMR_SETBRUSHORGEX 13
52 #define EMR_SETPIXELV 15
53 #define EMR_SETMAPPERFLAGS 16
54 #define EMR_SETMAPMODE 17
55 #define EMR_SETBKMODE 18
56 #define EMR_SETPOLYFILLMODE 19
57 #define EMR_SETROP2 20
58 #define EMR_SETSTRETCHBLTMODE 21
59 #define EMR_SETTEXTALIGN 22
60 #define EMR_SETCOLORADJUSTMENT 23
61 #define EMR_SETTEXTCOLOR 24
62 #define EMR_SETBKCOLOR 25
63 #define EMR_OFFSETCLIPRGN 26
64 #define EMR_MOVETOEX 27
65 #define EMR_SETMETARGN 28
66 #define EMR_EXCLUDECLIPRECT 29
67 #define EMR_INTERSECTCLIPRECT 30
68 #define EMR_SCALEVIEWPORTEXTEX 31
69 #define EMR_SCALEWINDOWEXTEX 32
71 #define EMR_RESTOREDC 34
72 #define EMR_SETWORLDTRANSFORM 35
73 #define EMR_MODIFYWORLDTRANSFORM 36
74 #define EMR_SELECTOBJECT 37
75 #define EMR_CREATEPEN 38
76 #define EMR_CREATEBRUSHINDIRECT 39
77 #define EMR_DELETEOBJECT 40
78 #define EMR_ANGLEARC 41
79 #define EMR_ELLIPSE 42
80 #define EMR_RECTANGLE 43
81 #define EMR_ROUNDRECT 44
85 #define EMR_SELECTPALETTE 48
86 #define EMR_CREATEPALETTE 49
87 #define EMR_SETPALETTEENTRIES 50
88 #define EMR_RESIZEPALETTE 51
89 #define EMR_REALIZEPALETTE 52
90 #define EMR_EXTFLOODFILL 53
93 #define EMR_POLYDRAW 56
94 #define EMR_SETARCDIRECTION 57
95 #define EMR_SETMITERLIMIT 58
96 #define EMR_BEGINPATH 59
97 #define EMR_ENDPATH 60
98 #define EMR_CLOSEFIGURE 61
99 #define EMR_FILLPATH 62
100 #define EMR_STROKEANDFILLPATH 63
101 #define EMR_STROKEPATH 64
102 #define EMR_FLATTENPATH 65
103 #define EMR_WIDENPATH 66
104 #define EMR_SELECTCLIPPATH 67
105 #define EMR_ABORTPATH 68
107 #define EMR_COMMENT 70 // Contains arbitrary private data.
108 // Comment Identifiers:
109 #define EMR_COMMENT_EMFPLUS 0x2B464D45 // Contains embedded EMF+ records.
110 #define EMR_COMMENT_EMFSPOOL 0x00000000 // Contains embedded EMFSPOOL records.
111 #define EMR_COMMENT_PUBLIC 0x43494447 // Specify extensions to EMF processing.
113 #define EMR_FILLRGN 71
114 #define EMR_FRAMERGN 72
115 #define EMR_INVERTRGN 73
116 #define EMR_PAINTRGN 74
117 #define EMR_EXTSELECTCLIPRGN 75
118 #define EMR_BITBLT 76
119 #define EMR_STRETCHBLT 77
120 #define EMR_MASKBLT 78
121 #define EMR_PLGBLT 79
122 #define EMR_SETDIBITSTODEVICE 80
123 #define EMR_STRETCHDIBITS 81
124 #define EMR_EXTCREATEFONTINDIRECTW 82
125 #define EMR_EXTTEXTOUTA 83
126 #define EMR_EXTTEXTOUTW 84
127 #define EMR_POLYBEZIER16 85
128 #define EMR_POLYGON16 86
129 #define EMR_POLYLINE16 87
130 #define EMR_POLYBEZIERTO16 88
131 #define EMR_POLYLINETO16 89
132 #define EMR_POLYPOLYLINE16 90
133 #define EMR_POLYPOLYGON16 91
134 #define EMR_POLYDRAW16 92
135 #define EMR_CREATEMONOBRUSH 93
136 #define EMR_CREATEDIBPATTERNBRUSHPT 94
137 #define EMR_EXTCREATEPEN 95
138 #define EMR_POLYTEXTOUTA 96
139 #define EMR_POLYTEXTOUTW 97
141 // WINDOWS VERSION >= 0x400
142 #define EMR_SETICMMODE 98
143 #define EMR_CREATECOLORSPACE 99
144 #define EMR_SETCOLORSPACE 100
145 #define EMR_DELETECOLORSPACE 101
146 #define EMR_GLSRECORD 102
147 #define EMR_GLSBOUNDEDRECORD 103
148 #define EMR_PIXELFORMAT 104
150 // WINDOWS VERSION >= 0x500
151 #define EMR_DRAWESCAPE 105
152 #define EMR_EXTESCAPE 106
153 #define EMR_STARTDOC 107
154 #define EMR_SMALLTEXTOUT 108
155 #define EMR_FORCEUFIMAPPING 109
156 #define EMR_NAMEDESCAPE 110
157 #define EMR_COLORCORRECTPALETTE 111
158 #define EMR_SETICMPROFILEA 112
159 #define EMR_SETICMPROFILEW 113
160 #define EMR_ALPHABLEND 114
161 #define EMR_ALPHADIBBLEND 115
162 #define EMR_TRANSPARENTBLT 116
163 #define EMR_TRANSPARENTDIB 117
164 #define EMR_GRADIENTFILL 118
165 #define EMR_SETLINKEDUFIS 119
166 #define EMR_SETTEXTJUSTIFICATION 120
172 record_type_name(sal_uInt32 nRecType
)
180 case EMR_HEADER
: return "HEADER";
181 case EMR_POLYBEZIER
: return "POLYBEZIER";
182 case EMR_POLYGON
: return "POLYGON";
183 case EMR_POLYLINE
: return "POLYLINE";
184 case EMR_POLYBEZIERTO
: return "POLYBEZIERTO";
185 case EMR_POLYLINETO
: return "POLYLINETO";
186 case EMR_POLYPOLYLINE
: return "POLYPOLYLINE";
187 case EMR_POLYPOLYGON
: return "POLYPOLYGON";
188 case EMR_SETWINDOWEXTEX
: return "SETWINDOWEXTEX";
189 case EMR_SETWINDOWORGEX
: return "SETWINDOWORGEX";
190 case EMR_SETVIEWPORTEXTEX
: return "SETVIEWPORTEXTEX";
191 case EMR_SETVIEWPORTORGEX
: return "SETVIEWPORTORGEX";
192 case EMR_SETBRUSHORGEX
: return "SETBRUSHORGEX";
193 case EMR_EOF
: return "EOF";
194 case EMR_SETPIXELV
: return "SETPIXELV";
195 case EMR_SETMAPPERFLAGS
: return "SETMAPPERFLAGS";
196 case EMR_SETMAPMODE
: return "SETMAPMODE";
197 case EMR_SETBKMODE
: return "SETBKMODE";
198 case EMR_SETPOLYFILLMODE
: return "SETPOLYFILLMODE";
199 case EMR_SETROP2
: return "SETROP2";
200 case EMR_SETSTRETCHBLTMODE
: return "SETSTRETCHBLTMODE";
201 case EMR_SETTEXTALIGN
: return "SETTEXTALIGN";
202 case EMR_SETCOLORADJUSTMENT
: return "SETCOLORADJUSTMENT";
203 case EMR_SETTEXTCOLOR
: return "SETTEXTCOLOR";
204 case EMR_SETBKCOLOR
: return "SETBKCOLOR";
205 case EMR_OFFSETCLIPRGN
: return "OFFSETCLIPRGN";
206 case EMR_MOVETOEX
: return "MOVETOEX";
207 case EMR_SETMETARGN
: return "SETMETARGN";
208 case EMR_EXCLUDECLIPRECT
: return "EXCLUDECLIPRECT";
209 case EMR_INTERSECTCLIPRECT
: return "INTERSECTCLIPRECT";
210 case EMR_SCALEVIEWPORTEXTEX
: return "SCALEVIEWPORTEXTEX";
211 case EMR_SCALEWINDOWEXTEX
: return "SCALEWINDOWEXTEX";
212 case EMR_SAVEDC
: return "SAVEDC";
213 case EMR_RESTOREDC
: return "RESTOREDC";
214 case EMR_SETWORLDTRANSFORM
: return "SETWORLDTRANSFORM";
215 case EMR_MODIFYWORLDTRANSFORM
: return "MODIFYWORLDTRANSFORM";
216 case EMR_SELECTOBJECT
: return "SELECTOBJECT";
217 case EMR_CREATEPEN
: return "CREATEPEN";
218 case EMR_CREATEBRUSHINDIRECT
: return "CREATEBRUSHINDIRECT";
219 case EMR_DELETEOBJECT
: return "DELETEOBJECT";
220 case EMR_ANGLEARC
: return "ANGLEARC";
221 case EMR_ELLIPSE
: return "ELLIPSE";
222 case EMR_RECTANGLE
: return "RECTANGLE";
223 case EMR_ROUNDRECT
: return "ROUNDRECT";
224 case EMR_ARC
: return "ARC";
225 case EMR_CHORD
: return "CHORD";
226 case EMR_PIE
: return "PIE";
227 case EMR_SELECTPALETTE
: return "SELECTPALETTE";
228 case EMR_CREATEPALETTE
: return "CREATEPALETTE";
229 case EMR_SETPALETTEENTRIES
: return "SETPALETTEENTRIES";
230 case EMR_RESIZEPALETTE
: return "RESIZEPALETTE";
231 case EMR_REALIZEPALETTE
: return "REALIZEPALETTE";
232 case EMR_EXTFLOODFILL
: return "EXTFLOODFILL";
233 case EMR_LINETO
: return "LINETO";
234 case EMR_ARCTO
: return "ARCTO";
235 case EMR_POLYDRAW
: return "POLYDRAW";
236 case EMR_SETARCDIRECTION
: return "SETARCDIRECTION";
237 case EMR_SETMITERLIMIT
: return "SETMITERLIMIT";
238 case EMR_BEGINPATH
: return "BEGINPATH";
239 case EMR_ENDPATH
: return "ENDPATH";
240 case EMR_CLOSEFIGURE
: return "CLOSEFIGURE";
241 case EMR_FILLPATH
: return "FILLPATH";
242 case EMR_STROKEANDFILLPATH
: return "STROKEANDFILLPATH";
243 case EMR_STROKEPATH
: return "STROKEPATH";
244 case EMR_FLATTENPATH
: return "FLATTENPATH";
245 case EMR_WIDENPATH
: return "WIDENPATH";
246 case EMR_SELECTCLIPPATH
: return "SELECTCLIPPATH";
247 case EMR_ABORTPATH
: return "ABORTPATH";
248 case EMR_COMMENT
: return "COMMENT";
249 case EMR_FILLRGN
: return "FILLRGN";
250 case EMR_FRAMERGN
: return "FRAMERGN";
251 case EMR_INVERTRGN
: return "INVERTRGN";
252 case EMR_PAINTRGN
: return "PAINTRGN";
253 case EMR_EXTSELECTCLIPRGN
: return "EXTSELECTCLIPRGN";
254 case EMR_BITBLT
: return "BITBLT";
255 case EMR_STRETCHBLT
: return "STRETCHBLT";
256 case EMR_MASKBLT
: return "MASKBLT";
257 case EMR_PLGBLT
: return "PLGBLT";
258 case EMR_SETDIBITSTODEVICE
: return "SETDIBITSTODEVICE";
259 case EMR_STRETCHDIBITS
: return "STRETCHDIBITS";
260 case EMR_EXTCREATEFONTINDIRECTW
: return "EXTCREATEFONTINDIRECTW";
261 case EMR_EXTTEXTOUTA
: return "EXTTEXTOUTA";
262 case EMR_EXTTEXTOUTW
: return "EXTTEXTOUTW";
263 case EMR_POLYBEZIER16
: return "POLYBEZIER16";
264 case EMR_POLYGON16
: return "POLYGON16";
265 case EMR_POLYLINE16
: return "POLYLINE16";
266 case EMR_POLYBEZIERTO16
: return "POLYBEZIERTO16";
267 case EMR_POLYLINETO16
: return "POLYLINETO16";
268 case EMR_POLYPOLYLINE16
: return "POLYPOLYLINE16";
269 case EMR_POLYPOLYGON16
: return "POLYPOLYGON16";
270 case EMR_POLYDRAW16
: return "POLYDRAW16";
271 case EMR_CREATEMONOBRUSH
: return "CREATEMONOBRUSH";
272 case EMR_CREATEDIBPATTERNBRUSHPT
: return "CREATEDIBPATTERNBRUSHPT";
273 case EMR_EXTCREATEPEN
: return "EXTCREATEPEN";
274 case EMR_POLYTEXTOUTA
: return "POLYTEXTOUTA";
275 case EMR_POLYTEXTOUTW
: return "POLYTEXTOUTW";
276 case EMR_SETICMMODE
: return "SETICMMODE";
277 case EMR_CREATECOLORSPACE
: return "CREATECOLORSPACE";
278 case EMR_SETCOLORSPACE
: return "SETCOLORSPACE";
279 case EMR_DELETECOLORSPACE
: return "DELETECOLORSPACE";
280 case EMR_GLSRECORD
: return "GLSRECORD";
281 case EMR_GLSBOUNDEDRECORD
: return "GLSBOUNDEDRECORD";
282 case EMR_PIXELFORMAT
: return "PIXELFORMAT";
283 case EMR_DRAWESCAPE
: return "DRAWESCAPE";
284 case EMR_EXTESCAPE
: return "EXTESCAPE";
285 case EMR_STARTDOC
: return "STARTDOC";
286 case EMR_SMALLTEXTOUT
: return "SMALLTEXTOUT";
287 case EMR_FORCEUFIMAPPING
: return "FORCEUFIMAPPING";
288 case EMR_NAMEDESCAPE
: return "NAMEDESCAPE";
289 case EMR_COLORCORRECTPALETTE
: return "COLORCORRECTPALETTE";
290 case EMR_SETICMPROFILEA
: return "SETICMPROFILEA";
291 case EMR_SETICMPROFILEW
: return "SETICMPROFILEW";
292 case EMR_ALPHABLEND
: return "ALPHABLEND";
293 case EMR_ALPHADIBBLEND
: return "ALPHADIBBLEND";
294 case EMR_TRANSPARENTBLT
: return "TRANSPARENTBLT";
295 case EMR_TRANSPARENTDIB
: return "TRANSPARENTDIB";
296 case EMR_GRADIENTFILL
: return "GRADIENTFILL";
297 case EMR_SETLINKEDUFIS
: return "SETLINKEDUFIS";
298 case EMR_SETTEXTJUSTIFICATION
: return "SETTEXTJUSTIFICATION";
300 // Yes, return a pointer to a static buffer. This is a very
301 // local debugging output function, so no big deal.
302 static char buffer
[11];
303 sprintf(buffer
, "0x%08" SAL_PRIxUINT32
, nRecType
);
311 unsigned char aBlendOperation
;
312 unsigned char aBlendFlags
;
313 unsigned char aSrcConstantAlpha
;
314 unsigned char aAlphaFormat
;
316 friend SvStream
& operator>>(SvStream
& rInStream
, BLENDFUNCTION
& rBlendFun
);
319 SvStream
& operator>>(SvStream
& rInStream
, BLENDFUNCTION
& rBlendFun
)
321 rInStream
.ReadUChar(rBlendFun
.aBlendOperation
);
322 rInStream
.ReadUChar(rBlendFun
.aBlendFlags
);
323 rInStream
.ReadUChar(rBlendFun
.aSrcConstantAlpha
);
324 rInStream
.ReadUChar(rBlendFun
.aAlphaFormat
);
328 bool ImplReadRegion( tools::PolyPolygon
& rPolyPoly
, SvStream
& rStream
, sal_uInt32 nLen
)
333 sal_uInt32 nHdSize
, nType
, nCount
, nRgnSize
, i
;
334 rStream
.ReadUInt32(nHdSize
);
335 rStream
.ReadUInt32(nType
);
336 rStream
.ReadUInt32(nCount
);
337 rStream
.ReadUInt32(nRgnSize
);
339 if (!rStream
.good() || nCount
== 0 || nType
!= RDH_RECTANGLES
)
343 if (o3tl::checked_multiply
<sal_uInt32
>(nCount
, 16, nSize
))
345 if (o3tl::checked_add
<sal_uInt32
>(nSize
, nHdSize
- 16, nSize
))
350 sal_Int32 nx1
, ny1
, nx2
, ny2
;
351 for (i
= 0; i
< nCount
; i
++)
353 rStream
.ReadInt32(nx1
);
354 rStream
.ReadInt32(ny1
);
355 rStream
.ReadInt32(nx2
);
356 rStream
.ReadInt32(ny2
);
358 tools::Rectangle
aRectangle(Point(nx1
, ny1
), Point(nx2
, ny2
));
360 tools::Polygon
aPolygon(aRectangle
);
361 tools::PolyPolygon
aPolyPolyOr1(aPolygon
);
362 tools::PolyPolygon
aPolyPolyOr2(rPolyPoly
);
363 rPolyPoly
.GetUnion(aPolyPolyOr1
, aPolyPolyOr2
);
364 rPolyPoly
= aPolyPolyOr2
;
369 } // anonymous namespace
373 EmfReader::EmfReader(SvStream
& rStream
,GDIMetaFile
& rGDIMetaFile
)
374 : MtfTools(rGDIMetaFile
, rStream
)
376 , mbRecordPath(false)
378 ,mbEMFPlusDualMode(false)
382 EmfReader::~EmfReader()
386 void EmfReader::ReadEMFPlusComment(sal_uInt32 length
, bool& bHaveDC
)
390 PassEMFPlusHeaderInfo();
392 #if OSL_DEBUG_LEVEL > 1
393 // debug code - write the stream to debug file /tmp/emf-stream.emf
394 sal_uInt64
const pos
= mpInputStream
->Tell();
395 mpInputStream
->Seek(0);
396 SvFileStream
file( OUString( "/tmp/emf-stream.emf" ), StreamMode::WRITE
| StreamMode::TRUNC
);
398 mpInputStream
->WriteStream(file
);
402 mpInputStream
->Seek( pos
);
408 sal_uInt64
const pos
= mpInputStream
->Tell();
409 auto buffer
= std::make_unique
<char[]>( length
);
410 PassEMFPlus( buffer
.get(), mpInputStream
->ReadBytes(buffer
.get(), length
) );
412 mpInputStream
->Seek( pos
);
416 // skip in SeekRel if impossibly unavailable
417 sal_uInt32 nRemainder
= length
;
419 const size_t nRequiredHeaderSize
= 12;
420 while (nRemainder
>= nRequiredHeaderSize
)
422 sal_uInt16
type(0), flags(0);
423 sal_uInt32
size(0), dataSize(0);
425 mpInputStream
->ReadUInt16( type
).ReadUInt16( flags
).ReadUInt32( size
).ReadUInt32( dataSize
);
426 nRemainder
-= nRequiredHeaderSize
;
428 SAL_INFO ("emfio", "\t\tEMF+ record type: " << std::hex
<< type
<< std::dec
);
430 // Get Device Context
431 // TODO We should use EmfPlusRecordType::GetDC instead
435 SAL_INFO ("emfio", "\t\tEMF+ lock DC (device context)");
438 // look for the "dual mode" in header
439 // it indicates that either EMF or EMF+ records should be processed
440 // 0x4001 = EMF+ header
441 // flags & 1 = dual mode active
442 if ( type
== 0x4001 && flags
& 1 )
444 mbEMFPlusDualMode
= true;
447 // Get the length of the remaining data of this record based
448 // on the alleged size
449 sal_uInt32 nRemainingRecordData
= size
>= nRequiredHeaderSize
?
450 size
-nRequiredHeaderSize
: 0;
451 // clip to available size
452 nRemainingRecordData
= std::min(nRemainingRecordData
, nRemainder
);
453 mpInputStream
->SeekRel(nRemainingRecordData
);
454 nRemainder
-= nRemainingRecordData
;
456 mpInputStream
->SeekRel(nRemainder
);
459 // these are referenced from inside the templates
460 static SvStream
& operator >> (SvStream
& rStream
, sal_Int16
&n
)
462 return rStream
.ReadInt16(n
);
465 static SvStream
& operator >> (SvStream
& rStream
, sal_Int32
&n
)
467 return rStream
.ReadInt32(n
);
471 * Reads polygons from the stream.
472 * The \<class T> parameter is for the type of the points (sal_uInt32 or sal_uInt16).
473 * skipFirst: if the first point read is the 0th point or the 1st point in the array.
476 tools::Polygon
EmfReader::ReadPolygonWithSkip(const bool skipFirst
, sal_uInt32 nNextPos
)
478 sal_uInt32
nPoints(0), nStartIndex(0);
479 mpInputStream
->SeekRel( 16 );
480 mpInputStream
->ReadUInt32( nPoints
);
487 return ReadPolygon
<T
>(nStartIndex
, nPoints
, nNextPos
);
491 * Reads polygons from the stream.
492 * The \<class T> parameter is for the type of the points
493 * nStartIndex: which is the starting index in the polygon of the first point read
494 * nPoints: number of points
495 * mpInputStream: the stream containing the polygons
498 tools::Polygon
EmfReader::ReadPolygon(sal_uInt32 nStartIndex
, sal_uInt32 nPoints
, sal_uInt32 nNextPos
)
500 bool bRecordOk
= nPoints
<= SAL_MAX_UINT16
;
501 SAL_WARN_IF(!bRecordOk
, "emfio", "polygon record has more polygons than we can handle");
502 if (!bRecordOk
|| !nPoints
)
503 return tools::Polygon();
505 auto nRemainingSize
= std::min(nNextPos
- mpInputStream
->Tell(), mpInputStream
->remainingSize());
506 auto nMaxPossiblePoints
= nRemainingSize
/ (sizeof(T
) * 2);
507 auto nPointCount
= nPoints
- nStartIndex
;
508 if (nPointCount
> nMaxPossiblePoints
)
510 SAL_WARN("emfio", "polygon claims more points than record can provide, truncating");
511 nPoints
= nMaxPossiblePoints
+ nStartIndex
;
514 tools::Polygon
aPolygon(nPoints
);
515 for (sal_uInt32 i
= nStartIndex
; i
< nPoints
&& mpInputStream
->good(); i
++ )
518 *mpInputStream
>> nX
>> nY
;
519 if (!mpInputStream
->good())
521 SAL_WARN("emfio", "short read on polygon, truncating");
525 aPolygon
[ i
] = Point( nX
, nY
);
532 * Reads a polyline from the WMF file and draws it
533 * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
536 void EmfReader::ReadAndDrawPolyLine(sal_uInt32 nNextPos
)
539 sal_uInt32 i
, nNumberOfPolylines( 0 ), nCount( 0 );
540 mpInputStream
->SeekRel( 0x10 ); // TODO Skipping Bounds. A 128-bit WMF RectL object (specifies the bounding rectangle in device units.)
541 mpInputStream
->ReadUInt32( nNumberOfPolylines
);
542 mpInputStream
->ReadUInt32( nCount
); // total number of points in all polylines
543 const auto nEndPos
= std::min(nNextPos
, mnEndPos
);
544 if (mpInputStream
->Tell() >= nEndPos
)
547 // taking the amount of points of each polygon, retrieving the total number of points
548 if ( mpInputStream
->good() &&
549 ( nNumberOfPolylines
< SAL_MAX_UINT32
/ sizeof( sal_uInt16
) ) &&
550 ( nNumberOfPolylines
* sizeof( sal_uInt16
) ) <= ( nEndPos
- mpInputStream
->Tell() )
553 std::unique_ptr
< sal_uInt32
[] > pnPolylinePointCount( new sal_uInt32
[ nNumberOfPolylines
] );
554 for ( i
= 0; i
< nNumberOfPolylines
&& mpInputStream
->good(); i
++ )
556 mpInputStream
->ReadUInt32( nPoints
);
557 pnPolylinePointCount
[ i
] = nPoints
;
559 // Get polyline points:
560 for ( i
= 0; ( i
< nNumberOfPolylines
) && mpInputStream
->good(); i
++ )
562 tools::Polygon aPolygon
= ReadPolygon
<T
>(0, pnPolylinePointCount
[i
], nNextPos
);
563 DrawPolyLine(aPolygon
, false, mbRecordPath
);
569 * Reads a poly polygon from the WMF file and draws it.
570 * The \<class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32)
573 void EmfReader::ReadAndDrawPolyPolygon(sal_uInt32 nNextPos
)
575 sal_uInt32
nPoly(0), nGesPoints(0), nReadPoints(0);
576 mpInputStream
->SeekRel( 0x10 );
577 // Number of polygons
578 mpInputStream
->ReadUInt32( nPoly
).ReadUInt32( nGesPoints
);
579 const auto nEndPos
= std::min(nNextPos
, mnEndPos
);
580 if (mpInputStream
->Tell() >= nEndPos
)
582 if (!mpInputStream
->good())
584 //check against numeric overflowing
585 if (nGesPoints
>= SAL_MAX_UINT32
/ sizeof(Point
))
587 if (nPoly
>= SAL_MAX_UINT32
/ sizeof(sal_uInt16
))
589 if (nPoly
* sizeof(sal_uInt16
) > nEndPos
- mpInputStream
->Tell())
592 // Get number of points in each polygon
593 std::vector
<sal_uInt16
> aPoints(nPoly
);
594 for (sal_uInt32 i
= 0; i
< nPoly
&& mpInputStream
->good(); ++i
)
596 sal_uInt32
nPoints(0);
597 mpInputStream
->ReadUInt32( nPoints
);
598 aPoints
[i
] = static_cast<sal_uInt16
>(nPoints
);
600 if ( mpInputStream
->good() && ( nGesPoints
* (sizeof(T
)+sizeof(T
)) ) <= ( nEndPos
- mpInputStream
->Tell() ) )
602 // Get polygon points
603 tools::PolyPolygon
aPolyPoly(nPoly
);
604 for (sal_uInt32 i
= 0; i
< nPoly
&& mpInputStream
->good(); ++i
)
606 const sal_uInt16
nPointCount(aPoints
[i
]);
607 std::vector
<Point
> aPtAry(nPointCount
);
608 for (sal_uInt16 j
= 0; j
< nPointCount
&& mpInputStream
->good(); ++j
)
611 *mpInputStream
>> nX
>> nY
;
612 aPtAry
[j
] = Point( nX
, nY
);
616 aPolyPoly
.Insert(tools::Polygon(aPtAry
.size(), aPtAry
.data()));
619 DrawPolyPolygon(aPolyPoly
, mbRecordPath
);
622 OSL_ENSURE(nReadPoints
== nGesPoints
, "The number Points processed from EMR_POLYPOLYGON is unequal imported number (!)");
625 bool EmfReader::ReadEnhWMF()
627 sal_uInt32 nStretchBltMode
= 0;
628 sal_uInt32
nNextPos(0),
629 nW(0), nH(0), nColor(0), nIndex(0),
630 nDat32(0), nNom1(0), nDen1(0), nNom2(0), nDen2(0);
631 sal_Int32
nX32(0), nY32(0), nx32(0), ny32(0);
633 bool bStatus
= ReadHeader();
634 bool bHaveDC
= false;
636 static bool bEnableEMFPlus
= ( getenv( "EMF_PLUS_DISABLE" ) == nullptr );
638 while( bStatus
&& mnRecordCount
-- && mpInputStream
->good())
640 sal_uInt32
nRecType(0), nRecSize(0);
641 mpInputStream
->ReadUInt32(nRecType
).ReadUInt32(nRecSize
);
643 if ( !mpInputStream
->good() || ( nRecSize
< 8 ) || ( nRecSize
& 3 ) ) // Parameters are always divisible by 4
649 auto nCurPos
= mpInputStream
->Tell();
651 if (mnEndPos
< nCurPos
- 8)
657 const sal_uInt32 nMaxPossibleRecSize
= mnEndPos
- (nCurPos
- 8);
658 if (nRecSize
> nMaxPossibleRecSize
)
664 nNextPos
= nCurPos
+ (nRecSize
- 8);
666 if( !maBmpSaveList
.empty()
667 && ( nRecType
!= EMR_STRETCHBLT
)
668 && ( nRecType
!= EMR_STRETCHDIBITS
)
670 ResolveBitmapActions( maBmpSaveList
);
675 SAL_INFO ("emfio", "0x" << std::hex
<< (nNextPos
- nRecSize
) << "-0x" << nNextPos
<< " " << record_type_name(nRecType
) << " size: " << nRecSize
<< std::dec
);
677 if( bEnableEMFPlus
&& nRecType
== EMR_COMMENT
) {
680 mpInputStream
->ReadUInt32( length
);
682 SAL_INFO("emfio", "\tGDI comment, length: " << length
);
684 if( mpInputStream
->good() && length
>= 4 && length
<= mpInputStream
->remainingSize() ) {
685 sal_uInt32 nCommentId
;
687 mpInputStream
->ReadUInt32( nCommentId
);
689 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
);
691 if( nCommentId
== EMR_COMMENT_EMFPLUS
&& nRecSize
>= 12 )
693 // [MS-EMF] 2.3.3: DataSize includes both CommentIdentifier and CommentRecordParm fields.
694 // We have already read 4-byte CommentIdentifier, so reduce length appropriately
695 ReadEMFPlusComment( length
-4, bHaveDC
);
697 else if( nCommentId
== EMR_COMMENT_PUBLIC
&& nRecSize
>= 12 )
699 // TODO: ReadGDIComment()
701 else if( nCommentId
== EMR_COMMENT_EMFSPOOL
&& nRecSize
>= 12 )
703 // TODO Implement reading EMFSPOOL comment
708 SAL_INFO ("emfio", "\t\tunknown id: 0x" << std::hex
<< nCommentId
<< std::dec
);
712 else if ( !bHaveDC
&& mbEMFPlusDualMode
&& nRecType
!= EMR_HEADER
&& nRecType
!= EMR_EOF
)
714 // skip content (EMF record) in dual mode
715 // we process only EMR_COMMENT (see above) to access EMF+ data
716 // with 2 exceptions, according to EMF+ specification:
717 // EMR_HEADER and EMR_EOF
718 // if a device context is given (bHaveDC) process the following EMF record, too.
720 else if( !mbEMFPlus
|| bHaveDC
|| nRecType
== EMR_EOF
)
724 case EMR_POLYBEZIERTO
:
725 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int32
>(true, nNextPos
), true, mbRecordPath
);
727 case EMR_POLYBEZIER
:
728 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int32
>(false, nNextPos
), false, mbRecordPath
);
732 DrawPolygon(ReadPolygonWithSkip
<sal_Int32
>(false, nNextPos
), mbRecordPath
);
735 case EMR_POLYLINETO
:
736 DrawPolyLine(ReadPolygonWithSkip
<sal_Int32
>(true, nNextPos
), true, mbRecordPath
);
740 DrawPolyLine(ReadPolygonWithSkip
<sal_Int32
>(false, nNextPos
), false, mbRecordPath
);
743 case EMR_POLYPOLYLINE
:
744 ReadAndDrawPolyLine
<sal_Int32
>(nNextPos
);
747 case EMR_POLYPOLYGON
:
748 ReadAndDrawPolyPolygon
<sal_Int32
>(nNextPos
);
751 case EMR_SETWINDOWEXTEX
:
753 sal_Int32 w
= 0, h
= 0;
754 mpInputStream
->ReadInt32( w
).ReadInt32( h
);
755 SetWinExt( Size( w
, h
), true);
759 case EMR_SETWINDOWORGEX
:
761 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
762 SetWinOrg( Point( nX32
, nY32
), true);
766 case EMR_SCALEWINDOWEXTEX
:
768 mpInputStream
->ReadUInt32( nNom1
).ReadUInt32( nDen1
).ReadUInt32( nNom2
).ReadUInt32( nDen2
);
769 if (nDen1
!= 0 && nDen2
!= 0)
770 ScaleWinExt( static_cast<double>(nNom1
) / nDen1
, static_cast<double>(nNom2
) / nDen2
);
772 SAL_WARN("vcl.emf", "ignoring bogus divide by zero");
776 case EMR_SETVIEWPORTORGEX
:
778 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
779 SetDevOrg( Point( nX32
, nY32
) );
783 case EMR_SCALEVIEWPORTEXTEX
:
785 mpInputStream
->ReadUInt32( nNom1
).ReadUInt32( nDen1
).ReadUInt32( nNom2
).ReadUInt32( nDen2
);
786 if (nDen1
!= 0 && nDen2
!= 0)
787 ScaleDevExt( static_cast<double>(nNom1
) / nDen1
, static_cast<double>(nNom2
) / nDen2
);
789 SAL_WARN("vcl.emf", "ignoring bogus divide by zero");
793 case EMR_SETVIEWPORTEXTEX
:
795 sal_Int32 w
= 0, h
= 0;
796 mpInputStream
->ReadInt32( w
).ReadInt32( h
);
797 SetDevExt( Size( w
, h
) );
807 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
808 DrawPixel( Point( nX32
, nY32
), ReadColor() );
812 case EMR_SETMAPMODE
:
815 mpInputStream
->ReadUInt32( nMapMode
);
816 SetMapMode( nMapMode
);
822 mpInputStream
->ReadUInt32( nDat32
);
823 SetBkMode( static_cast<BkMode
>(nDat32
) );
827 case EMR_SETPOLYFILLMODE
:
832 mpInputStream
->ReadUInt32( nDat32
);
833 SetRasterOp( static_cast<WMFRasterOp
>(nDat32
) );
837 case EMR_SETSTRETCHBLTMODE
:
839 mpInputStream
->ReadUInt32( nStretchBltMode
);
843 case EMR_SETTEXTALIGN
:
845 mpInputStream
->ReadUInt32( nDat32
);
846 SetTextAlign( nDat32
);
850 case EMR_SETTEXTCOLOR
:
852 SetTextColor( ReadColor() );
856 case EMR_SETBKCOLOR
:
858 SetBkColor( ReadColor() );
862 case EMR_OFFSETCLIPRGN
:
864 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
865 MoveClipRegion( Size( nX32
, nY32
) );
871 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
872 MoveTo( Point( nX32
, nY32
), mbRecordPath
);
876 case EMR_INTERSECTCLIPRECT
:
878 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
);
879 IntersectClipRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
) );
895 case EMR_SETWORLDTRANSFORM
:
898 *mpInputStream
>> aTempXForm
;
899 SetWorldTransform( aTempXForm
);
903 case EMR_MODIFYWORLDTRANSFORM
:
907 *mpInputStream
>> aTempXForm
;
908 mpInputStream
->ReadUInt32( nMode
);
909 ModifyWorldTransform( aTempXForm
, nMode
);
913 case EMR_SELECTOBJECT
:
915 mpInputStream
->ReadUInt32( nIndex
);
916 SelectObject( nIndex
);
922 mpInputStream
->ReadUInt32( nIndex
);
923 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
929 // #fdo39428 Remove SvStream operator>>(long&)
930 sal_Int32
nTmpW(0), nTmpH(0);
932 mpInputStream
->ReadUInt32( nStyle
).ReadInt32( nTmpW
).ReadInt32( nTmpH
);
933 aSize
.setWidth( nTmpW
);
934 aSize
.setHeight( nTmpH
);
937 aLineInfo
.SetWidth( aSize
.Width() );
939 bool bTransparent
= false;
940 switch( nStyle
& PS_STYLE_MASK
)
943 aLineInfo
.SetStyle( LineStyle::Dash
);
944 aLineInfo
.SetDashCount( 1 );
945 aLineInfo
.SetDotCount( 2 );
948 aLineInfo
.SetStyle( LineStyle::Dash
);
949 aLineInfo
.SetDashCount( 1 );
950 aLineInfo
.SetDotCount( 1 );
953 aLineInfo
.SetStyle( LineStyle::Dash
);
954 aLineInfo
.SetDashCount( 0 );
955 aLineInfo
.SetDotCount( 1 );
958 aLineInfo
.SetStyle( LineStyle::Dash
);
959 aLineInfo
.SetDashCount( 1 );
960 aLineInfo
.SetDotCount( 0 );
964 aLineInfo
.SetStyle( LineStyle::NONE
);
966 case PS_INSIDEFRAME
:
969 aLineInfo
.SetStyle( LineStyle::Solid
);
971 switch( nStyle
& PS_ENDCAP_STYLE_MASK
)
973 case PS_ENDCAP_ROUND
:
976 aLineInfo
.SetLineCap( css::drawing::LineCap_ROUND
);
980 case PS_ENDCAP_SQUARE
:
983 aLineInfo
.SetLineCap( css::drawing::LineCap_SQUARE
);
987 case PS_ENDCAP_FLAT
:
989 aLineInfo
.SetLineCap( css::drawing::LineCap_BUTT
);
991 switch( nStyle
& PS_JOIN_STYLE_MASK
)
994 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Round
);
997 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Miter
);
1000 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Bevel
);
1003 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::NONE
);
1005 CreateObjectIndexed(nIndex
, std::make_unique
<WinMtfLineStyle
>( ReadColor(), aLineInfo
, bTransparent
));
1010 case EMR_EXTCREATEPEN
:
1013 sal_uInt32 offBmi
, cbBmi
, offBits
, cbBits
, nStyle
, nWidth
, nBrushStyle
, elpNumEntries
;
1016 mpInputStream
->ReadUInt32( nIndex
);
1017 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1019 mpInputStream
->ReadUInt32( offBmi
).ReadUInt32( cbBmi
).ReadUInt32( offBits
).ReadUInt32( cbBits
). ReadUInt32( nStyle
).ReadUInt32( nWidth
).ReadUInt32( nBrushStyle
);
1020 aColorRef
= ReadColor();
1021 mpInputStream
->ReadInt32( elpHatch
).ReadUInt32( elpNumEntries
);
1025 aLineInfo
.SetWidth( nWidth
);
1027 bool bTransparent
= false;
1029 switch( nStyle
& PS_STYLE_MASK
)
1031 case PS_DASHDOTDOT
:
1032 aLineInfo
.SetStyle( LineStyle::Dash
);
1033 aLineInfo
.SetDashCount( 1 );
1034 aLineInfo
.SetDotCount( 2 );
1037 aLineInfo
.SetStyle( LineStyle::Dash
);
1038 aLineInfo
.SetDashCount( 1 );
1039 aLineInfo
.SetDotCount( 1 );
1042 aLineInfo
.SetStyle( LineStyle::Dash
);
1043 aLineInfo
.SetDashCount( 0 );
1044 aLineInfo
.SetDotCount( 1 );
1047 aLineInfo
.SetStyle( LineStyle::Dash
);
1048 aLineInfo
.SetDashCount( 1 );
1049 aLineInfo
.SetDotCount( 0 );
1052 bTransparent
= true;
1053 aLineInfo
.SetStyle( LineStyle::NONE
);
1056 case PS_INSIDEFRAME
:
1059 aLineInfo
.SetStyle( LineStyle::Solid
);
1061 switch( nStyle
& PS_ENDCAP_STYLE_MASK
)
1063 case PS_ENDCAP_ROUND
:
1064 if ( aLineInfo
.GetWidth() )
1066 aLineInfo
.SetLineCap( css::drawing::LineCap_ROUND
);
1070 case PS_ENDCAP_SQUARE
:
1071 if ( aLineInfo
.GetWidth() )
1073 aLineInfo
.SetLineCap( css::drawing::LineCap_SQUARE
);
1077 case PS_ENDCAP_FLAT
:
1079 aLineInfo
.SetLineCap( css::drawing::LineCap_BUTT
);
1081 switch( nStyle
& PS_JOIN_STYLE_MASK
)
1083 case PS_JOIN_ROUND
:
1084 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Round
);
1086 case PS_JOIN_MITER
:
1087 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Miter
);
1089 case PS_JOIN_BEVEL
:
1090 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Bevel
);
1093 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::NONE
);
1095 CreateObjectIndexed(nIndex
, std::make_unique
<WinMtfLineStyle
>( aColorRef
, aLineInfo
, bTransparent
));
1100 case EMR_CREATEBRUSHINDIRECT
:
1103 mpInputStream
->ReadUInt32( nIndex
);
1104 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1106 mpInputStream
->ReadUInt32( nStyle
);
1107 CreateObjectIndexed(nIndex
, std::make_unique
<WinMtfFillStyle
>( ReadColor(), ( nStyle
== BS_HOLLOW
) ));
1112 case EMR_DELETEOBJECT
:
1114 mpInputStream
->ReadUInt32( nIndex
);
1115 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1116 DeleteObject( nIndex
);
1122 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
);
1123 DrawEllipse( ReadRectangle( nX32
, nY32
, nx32
, ny32
) );
1127 case EMR_RECTANGLE
:
1129 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
);
1130 DrawRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
) );
1134 case EMR_ROUNDRECT
:
1136 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nW
).ReadUInt32( nH
);
1137 Size
aSize( Size( nW
, nH
) );
1138 DrawRoundRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
), aSize
);
1144 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1145 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1146 DrawArc( ReadRectangle( nX32
, nY32
, nx32
, ny32
), Point( nStartX
, nStartY
), Point( nEndX
, nEndY
) );
1152 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1153 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1154 DrawChord( ReadRectangle( nX32
, nY32
, nx32
, ny32
), Point( nStartX
, nStartY
), Point( nEndX
, nEndY
) );
1160 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1161 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1162 const tools::Rectangle
aRect( ReadRectangle( nX32
, nY32
, nx32
, ny32
));
1164 // #i73608# OutputDevice deviates from WMF
1165 // semantics. start==end means full ellipse here.
1166 if( nStartX
== nEndX
&& nStartY
== nEndY
)
1167 DrawEllipse( aRect
);
1169 DrawPie( aRect
, Point( nStartX
, nStartY
), Point( nEndX
, nEndY
) );
1175 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
);
1176 LineTo( Point( nX32
, nY32
), mbRecordPath
);
1182 sal_uInt32 nStartX
, nStartY
, nEndX
, nEndY
;
1183 mpInputStream
->ReadInt32( nX32
).ReadInt32( nY32
).ReadInt32( nx32
).ReadInt32( ny32
).ReadUInt32( nStartX
).ReadUInt32( nStartY
).ReadUInt32( nEndX
).ReadUInt32( nEndY
);
1184 DrawArc( ReadRectangle( nX32
, nY32
, nx32
, ny32
), Point( nStartX
, nStartY
), Point( nEndX
, nEndY
), true );
1188 case EMR_BEGINPATH
:
1191 mbRecordPath
= true;
1195 case EMR_ABORTPATH
:
1199 mbRecordPath
= false;
1202 case EMR_CLOSEFIGURE
:
1207 StrokeAndFillPath( false, true );
1210 case EMR_STROKEANDFILLPATH
:
1211 StrokeAndFillPath( true, true );
1214 case EMR_STROKEPATH
:
1215 StrokeAndFillPath( true, false );
1218 case EMR_SELECTCLIPPATH
:
1220 sal_Int32
nClippingMode(0);
1221 mpInputStream
->ReadInt32(nClippingMode
);
1222 SetClipPath(GetPathObj(), nClippingMode
, true);
1226 case EMR_EXTSELECTCLIPRGN
:
1228 sal_Int32
nClippingMode(0), cbRgnData(0);
1229 mpInputStream
->ReadInt32(cbRgnData
);
1230 mpInputStream
->ReadInt32(nClippingMode
);
1232 // This record's region data should be ignored if mode
1233 // is RGN_COPY - see EMF spec section 2.3.2.2
1234 if (nClippingMode
== RGN_COPY
)
1236 SetDefaultClipPath();
1240 tools::PolyPolygon aPolyPoly
;
1242 ImplReadRegion(aPolyPoly
, *mpInputStream
, nRecSize
);
1243 SetClipPath(aPolyPoly
, nClippingMode
, false);
1249 case EMR_ALPHABLEND
:
1251 sal_Int32
xDest(0), yDest(0), cxDest(0), cyDest(0);
1253 BLENDFUNCTION aFunc
;
1254 sal_Int32
xSrc(0), ySrc(0), cxSrc(0), cySrc(0);
1256 sal_uInt32
BkColorSrc(0), iUsageSrc(0), offBmiSrc(0);
1257 sal_uInt32
cbBmiSrc(0), offBitsSrc(0), cbBitsSrc(0);
1259 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1260 mpInputStream
->SeekRel( 0x10 );
1262 mpInputStream
->ReadInt32( xDest
).ReadInt32( yDest
).ReadInt32( cxDest
).ReadInt32( cyDest
);
1263 *mpInputStream
>> aFunc
;
1264 mpInputStream
->ReadInt32( xSrc
).ReadInt32( ySrc
);
1265 *mpInputStream
>> xformSrc
;
1266 mpInputStream
->ReadUInt32( BkColorSrc
).ReadUInt32( iUsageSrc
).ReadUInt32( offBmiSrc
).ReadUInt32( cbBmiSrc
)
1267 .ReadUInt32( offBitsSrc
).ReadUInt32( cbBitsSrc
).ReadInt32( cxSrc
).ReadInt32( cySrc
) ;
1269 if ( (cbBitsSrc
> (SAL_MAX_UINT32
- 14)) || ((SAL_MAX_UINT32
- 14) - cbBitsSrc
< cbBmiSrc
) ||
1270 cxDest
== SAL_MAX_INT32
|| cyDest
== SAL_MAX_INT32
)
1276 tools::Rectangle
aRect(Point(xDest
, yDest
), Size(cxDest
+ 1, cyDest
+ 1));
1278 const sal_uInt32 nSourceSize
= cbBmiSrc
+ cbBitsSrc
+ 14;
1279 bool bSafeRead
= nSourceSize
<= (mnEndPos
- mnStartPos
);
1280 sal_uInt32
nDeltaToDIB5HeaderSize(0);
1281 const bool bReadAlpha(0x01 == aFunc
.aAlphaFormat
);
1282 if (bSafeRead
&& bReadAlpha
)
1284 // we need to read alpha channel data if AlphaFormat of BLENDFUNCTION is
1285 // AC_SRC_ALPHA (==0x01). To read it, create a temp DIB-File which is ready
1287 const sal_uInt32 nHeaderSize
= getDIBV5HeaderSize();
1288 if (cbBmiSrc
> nHeaderSize
)
1291 nDeltaToDIB5HeaderSize
= nHeaderSize
- cbBmiSrc
;
1295 const sal_uInt32
nTargetSize(cbBmiSrc
+ nDeltaToDIB5HeaderSize
+ cbBitsSrc
+ 14);
1296 char* pBuf
= new char[ nTargetSize
];
1297 SvMemoryStream
aTmp( pBuf
, nTargetSize
, StreamMode::READ
| StreamMode::WRITE
);
1299 aTmp
.ObjectOwnsMemory( true );
1301 // write BM-Header (14 bytes)
1302 aTmp
.WriteUChar( 'B' )
1304 .WriteUInt32( cbBitsSrc
)
1307 .WriteUInt32( cbBmiSrc
+ nDeltaToDIB5HeaderSize
+ 14 );
1309 // copy DIBInfoHeader from source (cbBmiSrc bytes)
1310 mpInputStream
->Seek( nStart
+ offBmiSrc
);
1311 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmiSrc
);
1315 // need to add values for all stuff that DIBV5Header is bigger
1316 // than DIBInfoHeader, all values are correctly initialized to zero,
1317 // so we can use memset here
1318 memset(pBuf
+ cbBmiSrc
+ 14, 0, nDeltaToDIB5HeaderSize
);
1321 // copy bitmap data from source (offBitsSrc bytes)
1322 mpInputStream
->Seek( nStart
+ offBitsSrc
);
1323 mpInputStream
->ReadBytes(pBuf
+ 14 + nDeltaToDIB5HeaderSize
+ cbBmiSrc
, cbBitsSrc
);
1326 // prepare to read and fill BitmapEx
1334 if(ReadDIBV5(aBitmap
, aAlpha
, aTmp
))
1336 aBitmapEx
= BitmapEx(aBitmap
, aAlpha
);
1343 if(ReadDIB(aBitmap
, aTmp
, true))
1345 if(0xff != aFunc
.aSrcConstantAlpha
)
1347 // add const alpha channel
1348 aBitmapEx
= BitmapEx(
1350 AlphaMask(aBitmap
.GetSizePixel(), &aFunc
.aSrcConstantAlpha
));
1355 aBitmapEx
= BitmapEx(aBitmap
);
1360 if(!aBitmapEx
.IsEmpty())
1362 // test if it is sensible to crop
1363 if ( ( cxSrc
> 0 ) && ( cySrc
> 0 ) &&
1364 ( xSrc
>= 0 ) && ( ySrc
>= 0 ) &&
1365 ( xSrc
+ cxSrc
< aBitmapEx
.GetSizePixel().Width() ) &&
1366 ( ySrc
+ cySrc
< aBitmapEx
.GetSizePixel().Height() ) )
1368 const tools::Rectangle
aCropRect( Point( xSrc
, ySrc
), Size( cxSrc
, cySrc
) );
1370 aBitmapEx
.Crop( aCropRect
);
1374 static bool bDoSaveForVisualControl(false); // loplugin:constvars:ignore
1376 if(bDoSaveForVisualControl
)
1378 SvFileStream
aNew("c:\\metafile_content.png", StreamMode::WRITE
|StreamMode::TRUNC
);
1379 vcl::PNGWriter
aPNGWriter(aBitmapEx
);
1380 aPNGWriter
.Write(aNew
);
1383 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmapEx
, aRect
, SRCAND
|SRCINVERT
));
1390 case EMR_BITBLT
: // PASSTHROUGH INTENDED
1391 case EMR_STRETCHBLT
:
1393 sal_Int32 xDest
, yDest
, cxDest
, cyDest
, xSrc
, ySrc
, cxSrc
, cySrc
;
1394 sal_uInt32 dwRop
, iUsageSrc
, offBmiSrc
, cbBmiSrc
, offBitsSrc
, cbBitsSrc
;
1397 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1399 mpInputStream
->SeekRel( 0x10 );
1400 mpInputStream
->ReadInt32( xDest
).ReadInt32( yDest
).ReadInt32( cxDest
).ReadInt32( cyDest
).ReadUInt32( dwRop
).ReadInt32( xSrc
).ReadInt32( ySrc
)
1402 mpInputStream
->ReadUInt32( nColor
).ReadUInt32( iUsageSrc
).ReadUInt32( offBmiSrc
).ReadUInt32( cbBmiSrc
)
1403 .ReadUInt32( offBitsSrc
).ReadUInt32( cbBitsSrc
);
1405 if ( nRecType
== EMR_STRETCHBLT
)
1406 mpInputStream
->ReadInt32( cxSrc
).ReadInt32( cySrc
);
1411 tools::Rectangle
aRect( Point( xDest
, yDest
), Size( cxDest
, cyDest
) );
1413 if (!mpInputStream
->good() || (cbBitsSrc
> (SAL_MAX_UINT32
- 14)) || ((SAL_MAX_UINT32
- 14) - cbBitsSrc
< cbBmiSrc
))
1417 sal_uInt32 nSize
= cbBmiSrc
+ cbBitsSrc
+ 14;
1418 if ( nSize
<= ( mnEndPos
- mnStartPos
) )
1420 char* pBuf
= new char[ nSize
];
1421 SvMemoryStream
aTmp( pBuf
, nSize
, StreamMode::READ
| StreamMode::WRITE
);
1422 aTmp
.ObjectOwnsMemory( true );
1423 aTmp
.WriteUChar( 'B' )
1425 .WriteUInt32( cbBitsSrc
)
1428 .WriteUInt32( cbBmiSrc
+ 14 );
1429 mpInputStream
->Seek( nStart
+ offBmiSrc
);
1430 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmiSrc
);
1431 mpInputStream
->Seek( nStart
+ offBitsSrc
);
1432 mpInputStream
->ReadBytes(pBuf
+ 14 + cbBmiSrc
, cbBitsSrc
);
1434 ReadDIB(aBitmap
, aTmp
, true);
1436 // test if it is sensible to crop
1437 if ( (cxSrc
> 0) && (cySrc
> 0) &&
1438 (xSrc
>= 0) && (ySrc
>= 0) &&
1439 (aBitmap
.GetSizePixel().Width() >= cxSrc
) &&
1440 (xSrc
<= aBitmap
.GetSizePixel().Width() - cxSrc
) &&
1441 (aBitmap
.GetSizePixel().Height() >= cySrc
) &&
1442 (ySrc
<= aBitmap
.GetSizePixel().Height() - cySrc
) )
1444 tools::Rectangle
aCropRect( Point( xSrc
, ySrc
), Size( cxSrc
, cySrc
) );
1445 aBitmap
.Crop( aCropRect
);
1448 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmap
, aRect
, dwRop
));
1454 case EMR_STRETCHDIBITS
:
1456 sal_Int32 xDest
, yDest
, xSrc
, ySrc
, cxSrc
, cySrc
, cxDest
, cyDest
;
1457 sal_uInt32 offBmiSrc
, cbBmiSrc
, offBitsSrc
, cbBitsSrc
, iUsageSrc
, dwRop
;
1458 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1460 mpInputStream
->SeekRel( 0x10 );
1461 mpInputStream
->ReadInt32( xDest
)
1467 .ReadUInt32( offBmiSrc
)
1468 .ReadUInt32( cbBmiSrc
)
1469 .ReadUInt32( offBitsSrc
)
1470 .ReadUInt32( cbBitsSrc
)
1471 .ReadUInt32( iUsageSrc
)
1472 .ReadUInt32( dwRop
)
1473 .ReadInt32( cxDest
)
1474 .ReadInt32( cyDest
);
1476 if (!mpInputStream
->good() ||
1477 ((SAL_MAX_UINT32
- 14) < cbBitsSrc
) ||
1478 ((SAL_MAX_UINT32
- 14) - cbBitsSrc
< cbBmiSrc
))
1485 tools::Rectangle
aRect(xDest
, yDest
);
1486 aRect
.SaturatingSetSize(Size(cxDest
, cyDest
));
1488 sal_uInt32 nSize
= cbBmiSrc
+ cbBitsSrc
+ 14;
1489 if ( nSize
<= ( mnEndPos
- mnStartPos
) )
1491 char* pBuf
= new char[ nSize
];
1492 SvMemoryStream
aTmp( pBuf
, nSize
, StreamMode::READ
| StreamMode::WRITE
);
1493 aTmp
.ObjectOwnsMemory( true );
1494 aTmp
.WriteUChar( 'B' )
1496 .WriteUInt32( cbBitsSrc
)
1499 .WriteUInt32( cbBmiSrc
+ 14 );
1500 mpInputStream
->Seek( nStart
+ offBmiSrc
);
1501 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmiSrc
);
1502 mpInputStream
->Seek( nStart
+ offBitsSrc
);
1503 mpInputStream
->ReadBytes(pBuf
+ 14 + cbBmiSrc
, cbBitsSrc
);
1505 ReadDIB(aBitmap
, aTmp
, true);
1507 // test if it is sensible to crop
1508 if ( (cxSrc
> 0) && (cySrc
> 0) &&
1509 (xSrc
>= 0) && (ySrc
>= 0) &&
1510 (aBitmap
.GetSizePixel().Width() >= cxSrc
) &&
1511 (xSrc
<= aBitmap
.GetSizePixel().Width() - cxSrc
) &&
1512 (aBitmap
.GetSizePixel().Height() >= cySrc
) &&
1513 (ySrc
<= aBitmap
.GetSizePixel().Height() - cySrc
) )
1515 tools::Rectangle
aCropRect( Point( xSrc
, ySrc
), Size( cxSrc
, cySrc
) );
1516 aBitmap
.Crop( aCropRect
);
1518 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmap
, aRect
, dwRop
));
1524 case EMR_EXTCREATEFONTINDIRECTW
:
1526 mpInputStream
->ReadUInt32( nIndex
);
1527 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1530 mpInputStream
->ReadInt32( aLogFont
.lfHeight
)
1531 .ReadInt32( aLogFont
.lfWidth
)
1532 .ReadInt32( aLogFont
.lfEscapement
)
1533 .ReadInt32( aLogFont
.lfOrientation
)
1534 .ReadInt32( aLogFont
.lfWeight
)
1535 .ReadUChar( aLogFont
.lfItalic
)
1536 .ReadUChar( aLogFont
.lfUnderline
)
1537 .ReadUChar( aLogFont
.lfStrikeOut
)
1538 .ReadUChar( aLogFont
.lfCharSet
)
1539 .ReadUChar( aLogFont
.lfOutPrecision
)
1540 .ReadUChar( aLogFont
.lfClipPrecision
)
1541 .ReadUChar( aLogFont
.lfQuality
)
1542 .ReadUChar( aLogFont
.lfPitchAndFamily
);
1544 sal_Unicode lfFaceName
[LF_FACESIZE
+1];
1545 lfFaceName
[LF_FACESIZE
] = 0;
1546 for (int i
= 0; i
< LF_FACESIZE
; ++i
)
1548 sal_uInt16
nChar(0);
1549 mpInputStream
->ReadUInt16(nChar
);
1550 lfFaceName
[i
] = nChar
;
1552 aLogFont
.alfFaceName
= OUString( lfFaceName
);
1554 // #i123216# Not used in the test case of #121382# (always identity in XForm), also
1555 // no hints in ms docu if FontSize should be scaled with WT. Using with the example
1556 // from #i123216# creates errors, so removing.
1558 // // #i121382# Need to apply WorldTransform to FontHeight/Width; this should be completely
1559 // // changed to basegfx::B2DHomMatrix instead of 'struct XForm', but not now due to time
1560 // // constraints and dangers
1561 // const XForm& rXF = GetWorldTransform();
1562 // const basegfx::B2DHomMatrix aWT(rXF.eM11, rXF.eM21, rXF.eDx, rXF.eM12, rXF.eM22, rXF.eDy);
1563 // const basegfx::B2DVector aTransVec(aWT * basegfx::B2DVector(aLogFont.lfWidth, aLogFont.lfHeight));
1564 // aLogFont.lfWidth = aTransVec.getX();
1565 // aLogFont.lfHeight = aTransVec.getY();
1566 if (mpInputStream
->good() && aLogFont
.lfHeight
!= SAL_MIN_INT32
&& aLogFont
.lfWidth
!= SAL_MIN_INT32
)
1568 CreateObjectIndexed(nIndex
, std::make_unique
<WinMtfFontStyle
>( aLogFont
));
1574 case EMR_EXTTEXTOUTA
:
1577 case EMR_EXTTEXTOUTW
:
1579 sal_Int32 nLeft
, nTop
, nRight
, nBottom
, ptlReferenceX
, ptlReferenceY
, nGfxMode
, nXScale
, nYScale
;
1580 sal_uInt32 nOffString
, nOptions
, offDx
;
1583 nCurPos
= mpInputStream
->Tell() - 8;
1585 mpInputStream
->ReadInt32( nLeft
).ReadInt32( nTop
).ReadInt32( nRight
).ReadInt32( nBottom
).ReadInt32( nGfxMode
).ReadInt32( nXScale
).ReadInt32( nYScale
)
1586 .ReadInt32( ptlReferenceX
).ReadInt32( ptlReferenceY
).ReadInt32( nLen
).ReadUInt32( nOffString
).ReadUInt32( nOptions
);
1588 mpInputStream
->SeekRel( 0x10 );
1589 mpInputStream
->ReadUInt32( offDx
);
1591 ComplexTextLayoutFlags nTextLayoutMode
= ComplexTextLayoutFlags::Default
;
1592 if ( nOptions
& ETO_RTLREADING
)
1593 nTextLayoutMode
= ComplexTextLayoutFlags::BiDiRtl
| ComplexTextLayoutFlags::TextOriginLeft
;
1594 SetTextLayoutMode( nTextLayoutMode
);
1595 SAL_WARN_IF( ( nOptions
& ( ETO_PDY
| ETO_GLYPH_INDEX
) ) != 0, "emfio", "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" );
1597 Point
aPos( ptlReferenceX
, ptlReferenceY
);
1598 bool bLenSane
= nLen
> 0 && nLen
< static_cast<sal_Int32
>( SAL_MAX_UINT32
/ sizeof(sal_Int32
) );
1599 bool bOffStringSane
= nOffString
<= mnEndPos
- nCurPos
;
1600 if (bLenSane
&& bOffStringSane
)
1602 mpInputStream
->Seek( nCurPos
+ nOffString
);
1606 if ( nLen
<= static_cast<sal_Int32
>( mnEndPos
- mpInputStream
->Tell() ) )
1608 std::unique_ptr
<sal_Char
[]> pBuf(new sal_Char
[ nLen
]);
1609 mpInputStream
->ReadBytes(pBuf
.get(), nLen
);
1610 aText
= OUString(pBuf
.get(), nLen
, GetCharSet());
1615 if ( ( nLen
* sizeof(sal_Unicode
) ) <= ( mnEndPos
- mpInputStream
->Tell() ) )
1617 aText
= read_uInt16s_ToOUString(*mpInputStream
, nLen
);
1621 std::unique_ptr
<long[]> pDXAry
, pDYAry
;
1624 bool bOverflow
= o3tl::checked_multiply
<sal_Int32
>(nLen
, (nOptions
& ETO_PDY
) ? 8 : 4, nDxSize
);
1625 if (!bOverflow
&& offDx
&& ((nCurPos
+ offDx
+ nDxSize
) <= nNextPos
) && nNextPos
<= mnEndPos
)
1627 mpInputStream
->Seek( nCurPos
+ offDx
);
1628 pDXAry
.reset( new long[aText
.getLength()] );
1629 if (nOptions
& ETO_PDY
)
1631 pDYAry
.reset( new long[aText
.getLength()] );
1634 for (sal_Int32 i
= 0; i
< aText
.getLength(); ++i
)
1636 sal_Int32 nDxCount
= 1;
1637 if (aText
.getLength() != nLen
)
1639 sal_Unicode cUniChar
= aText
[i
];
1640 OString
aTmp(&cUniChar
, 1, GetCharSet());
1641 if (aTmp
.getLength() > 1)
1643 nDxCount
= aTmp
.getLength();
1647 sal_Int32 nDx
= 0, nDy
= 0;
1650 sal_Int32 nDxTmp
= 0;
1651 mpInputStream
->ReadInt32(nDxTmp
);
1653 if (nOptions
& ETO_PDY
)
1655 sal_Int32 nDyTmp
= 0;
1656 mpInputStream
->ReadInt32(nDyTmp
);
1662 if (nOptions
& ETO_PDY
)
1668 DrawText(aPos
, aText
, pDXAry
.get(), pDYAry
.get(), mbRecordPath
, nGfxMode
);
1673 case EMR_POLYBEZIERTO16
:
1674 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int16
>(true, nNextPos
), true, mbRecordPath
);
1677 case EMR_POLYBEZIER16
:
1678 DrawPolyBezier(ReadPolygonWithSkip
<sal_Int16
>(false, nNextPos
), false, mbRecordPath
);
1681 case EMR_POLYGON16
:
1682 DrawPolygon(ReadPolygonWithSkip
<sal_Int16
>(false, nNextPos
), mbRecordPath
);
1685 case EMR_POLYLINETO16
:
1686 DrawPolyLine(ReadPolygonWithSkip
<sal_Int16
>(true, nNextPos
), true, mbRecordPath
);
1689 case EMR_POLYLINE16
:
1690 DrawPolyLine(ReadPolygonWithSkip
<sal_Int16
>(false, nNextPos
), false, mbRecordPath
);
1693 case EMR_POLYPOLYLINE16
:
1694 ReadAndDrawPolyLine
<sal_Int16
>(nNextPos
);
1697 case EMR_POLYPOLYGON16
:
1698 ReadAndDrawPolyPolygon
<sal_Int16
>(nNextPos
);
1704 tools::PolyPolygon aPolyPoly
;
1705 mpInputStream
->SeekRel( 0x10 );
1706 mpInputStream
->ReadUInt32( nLen
).ReadUInt32( nIndex
);
1708 if ( ImplReadRegion( aPolyPoly
, *mpInputStream
, nRecSize
) )
1711 SelectObject( nIndex
);
1712 DrawPolyPolygon( aPolyPoly
);
1718 case EMR_CREATEDIBPATTERNBRUSHPT
:
1720 sal_uInt32 nStart
= mpInputStream
->Tell() - 8;
1723 mpInputStream
->ReadUInt32( nIndex
);
1725 if ( ( nIndex
& ENHMETA_STOCK_OBJECT
) == 0 )
1727 sal_uInt32 usage
, offBmi
, cbBmi
, offBits
, cbBits
;
1729 mpInputStream
->ReadUInt32( usage
);
1730 mpInputStream
->ReadUInt32( offBmi
);
1731 mpInputStream
->ReadUInt32( cbBmi
);
1732 mpInputStream
->ReadUInt32( offBits
);
1733 mpInputStream
->ReadUInt32( cbBits
);
1735 if ( (cbBits
> (SAL_MAX_UINT32
- 14)) || ((SAL_MAX_UINT32
- 14) - cbBits
< cbBmi
) )
1739 sal_uInt32 nSize
= cbBmi
+ cbBits
+ 14;
1740 if ( nSize
<= ( mnEndPos
- mnStartPos
) )
1742 char* pBuf
= new char[ nSize
];
1744 SvMemoryStream
aTmp( pBuf
, nSize
, StreamMode::READ
| StreamMode::WRITE
);
1745 aTmp
.ObjectOwnsMemory( true );
1746 aTmp
.WriteUChar( 'B' )
1748 .WriteUInt32( cbBits
)
1751 .WriteUInt32( cbBmi
+ 14 );
1752 mpInputStream
->Seek( nStart
+ offBmi
);
1753 mpInputStream
->ReadBytes(pBuf
+ 14, cbBmi
);
1754 mpInputStream
->Seek( nStart
+ offBits
);
1755 mpInputStream
->ReadBytes(pBuf
+ 14 + cbBmi
, cbBits
);
1757 ReadDIB(aBitmap
, aTmp
, true);
1762 CreateObjectIndexed(nIndex
, std::make_unique
<WinMtfFillStyle
>( aBitmap
));
1766 case EMR_MASKBLT
: SAL_INFO("emfio", "not implemented 'MaskBlt'"); break;
1767 case EMR_PLGBLT
: SAL_INFO("emfio", "not implemented 'PlgBlt'"); break;
1768 case EMR_SETDIBITSTODEVICE
: SAL_INFO("emfio", "not implemented 'SetDIBitsToDevice'"); break;
1769 case EMR_FRAMERGN
: SAL_INFO("emfio", "not implemented 'FrameRgn'"); break;
1770 case EMR_INVERTRGN
: SAL_INFO("emfio", "not implemented 'InvertRgn'"); break;
1771 case EMR_PAINTRGN
: SAL_INFO("emfio", "not implemented 'PaintRgn'"); break;
1772 case EMR_FLATTENPATH
: SAL_INFO("emfio", "not implemented 'FlattenPath'"); break;
1773 case EMR_WIDENPATH
: SAL_INFO("emfio", "not implemented 'WidenPath'"); break;
1774 case EMR_POLYDRAW
: SAL_INFO("emfio", "not implemented 'Polydraw'"); break;
1775 case EMR_SETARCDIRECTION
: SAL_INFO("emfio", "not implemented 'SetArcDirection'"); break;
1776 case EMR_SETPALETTEENTRIES
: SAL_INFO("emfio", "not implemented 'SetPaletteEntries'"); break;
1777 case EMR_RESIZEPALETTE
: SAL_INFO("emfio", "not implemented 'ResizePalette'"); break;
1778 case EMR_EXTFLOODFILL
: SAL_INFO("emfio", "not implemented 'ExtFloodFill'"); break;
1779 case EMR_ANGLEARC
: SAL_INFO("emfio", "not implemented 'AngleArc'"); break;
1780 case EMR_SETCOLORADJUSTMENT
: SAL_INFO("emfio", "not implemented 'SetColorAdjustment'"); break;
1781 case EMR_POLYDRAW16
: SAL_INFO("emfio", "not implemented 'PolyDraw16'"); break;
1782 case EMR_POLYTEXTOUTA
: SAL_INFO("emfio", "not implemented 'PolyTextOutA'"); break;
1783 case EMR_POLYTEXTOUTW
: SAL_INFO("emfio", "not implemented 'PolyTextOutW'"); break;
1784 case EMR_CREATECOLORSPACE
: SAL_INFO("emfio", "not implemented 'CreateColorSpace'"); break;
1785 case EMR_SETCOLORSPACE
: SAL_INFO("emfio", "not implemented 'SetColorSpace'"); break;
1786 case EMR_DELETECOLORSPACE
: SAL_INFO("emfio", "not implemented 'DeleteColorSpace'"); break;
1787 case EMR_GLSRECORD
: SAL_INFO("emfio", "not implemented 'GlsRecord'"); break;
1788 case EMR_GLSBOUNDEDRECORD
: SAL_INFO("emfio", "not implemented 'GlsBoundRecord'"); break;
1789 case EMR_PIXELFORMAT
: SAL_INFO("emfio", "not implemented 'PixelFormat'"); break;
1790 case EMR_DRAWESCAPE
: SAL_INFO("emfio", "not implemented 'DrawEscape'"); break;
1791 case EMR_EXTESCAPE
: SAL_INFO("emfio", "not implemented 'ExtEscape'"); break;
1792 case EMR_STARTDOC
: SAL_INFO("emfio", "not implemented 'StartDoc'"); break;
1793 case EMR_SMALLTEXTOUT
: SAL_INFO("emfio", "not implemented 'SmallTextOut'"); break;
1794 case EMR_FORCEUFIMAPPING
: SAL_INFO("emfio", "not implemented 'ForceUFIMapping'"); break;
1795 case EMR_NAMEDESCAPE
: SAL_INFO("emfio", "not implemented 'NamedEscape'"); break;
1796 case EMR_COLORCORRECTPALETTE
: SAL_INFO("emfio", "not implemented 'ColorCorrectPalette'"); break;
1797 case EMR_SETICMPROFILEA
: SAL_INFO("emfio", "not implemented 'SetICMProfileA'"); break;
1798 case EMR_SETICMPROFILEW
: SAL_INFO("emfio", "not implemented 'SetICMProfileW'"); break;
1799 case EMR_TRANSPARENTBLT
: SAL_INFO("emfio", "not implemented 'TransparenBlt'"); break;
1800 case EMR_TRANSPARENTDIB
: SAL_INFO("emfio", "not implemented 'TransparenDib'"); break;
1801 case EMR_GRADIENTFILL
: SAL_INFO("emfio", "not implemented 'GradientFill'"); break;
1802 case EMR_SETLINKEDUFIS
: SAL_INFO("emfio", "not implemented 'SetLinkedUFIS'"); break;
1804 case EMR_SETMAPPERFLAGS
: SAL_INFO("emfio", "not implemented 'SetMapperFlags'"); break;
1805 case EMR_SETICMMODE
: SAL_INFO("emfio", "not implemented 'SetICMMode'"); break;
1806 case EMR_CREATEMONOBRUSH
: SAL_INFO("emfio", "not implemented 'CreateMonoBrush'"); break;
1807 case EMR_SETBRUSHORGEX
: SAL_INFO("emfio", "not implemented 'SetBrushOrgEx'"); break;
1808 case EMR_SETMETARGN
: SAL_INFO("emfio", "not implemented 'SetMetArgn'"); break;
1809 case EMR_SETMITERLIMIT
: SAL_INFO("emfio", "not implemented 'SetMiterLimit'"); break;
1810 case EMR_EXCLUDECLIPRECT
: SAL_INFO("emfio", "not implemented 'ExcludeClipRect'"); break;
1811 case EMR_REALIZEPALETTE
: SAL_INFO("emfio", "not implemented 'RealizePalette'"); break;
1812 case EMR_SELECTPALETTE
: SAL_INFO("emfio", "not implemented 'SelectPalette'"); break;
1813 case EMR_CREATEPALETTE
: SAL_INFO("emfio", "not implemented 'CreatePalette'"); break;
1814 case EMR_ALPHADIBBLEND
: SAL_INFO("emfio", "not implemented 'AlphaDibBlend'"); break;
1815 case EMR_SETTEXTJUSTIFICATION
: SAL_INFO("emfio", "not implemented 'SetTextJustification'"); break;
1818 case EMR_HEADER
: // has already been read at ReadHeader()
1821 default : SAL_INFO("emfio", "Unknown Meta Action"); break;
1824 mpInputStream
->Seek( nNextPos
);
1826 if( !maBmpSaveList
.empty() )
1827 ResolveBitmapActions( maBmpSaveList
);
1830 mpInputStream
->Seek(mnEndPos
);
1835 bool EmfReader::ReadHeader()
1837 // Spare me the METAFILEHEADER here
1838 // Reading the METAHEADER - EMR_HEADER ([MS-EMF] section 2.3.4.2 EMR_HEADER Record Types)
1839 sal_uInt32
nType(0), nHeaderSize(0);
1840 mpInputStream
->ReadUInt32(nType
).ReadUInt32(nHeaderSize
);
1841 if (nType
!= 0x00000001)
1843 // per [MS-EMF] 2.3.4.2 EMF Header Record Types, type MUST be 0x00000001
1844 SAL_WARN("emfio", "EMF header type is not set to 0x00000001 - possibly corrupted file?");
1848 // Start reading the EMR_HEADER Header object
1850 // bound size (RectL object, see [MS-WMF] section 2.2.2.19)
1851 tools::Rectangle rclBounds
= ReadRectangle(); // rectangle in logical units
1853 // picture frame size (RectL object)
1854 tools::Rectangle rclFrame
= ReadRectangle(); // rectangle in device units 1/100th mm
1856 sal_uInt32
nSignature(0);
1857 mpInputStream
->ReadUInt32(nSignature
);
1859 // nSignature MUST be the ASCII characters "FME", see [WS-EMF] 2.2.9 Header Object
1860 // and 2.1.14 FormatSignature Enumeration
1861 if (nSignature
!= 0x464d4520)
1863 SAL_WARN("emfio", "EMF\t\tSignature is not 0x464d4520 (\"FME\") - possibly corrupted file?");
1867 sal_uInt32
nVersion(0);
1868 mpInputStream
->ReadUInt32(nVersion
); // according to [WS-EMF] 2.2.9, this SHOULD be 0x0001000, however
1869 // Microsoft note that not even Windows checks this...
1870 if (nVersion
!= 0x00010000)
1872 SAL_WARN("emfio", "EMF\t\tThis really should be 0x00010000, though not absolutely essential...");
1875 mpInputStream
->ReadUInt32(mnEndPos
); // size of metafile
1876 mnEndPos
+= mnStartPos
;
1878 sal_uInt32 nStrmPos
= mpInputStream
->Tell(); // checking if mnEndPos is valid
1879 sal_uInt32 nActualFileSize
= nStrmPos
+ mpInputStream
->remainingSize();
1881 if ( nActualFileSize
< mnEndPos
)
1883 SAL_WARN("emfio", "EMF\t\tEMF Header object records number of bytes as " << mnEndPos
1884 << ", however the file size is actually " << nActualFileSize
1885 << " bytes. Possible file corruption?");
1886 mnEndPos
= nActualFileSize
;
1889 mpInputStream
->ReadInt32(mnRecordCount
);
1891 if (mnRecordCount
<= 0)
1893 SAL_WARN("emfio", "EMF\t\tEMF Header object shows record counter as <= 0! This shouldn't "
1894 "be possible... indicator of possible file corruption?");
1898 // the number of "handles", or graphics objects used in the metafile
1900 sal_uInt16 nHandlesCount
;
1901 mpInputStream
->ReadUInt16(nHandlesCount
);
1903 // the next 2 bytes are reserved, but according to [MS-EMF] section 2.2.9
1904 // it MUST be 0x000 and MUST be ignored... the thing is, having such a specific
1905 // value is actually pretty useful in checking if there is possible corruption
1907 sal_uInt16
nReserved(0);
1908 mpInputStream
->ReadUInt16(nReserved
);
1910 if ( nReserved
!= 0x0000 )
1912 SAL_WARN("emfio", "EMF\t\tEMF Header object's reserved field is NOT 0x0000... possible "
1916 // The next 4 bytes specifies the number of characters in the metafile description.
1917 // The 4 bytes after that specific the offset from this record that contains the
1918 // metafile description... zero means no description string.
1919 // For now, we ignore it.
1921 mpInputStream
->SeekRel(0x8);
1923 sal_uInt32
nPalEntries(0);
1924 mpInputStream
->ReadUInt32(nPalEntries
);
1925 sal_Int32
nPixX(0), nPixY(0), nMillX(0), nMillY(0);
1926 mpInputStream
->ReadInt32(nPixX
);
1927 mpInputStream
->ReadInt32(nPixY
);
1928 mpInputStream
->ReadInt32(nMillX
);
1929 mpInputStream
->ReadInt32(nMillY
);
1931 SetrclFrame(rclFrame
);
1932 SetrclBounds(rclBounds
);
1933 SetRefPix(Size( nPixX
, nPixY
) );
1934 SetRefMill(Size( nMillX
, nMillY
) );
1936 return checkSeek(*mpInputStream
, mnStartPos
+ nHeaderSize
);
1939 tools::Rectangle
EmfReader::ReadRectangle()
1941 sal_Int32 nLeft
, nTop
, nRight
, nBottom
;
1942 mpInputStream
->ReadInt32(nLeft
);
1943 mpInputStream
->ReadInt32(nTop
);
1944 mpInputStream
->ReadInt32(nRight
);
1945 mpInputStream
->ReadInt32(nBottom
);
1946 return tools::Rectangle(nLeft
, nTop
, nRight
, nBottom
);
1949 tools::Rectangle
EmfReader::ReadRectangle( sal_Int32 x1
, sal_Int32 y1
, sal_Int32 x2
, sal_Int32 y2
)
1952 Point
aBR(o3tl::saturating_add
<sal_Int32
>(x2
, -1), o3tl::saturating_add
<sal_Int32
>(y2
, -1));
1953 return tools::Rectangle(aTL
, aBR
);
1957 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */