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 <wmfreader.hxx>
21 #include <emfreader.hxx>
24 #include <boost/optional.hpp>
26 #include <rtl/tencinfo.h>
27 #include <sal/log.hxx>
28 #include <osl/endian.h>
29 #include <vcl/gdimtf.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/dibtools.hxx>
32 #include <vcl/outdev.hxx>
33 #include <vcl/wmfexternal.hxx>
34 #include <tools/fract.hxx>
35 #include <vcl/bitmapaccess.hxx>
36 #include <vcl/BitmapTools.hxx>
37 #include <osl/thread.h>
40 #define W_META_SETBKCOLOR 0x0201
41 #define W_META_SETBKMODE 0x0102
42 #define W_META_SETMAPMODE 0x0103
43 #define W_META_SETROP2 0x0104
44 #define W_META_SETRELABS 0x0105
45 #define W_META_SETPOLYFILLMODE 0x0106
46 #define W_META_SETSTRETCHBLTMODE 0x0107
47 #define W_META_SETTEXTCHAREXTRA 0x0108
48 #define W_META_SETTEXTCOLOR 0x0209
49 #define W_META_SETTEXTJUSTIFICATION 0x020A
50 #define W_META_SETWINDOWORG 0x020B
51 #define W_META_SETWINDOWEXT 0x020C
52 #define W_META_SETVIEWPORTORG 0x020D
53 #define W_META_SETVIEWPORTEXT 0x020E
54 #define W_META_OFFSETWINDOWORG 0x020F
55 #define W_META_SCALEWINDOWEXT 0x0410
56 #define W_META_OFFSETVIEWPORTORG 0x0211
57 #define W_META_SCALEVIEWPORTEXT 0x0412
58 #define W_META_LINETO 0x0213
59 #define W_META_MOVETO 0x0214
60 #define W_META_EXCLUDECLIPRECT 0x0415
61 #define W_META_INTERSECTCLIPRECT 0x0416
62 #define W_META_ARC 0x0817
63 #define W_META_ELLIPSE 0x0418
64 #define W_META_FLOODFILL 0x0419
65 #define W_META_PIE 0x081A
66 #define W_META_RECTANGLE 0x041B
67 #define W_META_ROUNDRECT 0x061C
68 #define W_META_PATBLT 0x061D
69 #define W_META_SAVEDC 0x001E
70 #define W_META_SETPIXEL 0x041F
71 #define W_META_OFFSETCLIPRGN 0x0220
72 #define W_META_TEXTOUT 0x0521
73 #define W_META_BITBLT 0x0922
74 #define W_META_STRETCHBLT 0x0B23
75 #define W_META_POLYGON 0x0324
76 #define W_META_POLYLINE 0x0325
77 #define W_META_ESCAPE 0x0626
78 #define W_META_RESTOREDC 0x0127
79 #define W_META_FILLREGION 0x0228
80 #define W_META_FRAMEREGION 0x0429
81 #define W_META_INVERTREGION 0x012A
82 #define W_META_PAINTREGION 0x012B
83 #define W_META_SELECTCLIPREGION 0x012C
84 #define W_META_SELECTOBJECT 0x012D
85 #define W_META_SETTEXTALIGN 0x012E
86 #define W_META_DRAWTEXT 0x062F
87 #define W_META_CHORD 0x0830
88 #define W_META_SETMAPPERFLAGS 0x0231
89 #define W_META_EXTTEXTOUT 0x0a32
90 #define W_META_SETDIBTODEV 0x0d33
91 #define W_META_SELECTPALETTE 0x0234
92 #define W_META_REALIZEPALETTE 0x0035
93 #define W_META_ANIMATEPALETTE 0x0436
94 #define W_META_SETPALENTRIES 0x0037
95 #define W_META_POLYPOLYGON 0x0538
96 #define W_META_RESIZEPALETTE 0x0139
97 #define W_META_DIBBITBLT 0x0940
98 #define W_META_DIBSTRETCHBLT 0x0b41
99 #define W_META_DIBCREATEPATTERNBRUSH 0x0142
100 #define W_META_STRETCHDIB 0x0f43
101 #define W_META_EXTFLOODFILL 0x0548
102 #define W_META_RESETDC 0x014C
103 #define W_META_STARTDOC 0x014D
104 #define W_META_STARTPAGE 0x004F
105 #define W_META_ENDPAGE 0x0050
106 #define W_META_ABORTDOC 0x0052
107 #define W_META_ENDDOC 0x005E
108 #define W_META_DELETEOBJECT 0x01f0
109 #define W_META_CREATEPALETTE 0x00f7
110 #define W_META_CREATEBRUSH 0x00F8
111 #define W_META_CREATEPATTERNBRUSH 0x01F9
112 #define W_META_CREATEPENINDIRECT 0x02FA
113 #define W_META_CREATEFONTINDIRECT 0x02FB
114 #define W_META_CREATEBRUSHINDIRECT 0x02FC
115 #define W_META_CREATEBITMAPINDIRECT 0x02FD
116 #define W_META_CREATEBITMAP 0x06FE
117 #define W_META_CREATEREGION 0x06FF
121 void GetWinExtMax(const Point
& rSource
, tools::Rectangle
& rPlaceableBound
, const sal_Int16 nMapMode
)
123 Point
aSource(rSource
);
124 if (nMapMode
== MM_HIMETRIC
)
125 aSource
.setY( -rSource
.Y() );
126 if (aSource
.X() < rPlaceableBound
.Left())
127 rPlaceableBound
.SetLeft( aSource
.X() );
128 if (aSource
.X() > rPlaceableBound
.Right())
129 rPlaceableBound
.SetRight( aSource
.X() );
130 if (aSource
.Y() < rPlaceableBound
.Top())
131 rPlaceableBound
.SetTop( aSource
.Y() );
132 if (aSource
.Y() > rPlaceableBound
.Bottom())
133 rPlaceableBound
.SetBottom( aSource
.Y() );
136 void GetWinExtMax(const tools::Rectangle
& rSource
, tools::Rectangle
& rPlaceableBound
, const sal_Int16 nMapMode
)
138 GetWinExtMax(rSource
.TopLeft(), rPlaceableBound
, nMapMode
);
139 GetWinExtMax(rSource
.BottomRight(), rPlaceableBound
, nMapMode
);
146 inline Point
WmfReader::ReadPoint()
148 short nX
= 0, nY
= 0;
149 mpInputStream
->ReadInt16( nX
).ReadInt16( nY
);
150 return Point( nX
, nY
);
153 inline Point
WmfReader::ReadYX()
155 short nX
= 0, nY
= 0;
156 mpInputStream
->ReadInt16( nY
).ReadInt16( nX
);
157 return Point( nX
, nY
);
160 tools::Rectangle
WmfReader::ReadRectangle()
167 return tools::Rectangle( aTL
, aBR
);
170 Size
WmfReader::ReadYXExt()
173 mpInputStream
->ReadInt16( nH
).ReadInt16( nW
);
174 return Size( nW
, nH
);
177 void WmfReader::ReadRecordParams( sal_uInt16 nFunc
)
181 case W_META_SETBKCOLOR
:
183 SetBkColor( ReadColor() );
187 case W_META_SETBKMODE
:
190 mpInputStream
->ReadUInt16( nDat
);
191 SetBkMode( static_cast<BkMode
>(nDat
) );
196 case W_META_SETMAPMODE
:
198 sal_Int16 nMapMode
= 0;
199 mpInputStream
->ReadInt16( nMapMode
);
200 SetMapMode( nMapMode
);
206 sal_uInt16 nROP2
= 0;
207 mpInputStream
->ReadUInt16( nROP2
);
208 SetRasterOp( static_cast<WMFRasterOp
>(nROP2
) );
212 case W_META_SETTEXTCOLOR
:
214 SetTextColor( ReadColor() );
218 case W_META_SETWINDOWORG
:
220 SetWinOrg( ReadYX() );
224 case W_META_SETWINDOWEXT
:
226 short nWidth
= 0, nHeight
= 0;
227 mpInputStream
->ReadInt16( nHeight
).ReadInt16( nWidth
);
228 SetWinExt( Size( nWidth
, nHeight
) );
232 case W_META_OFFSETWINDOWORG
:
234 short nXAdd
= 0, nYAdd
= 0;
235 mpInputStream
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
236 SetWinOrgOffset( nXAdd
, nYAdd
);
240 case W_META_SCALEWINDOWEXT
:
242 short nXNum
= 0, nXDenom
= 0, nYNum
= 0, nYDenom
= 0;
243 mpInputStream
->ReadInt16( nYDenom
).ReadInt16( nYNum
).ReadInt16( nXDenom
).ReadInt16( nXNum
);
244 if (!nYDenom
|| !nXDenom
)
246 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
249 ScaleWinExt( static_cast<double>(nXNum
) / nXDenom
, static_cast<double>(nYNum
) / nYDenom
);
253 case W_META_SETVIEWPORTORG
:
254 case W_META_SETVIEWPORTEXT
:
257 case W_META_OFFSETVIEWPORTORG
:
259 short nXAdd
= 0, nYAdd
= 0;
260 mpInputStream
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
261 SetDevOrgOffset( nXAdd
, nYAdd
);
265 case W_META_SCALEVIEWPORTEXT
:
267 short nXNum
= 0, nXDenom
= 0, nYNum
= 0, nYDenom
= 0;
268 mpInputStream
->ReadInt16( nYDenom
).ReadInt16( nYNum
).ReadInt16( nXDenom
).ReadInt16( nXNum
);
269 if (!nYDenom
|| !nXDenom
)
271 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
274 ScaleDevExt( static_cast<double>(nXNum
) / nXDenom
, static_cast<double>(nYNum
) / nYDenom
);
290 case W_META_INTERSECTCLIPRECT
:
292 IntersectClipRect( ReadRectangle() );
296 case W_META_RECTANGLE
:
298 DrawRect( ReadRectangle() );
302 case W_META_ROUNDRECT
:
304 Size
aSize( ReadYXExt() );
305 DrawRoundRect( ReadRectangle(), Size( aSize
.Width() / 2, aSize
.Height() / 2 ) );
311 DrawEllipse( ReadRectangle() );
317 Point
aEnd( ReadYX() );
318 Point
aStart( ReadYX() );
319 tools::Rectangle
aRect( ReadRectangle() );
321 DrawArc( aRect
, aStart
, aEnd
);
327 Point
aEnd( ReadYX() );
328 Point
aStart( ReadYX() );
329 tools::Rectangle
aRect( ReadRectangle() );
332 // #i73608# OutputDevice deviates from WMF
333 // semantics. start==end means full ellipse here.
335 DrawEllipse( aRect
);
337 DrawPie( aRect
, aStart
, aEnd
);
343 Point
aEnd( ReadYX() );
344 Point
aStart( ReadYX() );
345 tools::Rectangle
aRect( ReadRectangle() );
347 DrawChord( aRect
, aStart
, aEnd
);
353 bool bRecordOk
= true;
355 sal_uInt16
nPoints(0);
356 mpInputStream
->ReadUInt16(nPoints
);
358 if (nPoints
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
364 tools::Polygon
aPoly(nPoints
);
365 for (sal_uInt16
i(0); i
< nPoints
&& mpInputStream
->good(); ++i
)
366 aPoly
[ i
] = ReadPoint();
367 DrawPolygon(aPoly
, false/*bRecordPath*/);
370 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polygon record has more points than we can handle");
372 bRecordOk
&= mpInputStream
->good();
376 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
382 case W_META_POLYPOLYGON
:
384 sal_uInt16
nPolyCount(0);
385 // Number of polygons:
386 mpInputStream
->ReadUInt16( nPolyCount
);
387 if (nPolyCount
&& mpInputStream
->good())
389 bool bRecordOk
= true;
390 if (nPolyCount
> mpInputStream
->remainingSize() / sizeof(sal_uInt16
))
395 // Number of points of each polygon. Determine total number of points
396 std::unique_ptr
<sal_uInt16
[]> xPolygonPointCounts(new sal_uInt16
[nPolyCount
]);
397 sal_uInt16
* pnPoints
= xPolygonPointCounts
.get();
398 tools::PolyPolygon
aPolyPoly(nPolyCount
);
399 sal_uInt16 nPoints
= 0;
400 for (sal_uInt16 a
= 0; a
< nPolyCount
&& mpInputStream
->good(); ++a
)
402 mpInputStream
->ReadUInt16( pnPoints
[a
] );
404 if (pnPoints
[a
] > SAL_MAX_UINT16
- nPoints
)
410 nPoints
+= pnPoints
[a
];
413 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polypolygon record has more polygons than we can handle");
415 bRecordOk
&= mpInputStream
->good();
419 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
423 // Polygon points are:
424 for (sal_uInt16 a
= 0; a
< nPolyCount
&& mpInputStream
->good(); ++a
)
426 const sal_uInt16
nPointCount(pnPoints
[a
]);
428 if (nPointCount
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
434 std::unique_ptr
<Point
[]> xPolygonPoints(new Point
[nPointCount
]);
435 Point
* pPtAry
= xPolygonPoints
.get();
437 for(sal_uInt16
b(0); b
< nPointCount
&& mpInputStream
->good(); ++b
)
439 pPtAry
[b
] = ReadPoint();
442 aPolyPoly
.Insert( tools::Polygon(nPointCount
, pPtAry
) );
445 bRecordOk
&= mpInputStream
->good();
449 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
453 DrawPolyPolygon( aPolyPoly
);
458 case W_META_POLYLINE
:
460 bool bRecordOk
= true;
462 sal_uInt16
nPoints(0);
463 mpInputStream
->ReadUInt16(nPoints
);
465 if (nPoints
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
471 tools::Polygon
aPoly(nPoints
);
472 for (sal_uInt16
i(0); i
< nPoints
&& mpInputStream
->good(); ++i
)
473 aPoly
[ i
] = ReadPoint();
474 DrawPolyLine( aPoly
);
477 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polyline record has more points than we can handle");
479 bRecordOk
&= mpInputStream
->good();
483 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
495 case W_META_RESTOREDC
:
501 case W_META_SETPIXEL
:
503 const Color aColor
= ReadColor();
504 DrawPixel( ReadYX(), aColor
);
508 case W_META_OFFSETCLIPRGN
:
510 MoveClipRegion( ReadYXExt() );
516 //record is Recordsize, RecordFunction, StringLength, <String>, YStart, XStart
517 const sal_uInt32 nNonStringLen
= sizeof(sal_uInt32
) + 4 * sizeof(sal_uInt16
);
518 const sal_uInt32 nRecSize
= mnRecSize
* 2;
520 if (nRecSize
< nNonStringLen
)
522 SAL_WARN("vcl.wmf", "W_META_TEXTOUT too short");
526 sal_uInt16 nLength
= 0;
527 mpInputStream
->ReadUInt16(nLength
);
528 sal_uInt16 nStoredLength
= (nLength
+ 1) &~ 1;
530 if (nRecSize
- nNonStringLen
< nStoredLength
)
532 SAL_WARN("vcl.wmf", "W_META_TEXTOUT too short, truncating string");
533 nLength
= nStoredLength
= nRecSize
- nNonStringLen
;
538 std::vector
<char> aChars(nStoredLength
);
539 nLength
= std::min
<sal_uInt16
>(nLength
, mpInputStream
->ReadBytes(aChars
.data(), aChars
.size()));
540 OUString
aText(aChars
.data(), nLength
, GetCharSet());
541 Point
aPosition( ReadYX() );
542 DrawText( aPosition
, aText
);
547 case W_META_EXTTEXTOUT
:
549 //record is Recordsize, RecordFunction, Y, X, StringLength, options, maybe rectangle, <String>
550 sal_uInt32 nNonStringLen
= sizeof(sal_uInt32
) + 5 * sizeof(sal_uInt16
);
551 const sal_uInt32 nRecSize
= mnRecSize
* 2;
553 if (nRecSize
< nNonStringLen
)
555 SAL_WARN("vcl.wmf", "W_META_EXTTEXTOUT too short");
559 auto nRecordPos
= mpInputStream
->Tell() - 6;
560 Point aPosition
= ReadYX();
561 sal_uInt16 nLen
= 0, nOptions
= 0;
562 mpInputStream
->ReadUInt16( nLen
).ReadUInt16( nOptions
);
564 if (nOptions
& ETO_CLIPPED
)
566 nNonStringLen
+= 2 * sizeof(sal_uInt16
);
568 if (nRecSize
< nNonStringLen
)
570 SAL_WARN("vcl.wmf", "W_META_TEXTOUT too short");
576 SAL_WARN("vcl.wmf", "clipping unsupported");
579 ComplexTextLayoutFlags nTextLayoutMode
= ComplexTextLayoutFlags::Default
;
580 if ( nOptions
& ETO_RTLREADING
)
581 nTextLayoutMode
= ComplexTextLayoutFlags::BiDiRtl
| ComplexTextLayoutFlags::TextOriginLeft
;
582 SetTextLayoutMode( nTextLayoutMode
);
583 SAL_WARN_IF( ( nOptions
& ( ETO_PDY
| ETO_GLYPH_INDEX
) ) != 0, "vcl.wmf", "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
585 // output only makes sense if the text contains characters
588 sal_Int32 nOriginalTextLen
= nLen
;
589 sal_Int32 nOriginalBlockLen
= ( nOriginalTextLen
+ 1 ) &~ 1;
591 auto nMaxStreamPos
= nRecordPos
+ nRecSize
;
592 auto nRemainingSize
= std::min(mpInputStream
->remainingSize(), nMaxStreamPos
- mpInputStream
->Tell());
593 if (nRemainingSize
< static_cast<sal_uInt32
>(nOriginalBlockLen
))
595 SAL_WARN("vcl.wmf", "exttextout record claimed more data than the stream can provide");
596 nOriginalTextLen
= nOriginalBlockLen
= nRemainingSize
;
599 std::unique_ptr
<char[]> pChar(new char[nOriginalBlockLen
]);
600 mpInputStream
->ReadBytes(pChar
.get(), nOriginalBlockLen
);
601 OUString
aText(pChar
.get(), nOriginalTextLen
, GetCharSet()); // after this conversion the text may contain
602 sal_Int32 nNewTextLen
= aText
.getLength(); // less character (japanese version), so the
603 // dxAry will not fit
606 std::unique_ptr
<long[]> pDXAry
, pDYAry
;
607 auto nDxArySize
= nMaxStreamPos
- mpInputStream
->Tell();
608 auto nDxAryEntries
= nDxArySize
>> 1;
609 bool bUseDXAry
= false;
611 if ( ( ( nDxAryEntries
% nOriginalTextLen
) == 0 ) && ( nNewTextLen
<= nOriginalTextLen
) )
613 sal_Int32 i
; // needed just outside the for
614 pDXAry
.reset(new long[ nNewTextLen
]);
615 if ( nOptions
& ETO_PDY
)
617 pDYAry
.reset(new long[ nNewTextLen
]);
619 for (i
= 0; i
< nNewTextLen
; i
++ )
621 if ( mpInputStream
->Tell() >= nMaxStreamPos
)
623 sal_Int32 nDxCount
= 1;
624 if ( nNewTextLen
!= nOriginalTextLen
)
626 sal_Unicode cUniChar
= aText
[i
];
627 OString
aTmp(&cUniChar
, 1, GetCharSet());
628 if ( aTmp
.getLength() > 1 )
630 nDxCount
= aTmp
.getLength();
634 sal_Int16 nDx
= 0, nDy
= 0;
637 if ( ( mpInputStream
->Tell() + 2 ) > nMaxStreamPos
)
639 sal_Int16 nDxTmp
= 0;
640 mpInputStream
->ReadInt16(nDxTmp
);
642 if ( nOptions
& ETO_PDY
)
644 if ( ( mpInputStream
->Tell() + 2 ) > nMaxStreamPos
)
646 sal_Int16 nDyTmp
= 0;
647 mpInputStream
->ReadInt16(nDyTmp
);
653 if ( nOptions
& ETO_PDY
)
658 if ( i
== nNewTextLen
)
661 if ( pDXAry
&& bUseDXAry
)
662 DrawText( aPosition
, aText
, pDXAry
.get(), pDYAry
.get() );
664 DrawText( aPosition
, aText
);
670 case W_META_SELECTOBJECT
:
672 sal_Int16 nObjIndex
= 0;
673 mpInputStream
->ReadInt16( nObjIndex
);
674 SelectObject( nObjIndex
);
678 case W_META_SETTEXTALIGN
:
680 sal_uInt16 nAlign
= 0;
681 mpInputStream
->ReadUInt16( nAlign
);
682 SetTextAlign( nAlign
);
688 // 0-3 : nWinROP #93454#
689 // 4-5 : y offset of source bitmap
690 // 6-7 : x offset of source bitmap
691 // 8-9 : used height of source bitmap
692 // 10-11 : used width of source bitmap
693 // 12-13 : destination position y (in pixel)
694 // 14-15 : destination position x (in pixel)
695 // 16-17 : don't know
696 // 18-19 : Width Bitmap in Pixel
697 // 20-21 : Height Bitmap in Pixel
698 // 22-23 : bytes per scanline
702 sal_Int32 nWinROP
= 0;
703 sal_uInt16 nSx
= 0, nSy
= 0, nSxe
= 0, nSye
= 0, nDontKnow
= 0, nWidth
= 0, nHeight
= 0, nBytesPerScan
= 0;
704 sal_uInt8 nPlanes
, nBitCount
;
706 mpInputStream
->ReadInt32( nWinROP
)
707 .ReadUInt16( nSy
).ReadUInt16( nSx
).ReadUInt16( nSye
).ReadUInt16( nSxe
);
708 Point
aPoint( ReadYX() );
709 mpInputStream
->ReadUInt16( nDontKnow
).ReadUInt16( nWidth
).ReadUInt16( nHeight
).ReadUInt16( nBytesPerScan
).ReadUChar( nPlanes
).ReadUChar( nBitCount
);
711 bool bOk
= nWidth
&& nHeight
&& nPlanes
== 1 && nBitCount
== 1 && nBytesPerScan
!= 0;
714 bOk
= nBytesPerScan
<= mpInputStream
->remainingSize() / nHeight
;
718 vcl::bitmap::RawBitmap
aBmp( Size( nWidth
, nHeight
), 24 );
719 for (sal_uInt16 y
= 0; y
< nHeight
&& mpInputStream
->good(); ++y
)
722 for (sal_uInt16 scan
= 0; scan
< nBytesPerScan
; scan
++ )
724 sal_Int8 nEightPixels
= 0;
725 mpInputStream
->ReadSChar( nEightPixels
);
726 for (sal_Int8 i
= 7; i
>= 0; i
-- )
730 aBmp
.SetPixel( y
, x
, ((nEightPixels
>>i
)&1) ? COL_BLACK
: COL_WHITE
);
736 BitmapEx aBitmap
= vcl::bitmap::CreateFromData(std::move(aBmp
));
738 ( nSx
+ nSxe
<= nWidth
) &&
739 ( nSy
+ nSye
<= nHeight
) )
741 tools::Rectangle
aCropRect( Point( nSx
, nSy
), Size( nSxe
, nSye
) );
742 aBitmap
.Crop( aCropRect
);
744 tools::Rectangle
aDestRect( aPoint
, Size( nSxe
, nSye
) );
745 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmap
, aDestRect
, nWinROP
));
750 case W_META_STRETCHBLT
:
751 case W_META_DIBBITBLT
:
752 case W_META_DIBSTRETCHBLT
:
753 case W_META_STRETCHDIB
:
755 sal_Int32 nWinROP
= 0;
756 sal_uInt16 nSx
= 0, nSy
= 0, nSxe
= 0, nSye
= 0, nUsage
= 0;
759 mpInputStream
->ReadInt32( nWinROP
);
761 if( nFunc
== W_META_STRETCHDIB
)
762 mpInputStream
->ReadUInt16( nUsage
);
764 // nSye and nSxe is the number of pixels that has to been used
765 // If they are set to zero, it is as indicator not to scale the bitmap later
767 if( nFunc
== W_META_STRETCHDIB
|| nFunc
== W_META_STRETCHBLT
|| nFunc
== W_META_DIBSTRETCHBLT
)
768 mpInputStream
->ReadUInt16( nSye
).ReadUInt16( nSxe
);
770 // nSy and nx is the offset of the first pixel
771 mpInputStream
->ReadUInt16( nSy
).ReadUInt16( nSx
);
773 if( nFunc
== W_META_STRETCHDIB
|| nFunc
== W_META_DIBBITBLT
|| nFunc
== W_META_DIBSTRETCHBLT
)
775 if ( nWinROP
== PATCOPY
)
776 mpInputStream
->ReadUInt16( nUsage
); // i don't know anything of this parameter, so its called nUsage
777 // DrawRect( Rectangle( ReadYX(), aDestSize ), false );
779 Size
aDestSize( ReadYXExt() );
780 if ( aDestSize
.Width() && aDestSize
.Height() ) // #92623# do not try to read buggy bitmaps
782 tools::Rectangle
aDestRect( ReadYX(), aDestSize
);
783 if ( nWinROP
!= PATCOPY
)
784 ReadDIB(aBmp
, *mpInputStream
, false);
786 // test if it is sensible to crop
788 ( nSx
+ nSxe
<= aBmp
.GetSizePixel().Width() ) &&
789 ( nSy
+ nSye
<= aBmp
.GetSizePixel().Height() ) )
791 tools::Rectangle
aCropRect( Point( nSx
, nSy
), Size( nSxe
, nSye
) );
792 aBmp
.Crop( aCropRect
);
794 maBmpSaveList
.emplace_back(new BSaveStruct(aBmp
, aDestRect
, nWinROP
));
800 case W_META_DIBCREATEPATTERNBRUSH
:
803 sal_uInt32 nRed
= 0, nGreen
= 0, nBlue
= 0, nCount
= 1;
804 sal_uInt16 nFunction
= 0;
806 mpInputStream
->ReadUInt16( nFunction
).ReadUInt16( nFunction
);
808 ReadDIB(aBmp
, *mpInputStream
, false);
811 Bitmap::ScopedReadAccess
pBmp(aBmp
);
812 for ( long y
= 0; y
< pBmp
->Height(); y
++ )
814 for ( long x
= 0; x
< pBmp
->Width(); x
++ )
816 const BitmapColor
aColor( pBmp
->GetColor( y
, x
) );
818 nRed
+= aColor
.GetRed();
819 nGreen
+= aColor
.GetGreen();
820 nBlue
+= aColor
.GetBlue();
823 nCount
= pBmp
->Height() * pBmp
->Width();
827 Color
aColor( static_cast<sal_uInt8
>( nRed
/ nCount
), static_cast<sal_uInt8
>( nGreen
/ nCount
), static_cast<sal_uInt8
>( nBlue
/ nCount
) );
828 CreateObject(std::make_unique
<WinMtfFillStyle
>( aColor
, false ));
832 case W_META_DELETEOBJECT
:
834 sal_Int16 nIndex
= 0;
835 mpInputStream
->ReadInt16( nIndex
);
836 DeleteObject( nIndex
);
840 case W_META_CREATEPALETTE
:
846 case W_META_CREATEBRUSH
:
848 CreateObject(std::make_unique
<WinMtfFillStyle
>( COL_WHITE
, false ));
852 case W_META_CREATEPATTERNBRUSH
:
854 CreateObject(std::make_unique
<WinMtfFillStyle
>( COL_WHITE
, false ));
858 case W_META_CREATEPENINDIRECT
:
861 sal_uInt16 nStyle
= 0;
862 sal_uInt16 nWidth
= 0;
863 sal_uInt16 nHeight
= 0;
865 mpInputStream
->ReadUInt16(nStyle
);
866 mpInputStream
->ReadUInt16(nWidth
);
867 mpInputStream
->ReadUInt16(nHeight
);
870 aLineInfo
.SetWidth(nWidth
);
872 bool bTransparent
= false;
874 switch( nStyle
& 0xFF )
877 aLineInfo
.SetStyle( LineStyle::Dash
);
878 aLineInfo
.SetDashCount( 1 );
879 aLineInfo
.SetDotCount( 2 );
882 aLineInfo
.SetStyle( LineStyle::Dash
);
883 aLineInfo
.SetDashCount( 1 );
884 aLineInfo
.SetDotCount( 1 );
887 aLineInfo
.SetStyle( LineStyle::Dash
);
888 aLineInfo
.SetDashCount( 0 );
889 aLineInfo
.SetDotCount( 1 );
892 aLineInfo
.SetStyle( LineStyle::Dash
);
893 aLineInfo
.SetDashCount( 1 );
894 aLineInfo
.SetDotCount( 0 );
898 aLineInfo
.SetStyle( LineStyle::NONE
);
901 case PS_INSIDEFRAME
:
903 aLineInfo
.SetStyle( LineStyle::Solid
);
905 switch( nStyle
& 0xF00 )
907 case PS_ENDCAP_ROUND
:
908 aLineInfo
.SetLineCap( css::drawing::LineCap_ROUND
);
910 case PS_ENDCAP_SQUARE
:
911 aLineInfo
.SetLineCap( css::drawing::LineCap_SQUARE
);
913 case PS_ENDCAP_FLAT
:
915 aLineInfo
.SetLineCap( css::drawing::LineCap_BUTT
);
917 switch( nStyle
& 0xF000 )
920 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Round
);
923 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Miter
);
926 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::Bevel
);
929 aLineInfo
.SetLineJoin ( basegfx::B2DLineJoin::NONE
);
931 CreateObject(std::make_unique
<WinMtfLineStyle
>( ReadColor(), aLineInfo
, bTransparent
));
935 case W_META_CREATEBRUSHINDIRECT
:
937 sal_uInt16 nStyle
= 0;
938 mpInputStream
->ReadUInt16( nStyle
);
939 CreateObject(std::make_unique
<WinMtfFillStyle
>( ReadColor(), ( nStyle
== BS_HOLLOW
) ));
943 case W_META_CREATEFONTINDIRECT
:
946 char lfFaceName
[LF_FACESIZE
+1];
947 sal_Int16 lfEscapement
= 0;
948 sal_Int16 lfOrientation
= 0;
949 sal_Int16 lfWeight
= 0;
952 aFontSize
= ReadYXExt();
953 mpInputStream
->ReadInt16( lfEscapement
);
954 mpInputStream
->ReadInt16( lfOrientation
);
955 mpInputStream
->ReadInt16( lfWeight
);
956 mpInputStream
->ReadUChar( aLogFont
.lfItalic
);
957 mpInputStream
->ReadUChar( aLogFont
.lfUnderline
);
958 mpInputStream
->ReadUChar( aLogFont
.lfStrikeOut
);
959 mpInputStream
->ReadUChar( aLogFont
.lfCharSet
);
960 mpInputStream
->ReadUChar( aLogFont
.lfOutPrecision
);
961 mpInputStream
->ReadUChar( aLogFont
.lfClipPrecision
);
962 mpInputStream
->ReadUChar( aLogFont
.lfQuality
);
963 mpInputStream
->ReadUChar( aLogFont
.lfPitchAndFamily
);
964 size_t nRet
= mpInputStream
->ReadBytes( lfFaceName
, LF_FACESIZE
);
965 lfFaceName
[nRet
] = 0;
966 aLogFont
.lfWidth
= aFontSize
.Width();
967 aLogFont
.lfHeight
= aFontSize
.Height();
968 aLogFont
.lfEscapement
= lfEscapement
;
969 aLogFont
.lfOrientation
= lfOrientation
;
970 aLogFont
.lfWeight
= lfWeight
;
972 rtl_TextEncoding eCharSet
;
973 if ( ( aLogFont
.lfCharSet
== OEM_CHARSET
) || ( aLogFont
.lfCharSet
== DEFAULT_CHARSET
) )
974 eCharSet
= osl_getThreadTextEncoding();
976 eCharSet
= rtl_getTextEncodingFromWindowsCharset( aLogFont
.lfCharSet
);
977 if ( eCharSet
== RTL_TEXTENCODING_DONTKNOW
)
978 eCharSet
= osl_getThreadTextEncoding();
979 if ( eCharSet
== RTL_TEXTENCODING_SYMBOL
)
980 eCharSet
= RTL_TEXTENCODING_MS_1252
;
981 aLogFont
.alfFaceName
= OUString( lfFaceName
, strlen(lfFaceName
), eCharSet
);
983 CreateObject(std::make_unique
<WinMtfFontStyle
>( aLogFont
));
987 case W_META_CREATEBITMAPINDIRECT
:
993 case W_META_CREATEBITMAP
:
999 case W_META_CREATEREGION
:
1005 case W_META_EXCLUDECLIPRECT
:
1007 ExcludeClipRect( ReadRectangle() );
1013 sal_uInt32 nROP
= 0;
1014 WMFRasterOp nOldROP
= WMFRasterOp::NONE
;
1015 mpInputStream
->ReadUInt32( nROP
);
1016 Size aSize
= ReadYXExt();
1017 nOldROP
= SetRasterOp( static_cast<WMFRasterOp
>(nROP
) );
1018 DrawRect( tools::Rectangle( ReadYX(), aSize
), false );
1019 SetRasterOp( nOldROP
);
1023 case W_META_SELECTCLIPREGION
:
1025 sal_Int16 nObjIndex
= 0;
1026 mpInputStream
->ReadInt16( nObjIndex
);
1029 tools::PolyPolygon aEmptyPolyPoly
;
1030 SetClipPath( aEmptyPolyPoly
, RGN_COPY
, true );
1035 case W_META_ESCAPE
:
1037 // mnRecSize has been checked previously to be greater than 3
1038 sal_uInt64 nMetaRecSize
= static_cast< sal_uInt64
>(mnRecSize
- 2 ) * 2;
1039 sal_uInt64 nMetaRecEndPos
= mpInputStream
->Tell() + nMetaRecSize
;
1041 // taking care that mnRecSize does not exceed the maximal stream position
1042 if ( nMetaRecEndPos
> mnEndPos
)
1044 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1047 if (mnRecSize
>= 4 ) // minimal escape length
1049 sal_uInt16 nMode
= 0, nLen
= 0;
1050 mpInputStream
->ReadUInt16( nMode
)
1051 .ReadUInt16( nLen
);
1052 if ( ( nMode
== W_MFCOMMENT
) && ( nLen
>= 4 ) )
1054 sal_uInt32 nNewMagic
= 0; // we have to read int32 for
1055 mpInputStream
->ReadUInt32( nNewMagic
); // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier
1057 if( nNewMagic
== 0x2c2a4f4f && nLen
>= 14 )
1059 sal_uInt16 nMagic2
= 0;
1060 mpInputStream
->ReadUInt16( nMagic2
);
1061 if( nMagic2
== 0x0a ) // 2nd half of magic
1062 { // continue with private escape
1063 sal_uInt32 nCheck
= 0, nEsc
= 0;
1064 mpInputStream
->ReadUInt32( nCheck
)
1065 .ReadUInt32( nEsc
);
1067 sal_uInt32 nEscLen
= nLen
- 14;
1068 if ( nEscLen
<= (mnRecSize
* 2 ) )
1070 #ifdef OSL_BIGENDIAN
1071 sal_uInt32 nTmp
= OSL_SWAPDWORD( nEsc
);
1072 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nTmp
, 4 );
1074 sal_uInt32 nCheckSum
= rtl_crc32( 0, &nEsc
, 4 );
1076 std::unique_ptr
<sal_Int8
[]> pData
;
1078 if ( ( static_cast< sal_uInt64
>( nEscLen
) + mpInputStream
->Tell() ) > nMetaRecEndPos
)
1080 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1085 pData
.reset(new sal_Int8
[ nEscLen
]);
1086 mpInputStream
->ReadBytes(pData
.get(), nEscLen
);
1087 nCheckSum
= rtl_crc32( nCheckSum
, pData
.get(), nEscLen
);
1089 if ( nCheck
== nCheckSum
)
1093 case PRIVATE_ESCAPE_UNICODE
:
1095 // we will use text instead of polygons only if we have the correct font
1096 if ( Application::GetDefaultDevice()->IsFontAvailable( GetFont().GetFamilyName() ) )
1100 sal_uInt32 nStringLen
, nDXCount
;
1101 std::unique_ptr
<long[]> pDXAry
;
1102 SvMemoryStream
aMemoryStream( nEscLen
);
1103 aMemoryStream
.WriteBytes(pData
.get(), nEscLen
);
1104 aMemoryStream
.Seek( STREAM_SEEK_TO_BEGIN
);
1105 sal_Int32
nTmpX(0), nTmpY(0);
1106 aMemoryStream
.ReadInt32( nTmpX
)
1108 .ReadUInt32( nStringLen
);
1112 if ( ( static_cast< sal_uInt64
>( nStringLen
) * sizeof( sal_Unicode
) ) < ( nEscLen
- aMemoryStream
.Tell() ) )
1115 aString
= read_uInt16s_ToOUString(aMemoryStream
, nStringLen
);
1116 aMemoryStream
.ReadUInt32( nDXCount
);
1117 if ( ( static_cast< sal_uInt64
>( nDXCount
) * sizeof( sal_Int32
) ) >= ( nEscLen
- aMemoryStream
.Tell() ) )
1120 pDXAry
.reset(new long[ nDXCount
]);
1121 for (sal_uInt32 i
= 0; i
< nDXCount
; i
++ )
1124 aMemoryStream
.ReadInt32( val
);
1127 aMemoryStream
.ReadUInt32(mnSkipActions
);
1128 DrawText( aPt
, aString
, pDXAry
.get() );
1138 else if ( (nNewMagic
== static_cast< sal_uInt32
>(0x43464D57)) && (nLen
>= 34) && ( static_cast<sal_Int32
>(nLen
+ 10) <= static_cast<sal_Int32
>(mnRecSize
* 2) ))
1140 sal_uInt32 nComType
= 0, nVersion
= 0, nFlags
= 0, nComRecCount
= 0,
1141 nCurRecSize
= 0, nRemainingSize
= 0, nEMFTotalSize
= 0;
1142 sal_uInt16 nCheck
= 0;
1144 mpInputStream
->ReadUInt32( nComType
).ReadUInt32( nVersion
).ReadUInt16( nCheck
).ReadUInt32( nFlags
)
1145 .ReadUInt32( nComRecCount
).ReadUInt32( nCurRecSize
)
1146 .ReadUInt32( nRemainingSize
).ReadUInt32( nEMFTotalSize
); // the nRemainingSize is not mentioned in MSDN documentation
1147 // but it seems to be required to read in data produced by OLE
1149 if( nComType
== 0x01 && nVersion
== 0x10000 && nComRecCount
)
1152 { // first EMF comment
1153 mnEMFRecCount
= nComRecCount
;
1154 mnEMFSize
= nEMFTotalSize
;
1155 if (mnEMFSize
> mpInputStream
->remainingSize())
1157 SAL_WARN("vcl.wmf", "emf size claims to be larger than remaining data");
1158 mpEMFStream
.reset();
1161 mpEMFStream
= std::make_unique
<SvMemoryStream
>(mnEMFSize
, 0);
1163 else if( (mnEMFRecCount
!= nComRecCount
) || (mnEMFSize
!= nEMFTotalSize
) ) // add additional checks here
1165 // total records should be the same as in previous comments
1166 mnEMFRecCount
= 0xFFFFFFFF;
1167 mpEMFStream
.reset();
1171 if (mpEMFStream
&& nCurRecSize
+ 34 > nLen
)
1173 mnEMFRecCount
= 0xFFFFFFFF;
1174 mpEMFStream
.reset();
1177 if (mpEMFStream
&& nCurRecSize
> mpInputStream
->remainingSize())
1179 SAL_WARN("vcl.wmf", "emf record size claims to be larger than remaining data");
1180 mnEMFRecCount
= 0xFFFFFFFF;
1181 mpEMFStream
.reset();
1186 std::vector
<sal_Int8
> aBuf(nCurRecSize
);
1187 sal_uInt32 nCount
= mpInputStream
->ReadBytes(aBuf
.data(), nCurRecSize
);
1188 if( nCount
== nCurRecSize
)
1189 mpEMFStream
->WriteBytes(aBuf
.data(), nCount
);
1198 case W_META_SETRELABS
:
1199 case W_META_SETPOLYFILLMODE
:
1200 case W_META_SETSTRETCHBLTMODE
:
1201 case W_META_SETTEXTCHAREXTRA
:
1202 case W_META_SETTEXTJUSTIFICATION
:
1203 case W_META_FLOODFILL
:
1204 case W_META_FILLREGION
:
1205 case W_META_FRAMEREGION
:
1206 case W_META_INVERTREGION
:
1207 case W_META_PAINTREGION
:
1208 case W_META_DRAWTEXT
:
1209 case W_META_SETMAPPERFLAGS
:
1210 case W_META_SETDIBTODEV
:
1211 case W_META_SELECTPALETTE
:
1212 case W_META_REALIZEPALETTE
:
1213 case W_META_ANIMATEPALETTE
:
1214 case W_META_SETPALENTRIES
:
1215 case W_META_RESIZEPALETTE
:
1216 case W_META_EXTFLOODFILL
:
1217 case W_META_RESETDC
:
1218 case W_META_STARTDOC
:
1219 case W_META_STARTPAGE
:
1220 case W_META_ENDPAGE
:
1221 case W_META_ABORTDOC
:
1227 static const long aMaxWidth
= 1024;
1229 bool WmfReader::ReadHeader()
1231 sal_uInt64
const nStrmPos
= mpInputStream
->Tell();
1233 sal_uInt32
nPlaceableMetaKey(0);
1234 // if available read the METAFILEHEADER
1235 mpInputStream
->ReadUInt32( nPlaceableMetaKey
);
1236 if (!mpInputStream
->good())
1239 tools::Rectangle aPlaceableBound
;
1241 bool bPlaceable
= nPlaceableMetaKey
== 0x9ac6cdd7L
;
1243 SAL_INFO("vcl.wmf", "Placeable: \"" << (bPlaceable
? "yes" : "no") << "\"");
1247 //TODO do some real error handling here
1250 // Skip reserved bytes
1251 mpInputStream
->SeekRel(2);
1254 mpInputStream
->ReadInt16( nVal
);
1255 aPlaceableBound
.SetLeft( nVal
);
1256 mpInputStream
->ReadInt16( nVal
);
1257 aPlaceableBound
.SetTop( nVal
);
1258 mpInputStream
->ReadInt16( nVal
);
1259 aPlaceableBound
.SetRight( nVal
);
1260 mpInputStream
->ReadInt16( nVal
);
1261 aPlaceableBound
.SetBottom( nVal
);
1264 mpInputStream
->ReadUInt16( mnUnitsPerInch
);
1267 mpInputStream
->SeekRel( 4 );
1269 // Skip and don't check the checksum
1270 mpInputStream
->SeekRel( 2 );
1274 mnUnitsPerInch
= 96;
1276 if (mpExternalHeader
!= nullptr
1277 && mpExternalHeader
->xExt
> 0
1278 && mpExternalHeader
->yExt
> 0
1279 && (mpExternalHeader
->mapMode
== MM_ISOTROPIC
|| mpExternalHeader
->mapMode
== MM_ANISOTROPIC
))
1281 // #n417818#: If we have an external header then overwrite the bounds!
1282 tools::Rectangle
aExtRect(0, 0,
1283 static_cast<double>(mpExternalHeader
->xExt
) * 567 * mnUnitsPerInch
/ 1440000,
1284 static_cast<double>(mpExternalHeader
->yExt
) * 567 * mnUnitsPerInch
/ 1440000);
1285 aPlaceableBound
= aExtRect
;
1287 SAL_INFO("vcl.wmf", "External header size "
1288 " t: " << aPlaceableBound
.Left() << " l: " << aPlaceableBound
.Top()
1289 << " b: " << aPlaceableBound
.Right() << " r: " << aPlaceableBound
.Bottom());
1291 SetMapMode(mpExternalHeader
->mapMode
);
1295 mpInputStream
->Seek(nStrmPos
+ 18); // set the streampos to the start of the metaactions
1296 GetPlaceableBound(aPlaceableBound
, mpInputStream
);
1298 // The image size is not known so normalize the calculated bounds so that the
1299 // resulting image is not too big
1300 const double fMaxWidth
= static_cast<double>(aMaxWidth
);
1301 if (aPlaceableBound
.GetWidth() > aMaxWidth
)
1303 double fRatio
= aPlaceableBound
.GetWidth() / fMaxWidth
;
1305 aPlaceableBound
= tools::Rectangle(
1306 aPlaceableBound
.Left() / fRatio
,
1307 aPlaceableBound
.Top() / fRatio
,
1308 aPlaceableBound
.Right() / fRatio
,
1309 aPlaceableBound
.Bottom() / fRatio
);
1311 SAL_INFO("vcl.wmf", "Placeable bounds "
1312 " t: " << aPlaceableBound
.Left() << " l: " << aPlaceableBound
.Top()
1313 << " b: " << aPlaceableBound
.Right() << " r: " << aPlaceableBound
.Bottom());
1317 mpInputStream
->Seek( nStrmPos
);
1320 SetWinOrg( aPlaceableBound
.TopLeft() );
1321 Size
aWMFSize( labs( aPlaceableBound
.GetWidth() ), labs( aPlaceableBound
.GetHeight() ) );
1322 SetWinExt( aWMFSize
);
1324 SAL_INFO("vcl.wmf", "WMF size w: " << aWMFSize
.Width() << " h: " << aWMFSize
.Height());
1326 Size
aDevExt( 10000, 10000 );
1327 if( ( labs( aWMFSize
.Width() ) > 1 ) && ( labs( aWMFSize
.Height() ) > 1 ) )
1329 const Fraction
aFrac( 1, mnUnitsPerInch
);
1330 MapMode
aWMFMap( MapUnit::MapInch
, Point(), aFrac
, aFrac
);
1331 Size
aSize100(OutputDevice::LogicToLogic(aWMFSize
, aWMFMap
, MapMode(MapUnit::Map100thMM
)));
1332 aDevExt
= Size( labs( aSize100
.Width() ), labs( aSize100
.Height() ) );
1334 SetDevExt( aDevExt
);
1336 SAL_INFO("vcl.wmf", "Dev size w: " << aDevExt
.Width() << " h: " << aDevExt
.Height());
1338 // read the METAHEADER
1339 sal_uInt32
nMetaKey(0);
1340 mpInputStream
->ReadUInt32( nMetaKey
); // type and headersize
1341 if (!mpInputStream
->good())
1343 if (nMetaKey
!= 0x00090001)
1345 sal_uInt16
aNextWord(0);
1346 mpInputStream
->ReadUInt16( aNextWord
);
1347 if (nMetaKey
!= 0x10000 || aNextWord
!= 0x09)
1349 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1354 mpInputStream
->SeekRel( 2 ); // Version (of Windows)
1355 mpInputStream
->SeekRel( 4 ); // Size (of file in words)
1356 mpInputStream
->SeekRel( 2 ); // NoObjects (maximum number of simultaneous objects)
1357 mpInputStream
->SeekRel( 4 ); // MaxRecord (size of largest record in words)
1358 mpInputStream
->SeekRel( 2 ); // NoParameters (Unused
1360 return mpInputStream
->good();
1363 void WmfReader::ReadWMF()
1365 sal_uInt16 nFunction
;
1369 mpEMFStream
.reset();
1374 SetMapMode( MM_ANISOTROPIC
);
1375 SetWinOrg( Point() );
1376 SetWinExt( Size( 1, 1 ) );
1377 SetDevExt( Size( 10000, 10000 ) );
1379 mnEndPos
=mpInputStream
->TellEnd();
1380 mpInputStream
->Seek( mnStartPos
);
1382 if ( ReadHeader( ) )
1384 auto nPos
= mpInputStream
->Tell();
1386 if( mnEndPos
- mnStartPos
)
1388 bool bEMFAvailable
= false;
1391 mpInputStream
->ReadUInt32(mnRecSize
).ReadUInt16( nFunction
);
1394 !mpInputStream
->good() ||
1396 (mnRecSize
== 3 && nFunction
== 0)
1399 if( mpInputStream
->eof() )
1400 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1405 const sal_uInt32 nAvailableBytes
= mnEndPos
- nPos
;
1406 const sal_uInt32 nMaxPossibleRecordSize
= nAvailableBytes
/2;
1407 if (mnRecSize
> nMaxPossibleRecordSize
)
1409 mpInputStream
->SetError(SVSTREAM_FILEFORMAT_ERROR
);
1413 if ( !bEMFAvailable
)
1415 if( !maBmpSaveList
.empty()
1416 && ( nFunction
!= W_META_STRETCHDIB
)
1417 && ( nFunction
!= W_META_DIBBITBLT
)
1418 && ( nFunction
!= W_META_DIBSTRETCHBLT
)
1421 ResolveBitmapActions( maBmpSaveList
);
1424 if ( !mnSkipActions
)
1425 ReadRecordParams( nFunction
);
1429 if(mpEMFStream
&& mnEMFRecCount
== mnEMFRec
)
1432 mpEMFStream
->Seek( 0 );
1433 std::unique_ptr
<EmfReader
> pEMFReader(std::make_unique
<EmfReader
>( *mpEMFStream
, aMeta
));
1434 bEMFAvailable
= pEMFReader
->ReadEnhWMF();
1435 pEMFReader
.reset(); // destroy first!!!
1439 AddFromGDIMetaFile( aMeta
);
1440 SetrclFrame( tools::Rectangle( Point(0, 0), aMeta
.GetPrefSize()));
1442 // the stream needs to be set to the wmf end position,
1443 // otherwise the GfxLink that is created will be incorrect
1444 // (leading to graphic loss after swapout/swapin).
1445 // so we will proceed normally, but are ignoring further wmf
1450 // something went wrong
1451 // continue with WMF, don't try this again
1452 mpEMFStream
.reset();
1457 nPos
+= mnRecSize
* 2;
1458 mpInputStream
->Seek(nPos
);
1462 mpInputStream
->SetError( SVSTREAM_GENERALERROR
);
1464 if( !mpInputStream
->GetError() && !maBmpSaveList
.empty() )
1465 ResolveBitmapActions( maBmpSaveList
);
1467 if ( mpInputStream
->GetError() )
1468 mpInputStream
->Seek( mnStartPos
);
1471 void WmfReader::GetPlaceableBound( tools::Rectangle
& rPlaceableBound
, SvStream
* pStm
)
1475 tools::Rectangle aBound
;
1476 aBound
.SetLeft( RECT_MAX
);
1477 aBound
.SetTop( RECT_MAX
);
1478 aBound
.SetRight( RECT_MIN
);
1479 aBound
.SetBottom( RECT_MIN
);
1480 bool bBoundsDetermined
= false;
1482 auto nPos
= pStm
->Tell();
1483 auto nEnd
= nPos
+ pStm
->remainingSize();
1486 boost::optional
<Size
> aWinExt
;
1488 Point
aViewportOrg(0,0);
1489 boost::optional
<Size
> aViewportExt
;
1493 sal_Int16 nMapMode
= MM_ANISOTROPIC
;
1494 sal_uInt16 nFunction
;
1499 pStm
->ReadUInt32( nRSize
).ReadUInt16( nFunction
);
1501 if( pStm
->GetError() )
1506 else if ( nRSize
==3 && nFunction
==0 )
1510 else if ( nRSize
< 3 || pStm
->eof() )
1512 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1518 case W_META_SETWINDOWORG
:
1524 case W_META_SETWINDOWEXT
:
1526 sal_Int16
nWidth(0), nHeight(0);
1527 pStm
->ReadInt16(nHeight
);
1528 pStm
->ReadInt16(nWidth
);
1529 aWinExt
= Size(nWidth
, nHeight
);
1533 case W_META_SETVIEWPORTORG
:
1535 aViewportOrg
= ReadYX();
1539 case W_META_SETVIEWPORTEXT
:
1541 sal_Int16
nWidth(0), nHeight(0);
1542 pStm
->ReadInt16(nHeight
);
1543 pStm
->ReadInt16(nWidth
);
1544 aViewportExt
= Size(nWidth
, nHeight
);
1548 case W_META_SETMAPMODE
:
1549 pStm
->ReadInt16( nMapMode
);
1554 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1555 bBoundsDetermined
= true;
1558 case W_META_RECTANGLE
:
1559 case W_META_INTERSECTCLIPRECT
:
1560 case W_META_EXCLUDECLIPRECT
:
1561 case W_META_ELLIPSE
:
1562 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1563 bBoundsDetermined
= true;
1566 case W_META_ROUNDRECT
:
1567 ReadYXExt(); // size
1568 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1569 bBoundsDetermined
= true;
1577 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1578 bBoundsDetermined
= true;
1581 case W_META_POLYGON
:
1583 bool bRecordOk
= true;
1585 sal_uInt16
nPoints(0);
1586 pStm
->ReadUInt16( nPoints
);
1588 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1594 for(sal_uInt16 i
= 0; i
< nPoints
; i
++ )
1596 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1597 bBoundsDetermined
= true;
1601 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polyline record claimed more points than the stream can provide");
1605 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1612 case W_META_POLYPOLYGON
:
1614 bool bRecordOk
= true;
1615 sal_uInt16
nPoly(0), nPoints(0);
1616 pStm
->ReadUInt16(nPoly
);
1617 if (nPoly
> pStm
->remainingSize() / sizeof(sal_uInt16
))
1623 for(sal_uInt16 i
= 0; i
< nPoly
; i
++ )
1626 pStm
->ReadUInt16( nP
);
1627 if (nP
> SAL_MAX_UINT16
- nPoints
)
1636 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polypolygon record has more polygons than we can handle");
1638 bRecordOk
= bRecordOk
&& pStm
->good();
1642 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1647 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1653 for (sal_uInt16 i
= 0; i
< nPoints
; i
++ )
1655 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1656 bBoundsDetermined
= true;
1660 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polypolygon record claimed more points than the stream can provide");
1662 bRecordOk
&= pStm
->good();
1666 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1673 case W_META_POLYLINE
:
1675 bool bRecordOk
= true;
1677 sal_uInt16
nPoints(0);
1678 pStm
->ReadUInt16(nPoints
);
1679 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1685 for (sal_uInt16 i
= 0; i
< nPoints
; ++i
)
1687 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1688 bBoundsDetermined
= true;
1692 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polyline record claimed more points than the stream can provide");
1696 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1703 case W_META_SETPIXEL
:
1706 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1707 bBoundsDetermined
= true;
1711 case W_META_TEXTOUT
:
1714 pStm
->ReadUInt16( nLength
);
1715 // todo: we also have to take care of the text width
1718 pStm
->SeekRel( ( nLength
+ 1 ) &~ 1 );
1719 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1720 bBoundsDetermined
= true;
1725 case W_META_EXTTEXTOUT
:
1727 sal_uInt16 nLen
, nOptions
;
1728 Point aPosition
= ReadYX();
1729 pStm
->ReadUInt16( nLen
).ReadUInt16( nOptions
);
1730 // todo: we also have to take care of the text width
1733 GetWinExtMax( aPosition
, aBound
, nMapMode
);
1734 bBoundsDetermined
= true;
1739 case W_META_STRETCHBLT
:
1740 case W_META_DIBBITBLT
:
1741 case W_META_DIBSTRETCHBLT
:
1742 case W_META_STRETCHDIB
:
1745 sal_uInt16 nSx
, nSy
, nUsage
;
1746 pStm
->ReadInt32( nWinROP
);
1748 if( nFunction
== W_META_STRETCHDIB
)
1749 pStm
->ReadUInt16( nUsage
);
1751 // nSye and nSxe is the number of pixels that has to been used
1752 if( nFunction
== W_META_STRETCHDIB
|| nFunction
== W_META_STRETCHBLT
|| nFunction
== W_META_DIBSTRETCHBLT
)
1754 sal_uInt16 nSxe
, nSye
;
1755 pStm
->ReadUInt16( nSye
).ReadUInt16( nSxe
);
1758 // nSy and nx is the offset of the first pixel
1759 pStm
->ReadUInt16( nSy
).ReadUInt16( nSx
);
1761 if( nFunction
== W_META_STRETCHDIB
|| nFunction
== W_META_DIBBITBLT
|| nFunction
== W_META_DIBSTRETCHBLT
)
1763 if ( nWinROP
== PATCOPY
)
1764 pStm
->ReadUInt16( nUsage
); // i don't know anything of this parameter, so its called nUsage
1765 // DrawRect( Rectangle( ReadYX(), aDestSize ), false );
1767 Size
aDestSize( ReadYXExt() );
1768 if ( aDestSize
.Width() && aDestSize
.Height() ) // #92623# do not try to read buggy bitmaps
1770 tools::Rectangle
aDestRect( ReadYX(), aDestSize
);
1771 GetWinExtMax( aDestRect
, aBound
, nMapMode
);
1772 bBoundsDetermined
= true;
1781 pStm
->ReadUInt32( nROP
);
1782 Size aSize
= ReadYXExt();
1783 GetWinExtMax( tools::Rectangle( ReadYX(), aSize
), aBound
, nMapMode
);
1784 bBoundsDetermined
= true;
1789 const auto nAvailableBytes
= nEnd
- nPos
;
1790 const auto nMaxPossibleRecordSize
= nAvailableBytes
/2;
1791 if (nRSize
<= nMaxPossibleRecordSize
)
1798 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1805 pStm
->SetError( SVSTREAM_GENERALERROR
);
1813 rPlaceableBound
= tools::Rectangle(aWinOrg
, *aWinExt
);
1814 SAL_INFO("vcl.wmf", "Window dimension "
1815 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1816 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1818 else if (aViewportExt
)
1820 rPlaceableBound
= tools::Rectangle(aViewportOrg
, *aViewportExt
);
1821 SAL_INFO("vcl.wmf", "Viewport dimension "
1822 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1823 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1825 else if (bBoundsDetermined
)
1827 rPlaceableBound
= aBound
;
1828 SAL_INFO("vcl.wmf", "Determined dimension "
1829 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1830 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1834 rPlaceableBound
.SetLeft( 0 );
1835 rPlaceableBound
.SetTop( 0 );
1836 rPlaceableBound
.SetRight( aMaxWidth
);
1837 rPlaceableBound
.SetBottom( aMaxWidth
);
1838 SAL_INFO("vcl.wmf", "Default dimension "
1839 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1840 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1845 WmfReader::WmfReader(SvStream
& rStreamWMF
, GDIMetaFile
& rGDIMetaFile
, const WmfExternal
* pExternalHeader
)
1846 : MtfTools(rGDIMetaFile
, rStreamWMF
)
1847 , mnUnitsPerInch(96)
1854 , mpExternalHeader(pExternalHeader
)
1859 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */