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 <osl/endian.h>
28 #include <vcl/gdimtf.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/dibtools.hxx>
31 #include <vcl/wmfexternal.hxx>
32 #include <tools/fract.hxx>
33 #include <o3tl/make_unique.hxx>
34 #include <vcl/bitmapaccess.hxx>
35 #include <vcl/BitmapTools.hxx>
36 #include <osl/thread.h>
39 #define W_META_SETBKCOLOR 0x0201
40 #define W_META_SETBKMODE 0x0102
41 #define W_META_SETMAPMODE 0x0103
42 #define W_META_SETROP2 0x0104
43 #define W_META_SETRELABS 0x0105
44 #define W_META_SETPOLYFILLMODE 0x0106
45 #define W_META_SETSTRETCHBLTMODE 0x0107
46 #define W_META_SETTEXTCHAREXTRA 0x0108
47 #define W_META_SETTEXTCOLOR 0x0209
48 #define W_META_SETTEXTJUSTIFICATION 0x020A
49 #define W_META_SETWINDOWORG 0x020B
50 #define W_META_SETWINDOWEXT 0x020C
51 #define W_META_SETVIEWPORTORG 0x020D
52 #define W_META_SETVIEWPORTEXT 0x020E
53 #define W_META_OFFSETWINDOWORG 0x020F
54 #define W_META_SCALEWINDOWEXT 0x0410
55 #define W_META_OFFSETVIEWPORTORG 0x0211
56 #define W_META_SCALEVIEWPORTEXT 0x0412
57 #define W_META_LINETO 0x0213
58 #define W_META_MOVETO 0x0214
59 #define W_META_EXCLUDECLIPRECT 0x0415
60 #define W_META_INTERSECTCLIPRECT 0x0416
61 #define W_META_ARC 0x0817
62 #define W_META_ELLIPSE 0x0418
63 #define W_META_FLOODFILL 0x0419
64 #define W_META_PIE 0x081A
65 #define W_META_RECTANGLE 0x041B
66 #define W_META_ROUNDRECT 0x061C
67 #define W_META_PATBLT 0x061D
68 #define W_META_SAVEDC 0x001E
69 #define W_META_SETPIXEL 0x041F
70 #define W_META_OFFSETCLIPRGN 0x0220
71 #define W_META_TEXTOUT 0x0521
72 #define W_META_BITBLT 0x0922
73 #define W_META_STRETCHBLT 0x0B23
74 #define W_META_POLYGON 0x0324
75 #define W_META_POLYLINE 0x0325
76 #define W_META_ESCAPE 0x0626
77 #define W_META_RESTOREDC 0x0127
78 #define W_META_FILLREGION 0x0228
79 #define W_META_FRAMEREGION 0x0429
80 #define W_META_INVERTREGION 0x012A
81 #define W_META_PAINTREGION 0x012B
82 #define W_META_SELECTCLIPREGION 0x012C
83 #define W_META_SELECTOBJECT 0x012D
84 #define W_META_SETTEXTALIGN 0x012E
85 #define W_META_DRAWTEXT 0x062F
86 #define W_META_CHORD 0x0830
87 #define W_META_SETMAPPERFLAGS 0x0231
88 #define W_META_EXTTEXTOUT 0x0a32
89 #define W_META_SETDIBTODEV 0x0d33
90 #define W_META_SELECTPALETTE 0x0234
91 #define W_META_REALIZEPALETTE 0x0035
92 #define W_META_ANIMATEPALETTE 0x0436
93 #define W_META_SETPALENTRIES 0x0037
94 #define W_META_POLYPOLYGON 0x0538
95 #define W_META_RESIZEPALETTE 0x0139
96 #define W_META_DIBBITBLT 0x0940
97 #define W_META_DIBSTRETCHBLT 0x0b41
98 #define W_META_DIBCREATEPATTERNBRUSH 0x0142
99 #define W_META_STRETCHDIB 0x0f43
100 #define W_META_EXTFLOODFILL 0x0548
101 #define W_META_RESETDC 0x014C
102 #define W_META_STARTDOC 0x014D
103 #define W_META_STARTPAGE 0x004F
104 #define W_META_ENDPAGE 0x0050
105 #define W_META_ABORTDOC 0x0052
106 #define W_META_ENDDOC 0x005E
107 #define W_META_DELETEOBJECT 0x01f0
108 #define W_META_CREATEPALETTE 0x00f7
109 #define W_META_CREATEBRUSH 0x00F8
110 #define W_META_CREATEPATTERNBRUSH 0x01F9
111 #define W_META_CREATEPENINDIRECT 0x02FA
112 #define W_META_CREATEFONTINDIRECT 0x02FB
113 #define W_META_CREATEBRUSHINDIRECT 0x02FC
114 #define W_META_CREATEBITMAPINDIRECT 0x02FD
115 #define W_META_CREATEBITMAP 0x06FE
116 #define W_META_CREATEREGION 0x06FF
120 void GetWinExtMax(const Point
& rSource
, tools::Rectangle
& rPlaceableBound
, const sal_Int16 nMapMode
)
122 Point
aSource(rSource
);
123 if (nMapMode
== MM_HIMETRIC
)
124 aSource
.setY( -rSource
.Y() );
125 if (aSource
.X() < rPlaceableBound
.Left())
126 rPlaceableBound
.SetLeft( aSource
.X() );
127 if (aSource
.X() > rPlaceableBound
.Right())
128 rPlaceableBound
.SetRight( aSource
.X() );
129 if (aSource
.Y() < rPlaceableBound
.Top())
130 rPlaceableBound
.SetTop( aSource
.Y() );
131 if (aSource
.Y() > rPlaceableBound
.Bottom())
132 rPlaceableBound
.SetBottom( aSource
.Y() );
135 void GetWinExtMax(const tools::Rectangle
& rSource
, tools::Rectangle
& rPlaceableBound
, const sal_Int16 nMapMode
)
137 GetWinExtMax(rSource
.TopLeft(), rPlaceableBound
, nMapMode
);
138 GetWinExtMax(rSource
.BottomRight(), rPlaceableBound
, nMapMode
);
145 inline Point
WmfReader::ReadPoint()
147 short nX
= 0, nY
= 0;
148 mpInputStream
->ReadInt16( nX
).ReadInt16( nY
);
149 return Point( nX
, nY
);
152 inline Point
WmfReader::ReadYX()
154 short nX
= 0, nY
= 0;
155 mpInputStream
->ReadInt16( nY
).ReadInt16( nX
);
156 return Point( nX
, nY
);
159 tools::Rectangle
WmfReader::ReadRectangle()
166 return tools::Rectangle( aTL
, aBR
);
169 Size
WmfReader::ReadYXExt()
172 mpInputStream
->ReadInt16( nH
).ReadInt16( nW
);
173 return Size( nW
, nH
);
176 void WmfReader::ReadRecordParams( sal_uInt16 nFunc
)
180 case W_META_SETBKCOLOR
:
182 SetBkColor( ReadColor() );
186 case W_META_SETBKMODE
:
189 mpInputStream
->ReadUInt16( nDat
);
190 SetBkMode( static_cast<BkMode
>(nDat
) );
195 case W_META_SETMAPMODE
:
197 sal_Int16 nMapMode
= 0;
198 mpInputStream
->ReadInt16( nMapMode
);
199 SetMapMode( nMapMode
);
205 sal_uInt16 nROP2
= 0;
206 mpInputStream
->ReadUInt16( nROP2
);
207 SetRasterOp( static_cast<WMFRasterOp
>(nROP2
) );
211 case W_META_SETTEXTCOLOR
:
213 SetTextColor( ReadColor() );
217 case W_META_SETWINDOWORG
:
219 SetWinOrg( ReadYX() );
223 case W_META_SETWINDOWEXT
:
225 short nWidth
= 0, nHeight
= 0;
226 mpInputStream
->ReadInt16( nHeight
).ReadInt16( nWidth
);
227 SetWinExt( Size( nWidth
, nHeight
) );
231 case W_META_OFFSETWINDOWORG
:
233 short nXAdd
= 0, nYAdd
= 0;
234 mpInputStream
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
235 SetWinOrgOffset( nXAdd
, nYAdd
);
239 case W_META_SCALEWINDOWEXT
:
241 short nXNum
= 0, nXDenom
= 0, nYNum
= 0, nYDenom
= 0;
242 mpInputStream
->ReadInt16( nYDenom
).ReadInt16( nYNum
).ReadInt16( nXDenom
).ReadInt16( nXNum
);
243 if (!nYDenom
|| !nXDenom
)
245 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
248 ScaleWinExt( static_cast<double>(nXNum
) / nXDenom
, static_cast<double>(nYNum
) / nYDenom
);
252 case W_META_SETVIEWPORTORG
:
253 case W_META_SETVIEWPORTEXT
:
256 case W_META_OFFSETVIEWPORTORG
:
258 short nXAdd
= 0, nYAdd
= 0;
259 mpInputStream
->ReadInt16( nYAdd
).ReadInt16( nXAdd
);
260 SetDevOrgOffset( nXAdd
, nYAdd
);
264 case W_META_SCALEVIEWPORTEXT
:
266 short nXNum
= 0, nXDenom
= 0, nYNum
= 0, nYDenom
= 0;
267 mpInputStream
->ReadInt16( nYDenom
).ReadInt16( nYNum
).ReadInt16( nXDenom
).ReadInt16( nXNum
);
268 if (!nYDenom
|| !nXDenom
)
270 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
273 ScaleDevExt( static_cast<double>(nXNum
) / nXDenom
, static_cast<double>(nYNum
) / nYDenom
);
289 case W_META_INTERSECTCLIPRECT
:
291 IntersectClipRect( ReadRectangle() );
295 case W_META_RECTANGLE
:
297 DrawRect( ReadRectangle() );
301 case W_META_ROUNDRECT
:
303 Size
aSize( ReadYXExt() );
304 DrawRoundRect( ReadRectangle(), Size( aSize
.Width() / 2, aSize
.Height() / 2 ) );
310 DrawEllipse( ReadRectangle() );
316 Point
aEnd( ReadYX() );
317 Point
aStart( ReadYX() );
318 tools::Rectangle
aRect( ReadRectangle() );
320 DrawArc( aRect
, aStart
, aEnd
);
326 Point
aEnd( ReadYX() );
327 Point
aStart( ReadYX() );
328 tools::Rectangle
aRect( ReadRectangle() );
331 // #i73608# OutputDevice deviates from WMF
332 // semantics. start==end means full ellipse here.
334 DrawEllipse( aRect
);
336 DrawPie( aRect
, aStart
, aEnd
);
342 Point
aEnd( ReadYX() );
343 Point
aStart( ReadYX() );
344 tools::Rectangle
aRect( ReadRectangle() );
346 DrawChord( aRect
, aStart
, aEnd
);
352 bool bRecordOk
= true;
354 sal_uInt16
nPoints(0);
355 mpInputStream
->ReadUInt16(nPoints
);
357 if (nPoints
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
363 tools::Polygon
aPoly(nPoints
);
364 for (sal_uInt16
i(0); i
< nPoints
&& mpInputStream
->good(); ++i
)
365 aPoly
[ i
] = ReadPoint();
366 DrawPolygon(aPoly
, false/*bRecordPath*/);
369 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polygon record has more points than we can handle");
371 bRecordOk
&= mpInputStream
->good();
375 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
381 case W_META_POLYPOLYGON
:
383 sal_uInt16
nPolyCount(0);
384 // Number of polygons:
385 mpInputStream
->ReadUInt16( nPolyCount
);
386 if (nPolyCount
&& mpInputStream
->good())
388 bool bRecordOk
= true;
389 if (nPolyCount
> mpInputStream
->remainingSize() / sizeof(sal_uInt16
))
394 // Number of points of each polygon. Determine total number of points
395 std::unique_ptr
<sal_uInt16
[]> xPolygonPointCounts(new sal_uInt16
[nPolyCount
]);
396 sal_uInt16
* pnPoints
= xPolygonPointCounts
.get();
397 tools::PolyPolygon
aPolyPoly(nPolyCount
);
398 sal_uInt16 nPoints
= 0;
399 for (sal_uInt16 a
= 0; a
< nPolyCount
&& mpInputStream
->good(); ++a
)
401 mpInputStream
->ReadUInt16( pnPoints
[a
] );
403 if (pnPoints
[a
] > SAL_MAX_UINT16
- nPoints
)
409 nPoints
+= pnPoints
[a
];
412 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polypolygon record has more polygons than we can handle");
414 bRecordOk
&= mpInputStream
->good();
418 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
422 // Polygon points are:
423 for (sal_uInt16 a
= 0; a
< nPolyCount
&& mpInputStream
->good(); ++a
)
425 const sal_uInt16
nPointCount(pnPoints
[a
]);
427 if (nPointCount
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
433 std::unique_ptr
<Point
[]> xPolygonPoints(new Point
[nPointCount
]);
434 Point
* pPtAry
= xPolygonPoints
.get();
436 for(sal_uInt16
b(0); b
< nPointCount
&& mpInputStream
->good(); ++b
)
438 pPtAry
[b
] = ReadPoint();
441 aPolyPoly
.Insert( tools::Polygon(nPointCount
, pPtAry
) );
444 bRecordOk
&= mpInputStream
->good();
448 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
452 DrawPolyPolygon( aPolyPoly
);
457 case W_META_POLYLINE
:
459 bool bRecordOk
= true;
461 sal_uInt16
nPoints(0);
462 mpInputStream
->ReadUInt16(nPoints
);
464 if (nPoints
> mpInputStream
->remainingSize() / (2 * sizeof(sal_uInt16
)))
470 tools::Polygon
aPoly(nPoints
);
471 for (sal_uInt16
i(0); i
< nPoints
&& mpInputStream
->good(); ++i
)
472 aPoly
[ i
] = ReadPoint();
473 DrawPolyLine( aPoly
);
476 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polyline record has more points than we can handle");
478 bRecordOk
&= mpInputStream
->good();
482 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
494 case W_META_RESTOREDC
:
500 case W_META_SETPIXEL
:
502 const Color aColor
= ReadColor();
503 DrawPixel( ReadYX(), aColor
);
507 case W_META_OFFSETCLIPRGN
:
509 MoveClipRegion( ReadYXExt() );
515 //record is Recordsize, RecordFunction, StringLength, <String>, YStart, XStart
516 const sal_uInt32 nNonStringLen
= sizeof(sal_uInt32
) + 4 * sizeof(sal_uInt16
);
517 const sal_uInt32 nRecSize
= mnRecSize
* 2;
519 if (nRecSize
< nNonStringLen
)
521 SAL_WARN("vcl.wmf", "W_META_TEXTOUT too short");
525 sal_uInt16 nLength
= 0;
526 mpInputStream
->ReadUInt16(nLength
);
527 sal_uInt16 nStoredLength
= (nLength
+ 1) &~ 1;
529 if (nRecSize
- nNonStringLen
< nStoredLength
)
531 SAL_WARN("vcl.wmf", "W_META_TEXTOUT too short, truncating string");
532 nLength
= nStoredLength
= nRecSize
- nNonStringLen
;
537 std::vector
<char> aChars(nStoredLength
);
538 nLength
= std::min
<sal_uInt16
>(nLength
, mpInputStream
->ReadBytes(aChars
.data(), aChars
.size()));
539 OUString
aText(aChars
.data(), nLength
, GetCharSet());
540 Point
aPosition( ReadYX() );
541 DrawText( aPosition
, aText
);
546 case W_META_EXTTEXTOUT
:
548 //record is Recordsize, RecordFunction, Y, X, StringLength, options, maybe rectangle, <String>
549 sal_uInt32 nNonStringLen
= sizeof(sal_uInt32
) + 5 * sizeof(sal_uInt16
);
550 const sal_uInt32 nRecSize
= mnRecSize
* 2;
552 if (nRecSize
< nNonStringLen
)
554 SAL_WARN("vcl.wmf", "W_META_EXTTEXTOUT too short");
558 auto nRecordPos
= mpInputStream
->Tell() - 6;
559 Point aPosition
= ReadYX();
560 sal_uInt16 nLen
= 0, nOptions
= 0;
561 mpInputStream
->ReadUInt16( nLen
).ReadUInt16( nOptions
);
563 if (nOptions
& ETO_CLIPPED
)
565 nNonStringLen
+= 2 * sizeof(sal_uInt16
);
567 if (nRecSize
< nNonStringLen
)
569 SAL_WARN("vcl.wmf", "W_META_TEXTOUT too short");
575 SAL_WARN("vcl.wmf", "clipping unsupported");
578 ComplexTextLayoutFlags nTextLayoutMode
= ComplexTextLayoutFlags::Default
;
579 if ( nOptions
& ETO_RTLREADING
)
580 nTextLayoutMode
= ComplexTextLayoutFlags::BiDiRtl
| ComplexTextLayoutFlags::TextOriginLeft
;
581 SetTextLayoutMode( nTextLayoutMode
);
582 SAL_WARN_IF( ( nOptions
& ( ETO_PDY
| ETO_GLYPH_INDEX
) ) != 0, "vcl.wmf", "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" );
584 // output only makes sense if the text contains characters
587 sal_Int32 nOriginalTextLen
= nLen
;
588 sal_Int32 nOriginalBlockLen
= ( nOriginalTextLen
+ 1 ) &~ 1;
590 auto nMaxStreamPos
= nRecordPos
+ nRecSize
;
591 auto nRemainingSize
= std::min(mpInputStream
->remainingSize(), nMaxStreamPos
- mpInputStream
->Tell());
592 if (nRemainingSize
< static_cast<sal_uInt32
>(nOriginalBlockLen
))
594 SAL_WARN("vcl.wmf", "exttextout record claimed more data than the stream can provide");
595 nOriginalTextLen
= nOriginalBlockLen
= nRemainingSize
;
598 std::unique_ptr
<char[]> pChar(new char[nOriginalBlockLen
]);
599 mpInputStream
->ReadBytes(pChar
.get(), nOriginalBlockLen
);
600 OUString
aText(pChar
.get(), nOriginalTextLen
, GetCharSet()); // after this conversion the text may contain
601 sal_Int32 nNewTextLen
= aText
.getLength(); // less character (japanese version), so the
602 // dxAry will not fit
605 std::unique_ptr
<long[]> pDXAry
, pDYAry
;
606 auto nDxArySize
= nMaxStreamPos
- mpInputStream
->Tell();
607 auto nDxAryEntries
= nDxArySize
>> 1;
608 bool bUseDXAry
= false;
610 if ( ( ( nDxAryEntries
% nOriginalTextLen
) == 0 ) && ( nNewTextLen
<= nOriginalTextLen
) )
612 sal_Int32 i
; // needed just outside the for
613 pDXAry
.reset(new long[ nNewTextLen
]);
614 if ( nOptions
& ETO_PDY
)
616 pDYAry
.reset(new long[ nNewTextLen
]);
618 for (i
= 0; i
< nNewTextLen
; i
++ )
620 if ( mpInputStream
->Tell() >= nMaxStreamPos
)
622 sal_Int32 nDxCount
= 1;
623 if ( nNewTextLen
!= nOriginalTextLen
)
625 sal_Unicode cUniChar
= aText
[i
];
626 OString
aTmp(&cUniChar
, 1, GetCharSet());
627 if ( aTmp
.getLength() > 1 )
629 nDxCount
= aTmp
.getLength();
633 sal_Int16 nDx
= 0, nDy
= 0;
636 if ( ( mpInputStream
->Tell() + 2 ) > nMaxStreamPos
)
638 sal_Int16 nDxTmp
= 0;
639 mpInputStream
->ReadInt16(nDxTmp
);
641 if ( nOptions
& ETO_PDY
)
643 if ( ( mpInputStream
->Tell() + 2 ) > nMaxStreamPos
)
645 sal_Int16 nDyTmp
= 0;
646 mpInputStream
->ReadInt16(nDyTmp
);
652 if ( nOptions
& ETO_PDY
)
657 if ( i
== nNewTextLen
)
660 if ( pDXAry
&& bUseDXAry
)
661 DrawText( aPosition
, aText
, pDXAry
.get(), pDYAry
.get() );
663 DrawText( aPosition
, aText
);
669 case W_META_SELECTOBJECT
:
671 sal_Int16 nObjIndex
= 0;
672 mpInputStream
->ReadInt16( nObjIndex
);
673 SelectObject( nObjIndex
);
677 case W_META_SETTEXTALIGN
:
679 sal_uInt16 nAlign
= 0;
680 mpInputStream
->ReadUInt16( nAlign
);
681 SetTextAlign( nAlign
);
687 // 0-3 : nWinROP #93454#
688 // 4-5 : y offset of source bitmap
689 // 6-7 : x offset of source bitmap
690 // 8-9 : used height of source bitmap
691 // 10-11 : used width of source bitmap
692 // 12-13 : destination position y (in pixel)
693 // 14-15 : destination position x (in pixel)
694 // 16-17 : don't know
695 // 18-19 : Width Bitmap in Pixel
696 // 20-21 : Height Bitmap in Pixel
697 // 22-23 : bytes per scanline
701 sal_Int32 nWinROP
= 0;
702 sal_uInt16 nSx
= 0, nSy
= 0, nSxe
= 0, nSye
= 0, nDontKnow
= 0, nWidth
= 0, nHeight
= 0, nBytesPerScan
= 0;
703 sal_uInt8 nPlanes
, nBitCount
;
705 mpInputStream
->ReadInt32( nWinROP
)
706 .ReadUInt16( nSy
).ReadUInt16( nSx
).ReadUInt16( nSye
).ReadUInt16( nSxe
);
707 Point
aPoint( ReadYX() );
708 mpInputStream
->ReadUInt16( nDontKnow
).ReadUInt16( nWidth
).ReadUInt16( nHeight
).ReadUInt16( nBytesPerScan
).ReadUChar( nPlanes
).ReadUChar( nBitCount
);
710 bool bOk
= nWidth
&& nHeight
&& nPlanes
== 1 && nBitCount
== 1 && nBytesPerScan
!= 0;
713 bOk
= nBytesPerScan
<= mpInputStream
->remainingSize() / nHeight
;
717 vcl::bitmap::RawBitmap
aBmp( Size( nWidth
, nHeight
), 24 );
718 for (sal_uInt16 y
= 0; y
< nHeight
&& mpInputStream
->good(); ++y
)
721 for (sal_uInt16 scan
= 0; scan
< nBytesPerScan
; scan
++ )
723 sal_Int8 nEightPixels
= 0;
724 mpInputStream
->ReadSChar( nEightPixels
);
725 for (sal_Int8 i
= 7; i
>= 0; i
-- )
729 aBmp
.SetPixel( y
, x
, ((nEightPixels
>>i
)&1) ? COL_BLACK
: COL_WHITE
);
735 BitmapEx aBitmap
= vcl::bitmap::CreateFromData(std::move(aBmp
));
737 ( nSx
+ nSxe
<= nWidth
) &&
738 ( nSy
+ nSye
<= nHeight
) )
740 tools::Rectangle
aCropRect( Point( nSx
, nSy
), Size( nSxe
, nSye
) );
741 aBitmap
.Crop( aCropRect
);
743 tools::Rectangle
aDestRect( aPoint
, Size( nSxe
, nSye
) );
744 maBmpSaveList
.emplace_back(new BSaveStruct(aBitmap
, aDestRect
, nWinROP
));
749 case W_META_STRETCHBLT
:
750 case W_META_DIBBITBLT
:
751 case W_META_DIBSTRETCHBLT
:
752 case W_META_STRETCHDIB
:
754 sal_Int32 nWinROP
= 0;
755 sal_uInt16 nSx
= 0, nSy
= 0, nSxe
= 0, nSye
= 0, nUsage
= 0;
758 mpInputStream
->ReadInt32( nWinROP
);
760 if( nFunc
== W_META_STRETCHDIB
)
761 mpInputStream
->ReadUInt16( nUsage
);
763 // nSye and nSxe is the number of pixels that has to been used
764 // If they are set to zero, it is as indicator not to scale the bitmap later
766 if( nFunc
== W_META_STRETCHDIB
|| nFunc
== W_META_STRETCHBLT
|| nFunc
== W_META_DIBSTRETCHBLT
)
767 mpInputStream
->ReadUInt16( nSye
).ReadUInt16( nSxe
);
769 // nSy and nx is the offset of the first pixel
770 mpInputStream
->ReadUInt16( nSy
).ReadUInt16( nSx
);
772 if( nFunc
== W_META_STRETCHDIB
|| nFunc
== W_META_DIBBITBLT
|| nFunc
== W_META_DIBSTRETCHBLT
)
774 if ( nWinROP
== PATCOPY
)
775 mpInputStream
->ReadUInt16( nUsage
); // i don't know anything of this parameter, so its called nUsage
776 // DrawRect( Rectangle( ReadYX(), aDestSize ), false );
778 Size
aDestSize( ReadYXExt() );
779 if ( aDestSize
.Width() && aDestSize
.Height() ) // #92623# do not try to read buggy bitmaps
781 tools::Rectangle
aDestRect( ReadYX(), aDestSize
);
782 if ( nWinROP
!= PATCOPY
)
783 ReadDIB(aBmp
, *mpInputStream
, false);
785 // test if it is sensible to crop
787 ( nSx
+ nSxe
<= aBmp
.GetSizePixel().Width() ) &&
788 ( nSy
+ nSye
<= aBmp
.GetSizePixel().Height() ) )
790 tools::Rectangle
aCropRect( Point( nSx
, nSy
), Size( nSxe
, nSye
) );
791 aBmp
.Crop( aCropRect
);
793 maBmpSaveList
.emplace_back(new BSaveStruct(aBmp
, aDestRect
, nWinROP
));
799 case W_META_DIBCREATEPATTERNBRUSH
:
802 sal_uInt32 nRed
= 0, nGreen
= 0, nBlue
= 0, nCount
= 1;
803 sal_uInt16 nFunction
= 0;
805 mpInputStream
->ReadUInt16( nFunction
).ReadUInt16( nFunction
);
807 ReadDIB(aBmp
, *mpInputStream
, false);
808 Bitmap::ScopedReadAccess
pBmp(aBmp
);
811 for ( long y
= 0; y
< pBmp
->Height(); y
++ )
813 for ( long x
= 0; x
< pBmp
->Width(); x
++ )
815 const BitmapColor
aColor( pBmp
->GetColor( y
, x
) );
817 nRed
+= aColor
.GetRed();
818 nGreen
+= aColor
.GetGreen();
819 nBlue
+= aColor
.GetBlue();
822 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(o3tl::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(o3tl::make_unique
<WinMtfFillStyle
>( COL_WHITE
, false ));
852 case W_META_CREATEPATTERNBRUSH
:
854 CreateObject(o3tl::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(o3tl::make_unique
<WinMtfLineStyle
>( ReadColor(), aLineInfo
, bTransparent
));
935 case W_META_CREATEBRUSHINDIRECT
:
937 sal_uInt16 nStyle
= 0;
938 mpInputStream
->ReadUInt16( nStyle
);
939 CreateObject(o3tl::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(o3tl::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
= o3tl::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
;
1368 mnCurrentAction
= 0;
1370 mpEMFStream
.reset();
1375 SetMapMode( MM_ANISOTROPIC
);
1376 SetWinOrg( Point() );
1377 SetWinExt( Size( 1, 1 ) );
1378 SetDevExt( Size( 10000, 10000 ) );
1380 mnEndPos
=mpInputStream
->Seek( STREAM_SEEK_TO_END
);
1381 mpInputStream
->Seek( mnStartPos
);
1383 if ( ReadHeader( ) )
1385 auto nPos
= mpInputStream
->Tell();
1387 if( mnEndPos
- mnStartPos
)
1389 bool bEMFAvailable
= false;
1393 mpInputStream
->ReadUInt32(mnRecSize
).ReadUInt16( nFunction
);
1396 !mpInputStream
->good() ||
1398 (mnRecSize
== 3 && nFunction
== 0)
1401 if( mpInputStream
->eof() )
1402 mpInputStream
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1407 const sal_uInt32 nAvailableBytes
= mnEndPos
- nPos
;
1408 const sal_uInt32 nMaxPossibleRecordSize
= nAvailableBytes
/2;
1409 if (mnRecSize
> nMaxPossibleRecordSize
)
1411 mpInputStream
->SetError(SVSTREAM_FILEFORMAT_ERROR
);
1415 if ( !bEMFAvailable
)
1417 if( !maBmpSaveList
.empty()
1418 && ( nFunction
!= W_META_STRETCHDIB
)
1419 && ( nFunction
!= W_META_DIBBITBLT
)
1420 && ( nFunction
!= W_META_DIBSTRETCHBLT
)
1423 ResolveBitmapActions( maBmpSaveList
);
1426 if ( !mnSkipActions
)
1427 ReadRecordParams( nFunction
);
1431 if(mpEMFStream
&& mnEMFRecCount
== mnEMFRec
)
1434 mpEMFStream
->Seek( 0 );
1435 std::unique_ptr
<EmfReader
> pEMFReader(o3tl::make_unique
<EmfReader
>( *mpEMFStream
, aMeta
));
1436 bEMFAvailable
= pEMFReader
->ReadEnhWMF();
1437 pEMFReader
.reset(); // destroy first!!!
1441 AddFromGDIMetaFile( aMeta
);
1442 SetrclFrame( tools::Rectangle( Point(0, 0), aMeta
.GetPrefSize()));
1444 // the stream needs to be set to the wmf end position,
1445 // otherwise the GfxLink that is created will be incorrect
1446 // (leading to graphic loss after swapout/swapin).
1447 // so we will proceed normally, but are ignoring further wmf
1452 // something went wrong
1453 // continue with WMF, don't try this again
1454 mpEMFStream
.reset();
1459 nPos
+= mnRecSize
* 2;
1460 mpInputStream
->Seek(nPos
);
1464 mpInputStream
->SetError( SVSTREAM_GENERALERROR
);
1466 if( !mpInputStream
->GetError() && !maBmpSaveList
.empty() )
1467 ResolveBitmapActions( maBmpSaveList
);
1469 if ( mpInputStream
->GetError() )
1470 mpInputStream
->Seek( mnStartPos
);
1473 void WmfReader::GetPlaceableBound( tools::Rectangle
& rPlaceableBound
, SvStream
* pStm
)
1477 tools::Rectangle aBound
;
1478 aBound
.SetLeft( RECT_MAX
);
1479 aBound
.SetTop( RECT_MAX
);
1480 aBound
.SetRight( RECT_MIN
);
1481 aBound
.SetBottom( RECT_MIN
);
1482 bool bBoundsDetermined
= false;
1484 auto nPos
= pStm
->Tell();
1485 auto nEnd
= nPos
+ pStm
->remainingSize();
1488 boost::optional
<Size
> aWinExt
;
1490 Point
aViewportOrg(0,0);
1491 boost::optional
<Size
> aViewportExt
;
1495 sal_Int16 nMapMode
= MM_ANISOTROPIC
;
1496 sal_uInt16 nFunction
;
1501 pStm
->ReadUInt32( nRSize
).ReadUInt16( nFunction
);
1503 if( pStm
->GetError() )
1508 else if ( nRSize
==3 && nFunction
==0 )
1512 else if ( nRSize
< 3 || pStm
->eof() )
1514 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1520 case W_META_SETWINDOWORG
:
1526 case W_META_SETWINDOWEXT
:
1528 sal_Int16
nWidth(0), nHeight(0);
1529 pStm
->ReadInt16(nHeight
);
1530 pStm
->ReadInt16(nWidth
);
1531 aWinExt
= Size(nWidth
, nHeight
);
1535 case W_META_SETVIEWPORTORG
:
1537 aViewportOrg
= ReadYX();
1541 case W_META_SETVIEWPORTEXT
:
1543 sal_Int16
nWidth(0), nHeight(0);
1544 pStm
->ReadInt16(nHeight
);
1545 pStm
->ReadInt16(nWidth
);
1546 aViewportExt
= Size(nWidth
, nHeight
);
1550 case W_META_SETMAPMODE
:
1551 pStm
->ReadInt16( nMapMode
);
1556 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1557 bBoundsDetermined
= true;
1560 case W_META_RECTANGLE
:
1561 case W_META_INTERSECTCLIPRECT
:
1562 case W_META_EXCLUDECLIPRECT
:
1563 case W_META_ELLIPSE
:
1564 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1565 bBoundsDetermined
= true;
1568 case W_META_ROUNDRECT
:
1569 ReadYXExt(); // size
1570 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1571 bBoundsDetermined
= true;
1579 GetWinExtMax( ReadRectangle(), aBound
, nMapMode
);
1580 bBoundsDetermined
= true;
1583 case W_META_POLYGON
:
1585 bool bRecordOk
= true;
1587 sal_uInt16
nPoints(0);
1588 pStm
->ReadUInt16( nPoints
);
1590 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1596 for(sal_uInt16 i
= 0; i
< nPoints
; i
++ )
1598 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1599 bBoundsDetermined
= true;
1603 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polyline record claimed more points than the stream can provide");
1607 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1614 case W_META_POLYPOLYGON
:
1616 bool bRecordOk
= true;
1617 sal_uInt16
nPoly(0), nPoints(0);
1618 pStm
->ReadUInt16(nPoly
);
1619 if (nPoly
> pStm
->remainingSize() / sizeof(sal_uInt16
))
1625 for(sal_uInt16 i
= 0; i
< nPoly
; i
++ )
1628 pStm
->ReadUInt16( nP
);
1629 if (nP
> SAL_MAX_UINT16
- nPoints
)
1638 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polypolygon record has more polygons than we can handle");
1640 bRecordOk
= bRecordOk
&& pStm
->good();
1644 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1649 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1655 for (sal_uInt16 i
= 0; i
< nPoints
; i
++ )
1657 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1658 bBoundsDetermined
= true;
1662 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polypolygon record claimed more points than the stream can provide");
1664 bRecordOk
&= pStm
->good();
1668 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1675 case W_META_POLYLINE
:
1677 bool bRecordOk
= true;
1679 sal_uInt16
nPoints(0);
1680 pStm
->ReadUInt16(nPoints
);
1681 if (nPoints
> pStm
->remainingSize() / (2 * sizeof(sal_uInt16
)))
1687 for (sal_uInt16 i
= 0; i
< nPoints
; ++i
)
1689 GetWinExtMax( ReadPoint(), aBound
, nMapMode
);
1690 bBoundsDetermined
= true;
1694 SAL_WARN_IF(!bRecordOk
, "vcl.wmf", "polyline record claimed more points than the stream can provide");
1698 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1705 case W_META_SETPIXEL
:
1708 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1709 bBoundsDetermined
= true;
1713 case W_META_TEXTOUT
:
1716 pStm
->ReadUInt16( nLength
);
1717 // todo: we also have to take care of the text width
1720 pStm
->SeekRel( ( nLength
+ 1 ) &~ 1 );
1721 GetWinExtMax( ReadYX(), aBound
, nMapMode
);
1722 bBoundsDetermined
= true;
1727 case W_META_EXTTEXTOUT
:
1729 sal_uInt16 nLen
, nOptions
;
1732 aPosition
= ReadYX();
1733 pStm
->ReadUInt16( nLen
).ReadUInt16( nOptions
);
1734 // todo: we also have to take care of the text width
1737 GetWinExtMax( aPosition
, aBound
, nMapMode
);
1738 bBoundsDetermined
= true;
1743 case W_META_STRETCHBLT
:
1744 case W_META_DIBBITBLT
:
1745 case W_META_DIBSTRETCHBLT
:
1746 case W_META_STRETCHDIB
:
1749 sal_uInt16 nSx
, nSy
, nUsage
;
1750 pStm
->ReadInt32( nWinROP
);
1752 if( nFunction
== W_META_STRETCHDIB
)
1753 pStm
->ReadUInt16( nUsage
);
1755 // nSye and nSxe is the number of pixels that has to been used
1756 if( nFunction
== W_META_STRETCHDIB
|| nFunction
== W_META_STRETCHBLT
|| nFunction
== W_META_DIBSTRETCHBLT
)
1758 sal_uInt16 nSxe
, nSye
;
1759 pStm
->ReadUInt16( nSye
).ReadUInt16( nSxe
);
1762 // nSy and nx is the offset of the first pixel
1763 pStm
->ReadUInt16( nSy
).ReadUInt16( nSx
);
1765 if( nFunction
== W_META_STRETCHDIB
|| nFunction
== W_META_DIBBITBLT
|| nFunction
== W_META_DIBSTRETCHBLT
)
1767 if ( nWinROP
== PATCOPY
)
1768 pStm
->ReadUInt16( nUsage
); // i don't know anything of this parameter, so its called nUsage
1769 // DrawRect( Rectangle( ReadYX(), aDestSize ), false );
1771 Size
aDestSize( ReadYXExt() );
1772 if ( aDestSize
.Width() && aDestSize
.Height() ) // #92623# do not try to read buggy bitmaps
1774 tools::Rectangle
aDestRect( ReadYX(), aDestSize
);
1775 GetWinExtMax( aDestRect
, aBound
, nMapMode
);
1776 bBoundsDetermined
= true;
1785 pStm
->ReadUInt32( nROP
);
1786 Size aSize
= ReadYXExt();
1787 GetWinExtMax( tools::Rectangle( ReadYX(), aSize
), aBound
, nMapMode
);
1788 bBoundsDetermined
= true;
1793 const auto nAvailableBytes
= nEnd
- nPos
;
1794 const auto nMaxPossibleRecordSize
= nAvailableBytes
/2;
1795 if (nRSize
<= nMaxPossibleRecordSize
)
1802 pStm
->SetError( SVSTREAM_FILEFORMAT_ERROR
);
1809 pStm
->SetError( SVSTREAM_GENERALERROR
);
1817 rPlaceableBound
= tools::Rectangle(aWinOrg
, *aWinExt
);
1818 SAL_INFO("vcl.wmf", "Window dimension "
1819 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1820 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1822 else if (aViewportExt
)
1824 rPlaceableBound
= tools::Rectangle(aViewportOrg
, *aViewportExt
);
1825 SAL_INFO("vcl.wmf", "Viewport dimension "
1826 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1827 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1829 else if (bBoundsDetermined
)
1831 rPlaceableBound
= aBound
;
1832 SAL_INFO("vcl.wmf", "Determined dimension "
1833 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1834 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1838 rPlaceableBound
.SetLeft( 0 );
1839 rPlaceableBound
.SetTop( 0 );
1840 rPlaceableBound
.SetRight( aMaxWidth
);
1841 rPlaceableBound
.SetBottom( aMaxWidth
);
1842 SAL_INFO("vcl.wmf", "Default dimension "
1843 " t: " << rPlaceableBound
.Left() << " l: " << rPlaceableBound
.Top()
1844 << " b: " << rPlaceableBound
.Right() << " r: " << rPlaceableBound
.Bottom());
1849 WmfReader::WmfReader(SvStream
& rStreamWMF
, GDIMetaFile
& rGDIMetaFile
, const WmfExternal
* pExternalHeader
)
1850 : MtfTools(rGDIMetaFile
, rStreamWMF
)
1851 , mnUnitsPerInch(96)
1858 , mnCurrentAction(0)
1859 , mpExternalHeader(pExternalHeader
)
1864 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */