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 <filter/EpsWriter.hxx>
21 #include <tools/stream.hxx>
22 #include <tools/poly.hxx>
23 #include <tools/fract.hxx>
24 #include <tools/helpers.hxx>
25 #include <tools/UnitConversion.hxx>
26 #include <unotools/resmgr.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/metaact.hxx>
29 #include <vcl/graph.hxx>
30 #include <vcl/BitmapReadAccess.hxx>
31 #include <vcl/region.hxx>
32 #include <vcl/font.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vcl/cvtgrf.hxx>
35 #include <vcl/gradient.hxx>
36 #include <unotools/configmgr.hxx>
37 #include <vcl/FilterConfigItem.hxx>
38 #include <vcl/graphictools.hxx>
39 #include <vcl/weld.hxx>
40 #include <strings.hrc>
41 #include <osl/diagnose.h>
42 #include <com/sun/star/task/XStatusIndicator.hpp>
43 #include <officecfg/Office/Common.hxx>
48 using namespace ::com::sun::star::uno
;
50 #define POSTSCRIPT_BOUNDINGSEARCH 0x1000 // we only try to get the BoundingBox
51 // in the first 4096 bytes
53 #define EPS_PREVIEW_TIFF 1
54 #define EPS_PREVIEW_EPSI 2
56 #define PS_LINESIZE 70 // maximum number of characters a line in the output
58 // -----------------------------field-types------------------------------
64 struct StackMember
* pSucc
;
79 SvtGraphicStroke::CapType eLineCap
;
80 SvtGraphicStroke::JoinType eJoinType
;
81 SvtGraphicStroke::DashArray aDashArray
;
87 PSLZWCTreeNode
* pBrother
; // next node who has the same father
88 PSLZWCTreeNode
* pFirstChild
; // first son
89 sal_uInt16 nCode
; // The code for the string of pixel values, which arises if... <missing comment>
90 sal_uInt16 nValue
; // the pixel value
93 enum NMode
{PS_NONE
= 0x00, PS_SPACE
= 0x01, PS_RET
= 0x02, PS_WRAP
= 0x04}; // formatting mode: action which is inserted behind the output
94 inline NMode
operator|(NMode a
, NMode b
)
96 return static_cast<NMode
>(static_cast<sal_uInt8
>(a
) | static_cast<sal_uInt8
>(b
));
103 bool mbLevelWarning
; // if there any embedded eps file which was not exported
104 sal_uInt32 mnLatestPush
; // offset to streamposition, where last push was done
106 tools::Long mnLevel
; // dialog options
110 sal_Int32 mnTextMode
;
113 const GDIMetaFile
* pMTF
;
114 std::unique_ptr
<GDIMetaFile
>
115 pAMTF
; // only created if Graphics is not a Metafile
116 ScopedVclPtrInstance
<VirtualDevice
>
119 double nBoundingX2
; // this represents the bounding box
122 StackMember
* pGDIStack
;
123 sal_uInt32 mnCursorPos
; // current cursor position in output
124 Color aColor
; // current color which is used for output
126 Color aLineColor
; // current GDIMetafile color settings
131 Color aTextFillColor
;
132 Color aBackgroundColor
;
133 TextAlign eTextAlign
;
137 SvtGraphicStroke::CapType eLineCap
;
138 SvtGraphicStroke::JoinType eJoinType
;
139 SvtGraphicStroke::DashArray aDashArray
;
142 vcl::Font maLastFont
;
144 std::unique_ptr
<PSLZWCTreeNode
[]> pTable
; // LZW compression data
145 PSLZWCTreeNode
* pPrefix
; // the compression is as same as the TIFF compression
146 sal_uInt16 nDataSize
;
147 sal_uInt16 nClearCode
;
149 sal_uInt16 nTableSize
;
150 sal_uInt16 nCodeSize
;
154 css::uno::Reference
< css::task::XStatusIndicator
> xStatusIndicator
;
156 void ImplWriteProlog( const Graphic
* pPreviewEPSI
);
157 void ImplWriteEpilog();
158 void ImplWriteActions( const GDIMetaFile
& rMtf
, VirtualDevice
& rVDev
);
160 // this method makes LF's, space inserting and word wrapping as used in all nMode
162 inline void ImplExecMode( NMode nMode
);
164 // writes char[] + LF to stream
165 inline void ImplWriteLine( const char*, NMode nMode
= PS_RET
);
167 // writes ( nNumb / 10^nCount ) in ASCII format to stream
168 void ImplWriteF( sal_Int32 nNumb
, sal_uInt8 nCount
= 3, NMode nMode
= PS_SPACE
);
170 // writes a double in ASCII format to stream
171 void ImplWriteDouble( double );
173 // writes a long in ASCII format to stream
174 void ImplWriteLong( sal_Int32 nNumb
, NMode nMode
= PS_SPACE
);
176 // writes a byte in ASCII format to stream
177 void ImplWriteByte( sal_uInt8 nNumb
, NMode nMode
= PS_SPACE
);
179 // writes a byte in ASCII (hex) format to stream
180 void ImplWriteHexByte( sal_uInt8 nNumb
, NMode nMode
= PS_WRAP
);
182 // writes nNumb as number from 0.000 till 1.000 in ASCII format to stream
183 void ImplWriteB1( sal_uInt8 nNumb
);
185 inline void ImplWritePoint( const Point
& );
186 void ImplMoveTo( const Point
& );
187 void ImplLineTo( const Point
&, NMode nMode
= PS_SPACE
);
188 void ImplCurveTo( const Point
& rP1
, const Point
& rP2
, const Point
& rP3
, NMode nMode
);
189 void ImplTranslate( const double& fX
, const double& fY
);
190 void ImplScale( const double& fX
, const double& fY
);
192 void ImplAddPath( const tools::Polygon
& rPolygon
);
193 void ImplWriteLineInfo( double fLineWidth
, double fMiterLimit
, SvtGraphicStroke::CapType eLineCap
,
194 SvtGraphicStroke::JoinType eJoinType
, SvtGraphicStroke::DashArray
&& rDashArray
);
195 void ImplWriteLineInfo( const LineInfo
& rLineInfo
);
196 void ImplRect( const tools::Rectangle
& rRectangle
);
197 void ImplRectFill ( const tools::Rectangle
& rRectangle
);
198 void ImplWriteGradient( const tools::PolyPolygon
& rPolyPoly
, const Gradient
& rGradient
, VirtualDevice
& rVDev
);
199 void ImplIntersect( const tools::PolyPolygon
& rPolyPoly
);
200 void ImplPolyPoly( const tools::PolyPolygon
& rPolyPolygon
, bool bTextOutline
= false );
201 void ImplPolyLine( const tools::Polygon
& rPolygon
);
203 void ImplSetClipRegion( vcl::Region
const & rRegion
);
204 void ImplBmp( Bitmap
const *, AlphaMask
const *, const Point
&, double nWidth
, double nHeight
);
205 void ImplText( const OUString
& rUniString
, const Point
& rPos
, KernArraySpan pDXArry
, std::span
<const sal_Bool
> pKashidaArry
, sal_Int32 nWidth
, VirtualDevice
const & rVDev
);
206 void ImplSetAttrForText( const Point
& rPoint
);
207 void ImplWriteCharacter( char );
208 void ImplWriteString( const OString
&, VirtualDevice
const & rVDev
, KernArraySpan pDXArry
, bool bStretch
);
209 void ImplDefineFont( const char*, const char* );
211 void ImplClosePathDraw();
214 inline void ImplWriteLineColor( NMode nMode
);
215 inline void ImplWriteFillColor( NMode nMode
);
216 inline void ImplWriteTextColor( NMode nMode
);
217 void ImplWriteColor( NMode nMode
);
219 void ImplGetMapMode( const MapMode
& );
220 static bool ImplGetBoundingBox( double* nNumb
, sal_uInt8
* pSource
, sal_uInt32 nSize
);
221 static sal_uInt8
* ImplSearchEntry( sal_uInt8
* pSource
, sal_uInt8
const * pDest
, sal_uInt32 nComp
, sal_uInt32 nSize
);
223 void StartCompression();
224 void Compress( sal_uInt8 nSrc
);
225 void EndCompression();
226 inline void WriteBits( sal_uInt16 nCode
, sal_uInt16 nCodeLen
);
229 bool WritePS( const Graphic
& rGraphic
, SvStream
& rTargetStream
, FilterConfigItem
* );
235 //========================== methods from PSWriter ==========================
240 , mbLevelWarning(false)
244 , mbCompression(false)
255 , bTextFillColor(false)
272 bool PSWriter::WritePS( const Graphic
& rGraphic
, SvStream
& rTargetStream
, FilterConfigItem
* pFilterConfigItem
)
274 sal_uInt32 nStreamPosition
= 0, nPSPosition
= 0; // -Wall warning, unset, check
278 mbLevelWarning
= false;
279 mnLatestPush
= 0xEFFFFFFE;
281 if ( pFilterConfigItem
)
283 xStatusIndicator
= pFilterConfigItem
->GetStatusIndicator();
284 if ( xStatusIndicator
.is() )
286 xStatusIndicator
->start( OUString(), 100 );
290 mpPS
= &rTargetStream
;
291 mpPS
->SetEndian( SvStreamEndian::LITTLE
);
293 // default values for the dialog options
296 #ifdef UNX // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
297 mbCompression
= false;
299 mbCompression
= true;
301 mnTextMode
= 0; // default0 : export glyph outlines
303 // try to get the dialog selection
304 if ( pFilterConfigItem
)
306 #ifdef UNX // don't put binary tiff preview ahead of postscript code by default on unix as ghostscript is unable to read it
307 mnPreview
= pFilterConfigItem
->ReadInt32( u
"Preview"_ustr
, 0 );
309 mnPreview
= pFilterConfigItem
->ReadInt32( "Preview", 1 );
311 mnLevel
= pFilterConfigItem
->ReadInt32( u
"Version"_ustr
, 2 );
314 mbGrayScale
= pFilterConfigItem
->ReadInt32( u
"ColorFormat"_ustr
, 1 ) == 2;
315 #ifdef UNX // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
316 mbCompression
= pFilterConfigItem
->ReadInt32( u
"CompressionMode"_ustr
, 0 ) != 0;
318 mbCompression
= pFilterConfigItem
->ReadInt32( "CompressionMode", 1 ) == 1;
320 mnTextMode
= pFilterConfigItem
->ReadInt32( u
"TextMode"_ustr
, 0 );
321 if ( mnTextMode
> 2 )
325 // compression is not available for Level 1
329 mbCompression
= false;
332 if ( mnPreview
& EPS_PREVIEW_TIFF
)
334 rTargetStream
.WriteUInt32( 0xC6D3D0C5 );
335 nStreamPosition
= rTargetStream
.Tell();
336 rTargetStream
.WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
337 .WriteUInt32( nStreamPosition
+ 26 ).WriteUInt32( 0 ).WriteUInt16( 0xffff );
342 BitmapEx
aTempBitmapEx( rGraphic
.GetBitmapEx() );
343 aTempBitmapEx
.Convert( BmpConversion::N8BitGreys
);
344 nErrCode
= GraphicConverter::Export( rTargetStream
, aTempBitmapEx
, ConvertDataFormat::TIF
) ;
347 nErrCode
= GraphicConverter::Export( rTargetStream
, rGraphic
, ConvertDataFormat::TIF
) ;
349 if ( nErrCode
== ERRCODE_NONE
)
351 nPSPosition
= rTargetStream
.TellEnd();
352 rTargetStream
.Seek( nStreamPosition
+ 20 );
353 rTargetStream
.WriteUInt32( nPSPosition
- 30 ); // size of tiff gfx
354 rTargetStream
.Seek( nPSPosition
);
358 mnPreview
&=~ EPS_PREVIEW_TIFF
;
359 rTargetStream
.Seek( nStreamPosition
- 4 );
363 // global default value setting
366 if (rGraphic
.GetType() == GraphicType::GdiMetafile
)
367 pMTF
= &rGraphic
.GetGDIMetaFile();
368 else if (rGraphic
.GetGDIMetaFile().GetActionSize())
370 pAMTF
.reset( new GDIMetaFile( rGraphic
.GetGDIMetaFile() ) );
375 BitmapEx
aBmp( rGraphic
.GetBitmapEx() );
376 pAMTF
.reset( new GDIMetaFile
);
377 ScopedVclPtrInstance
< VirtualDevice
> pTmpVDev
;
378 pAMTF
->Record( pTmpVDev
);
379 pTmpVDev
->DrawBitmapEx( Point(), aBmp
);
381 pAMTF
->SetPrefSize( aBmp
.GetSizePixel() );
384 pVDev
->SetMapMode( pMTF
->GetPrefMapMode() );
385 nBoundingX2
= pMTF
->GetPrefSize().Width();
386 nBoundingY2
= pMTF
->GetPrefSize().Height();
389 aColor
= COL_TRANSPARENT
;
391 aLineColor
= COL_BLACK
;
393 aFillColor
= COL_WHITE
;
394 bTextFillColor
= true;
395 aTextFillColor
= COL_BLACK
;
397 fMiterLimit
= 15; // use same limit as most graphic systems and basegfx
398 eLineCap
= SvtGraphicStroke::capButt
;
399 eJoinType
= SvtGraphicStroke::joinMiter
;
400 aBackgroundColor
= COL_WHITE
;
401 eTextAlign
= ALIGN_BASELINE
;
403 if( pMTF
->GetActionSize() )
405 ImplWriteProlog( ( mnPreview
& EPS_PREVIEW_EPSI
) ? &rGraphic
: nullptr );
407 ImplWriteActions( *pMTF
, *pVDev
);
409 if ( mnPreview
& EPS_PREVIEW_TIFF
)
411 sal_uInt32 nPosition
= rTargetStream
.Tell();
412 rTargetStream
.Seek( nStreamPosition
);
413 rTargetStream
.WriteUInt32( nPSPosition
);
414 rTargetStream
.WriteUInt32( nPosition
- nPSPosition
);
415 rTargetStream
.Seek( nPosition
);
420 pGDIStack
=pGS
->pSucc
;
427 if ( mbStatus
&& mbLevelWarning
&& pFilterConfigItem
)
429 std::locale loc
= Translate::Create("flt");
430 std::unique_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(nullptr,
431 VclMessageType::Info
, VclButtonsType::Ok
,
432 Translate::get(KEY_VERSION_CHECK
, loc
)));
436 if ( xStatusIndicator
.is() )
437 xStatusIndicator
->end();
442 void PSWriter::ImplWriteProlog( const Graphic
* pPreview
)
444 ImplWriteLine( "%!PS-Adobe-3.0 EPSF-3.0 " );
445 mpPS
->WriteOString( "%%BoundingBox: " ); // BoundingBox
448 Size aSizePoint
= OutputDevice::LogicToLogic( pMTF
->GetPrefSize(),
449 pMTF
->GetPrefMapMode(), MapMode(MapUnit::MapPoint
));
450 ImplWriteLong( aSizePoint
.Width() );
451 ImplWriteLong( aSizePoint
.Height() ,PS_RET
);
452 ImplWriteLine( "%%Pages: 0" );
454 OUString aCreatorOverride
= officecfg::Office::Common::Save::Document::GeneratorOverride::get();
455 if( !aCreatorOverride
.isEmpty())
456 aCreator
= aCreatorOverride
;
458 aCreator
= "%%Creator: " + utl::ConfigManager::getProductName() + " " +
459 utl::ConfigManager::getProductVersion();
460 ImplWriteLine( OUStringToOString( aCreator
, RTL_TEXTENCODING_UTF8
).getStr() );
461 ImplWriteLine( "%%Title: none" );
462 ImplWriteLine( "%%CreationDate: none" );
466 mpPS
->WriteOString( "%%LanguageLevel: " ); // Language level
467 ImplWriteLong( mnLevel
, PS_RET
);
468 if ( !mbGrayScale
&& mnLevel
== 1 )
469 ImplWriteLine( "%%Extensions: CMYK" ); // CMYK extension is to set in color mode in level 1
470 ImplWriteLine( "%%EndComments" );
471 if ( pPreview
&& aSizePoint
.Width() && aSizePoint
.Height() )
473 Size
aSizeBitmap( ( aSizePoint
.Width() + 7 ) & ~7, aSizePoint
.Height() );
474 Bitmap
aTmpBitmap( pPreview
->GetBitmapEx().GetBitmap() );
475 aTmpBitmap
.Scale( aSizeBitmap
, BmpScaleFlag::BestQuality
);
476 aTmpBitmap
.Convert( BmpConversion::N1BitThreshold
);
477 BitmapScopedReadAccess
pAcc(aTmpBitmap
);
480 mpPS
->WriteOString( "%%BeginPreview: " ); // BoundingBox
481 ImplWriteLong( aSizeBitmap
.Width() );
482 ImplWriteLong( aSizeBitmap
.Height() );
483 mpPS
->WriteOString( "1 " );
484 sal_Int32 nLines
= aSizeBitmap
.Width() / 312;
485 if ( ( nLines
* 312 ) != aSizeBitmap
.Width() )
487 nLines
*= aSizeBitmap
.Height();
488 ImplWriteLong( nLines
);
489 sal_Int32 nCount2
, nCount
= 4;
490 const BitmapColor
aBlack( pAcc
->GetBestMatchingColor( COL_BLACK
) );
491 for ( tools::Long nY
= 0; nY
< aSizeBitmap
.Height(); nY
++ )
495 Scanline pScanline
= pAcc
->GetScanline( nY
);
496 for ( tools::Long nX
= 0; nX
< aSizeBitmap
.Width(); nX
++ )
500 ImplExecMode( PS_RET
);
501 mpPS
->WriteOString( "%" );
505 if ( pAcc
->GetPixelFromData( pScanline
, nX
) == aBlack
)
507 if ( ! ( --nCount
) )
513 mpPS
->WriteChar( nVal
);
521 ImplExecMode( PS_RET
);
522 ImplWriteLine( "%%EndPreview" );
525 ImplWriteLine( "%%BeginProlog" );
526 ImplWriteLine( "%%BeginResource: procset SDRes-Prolog 1.0 0" );
529 ImplWriteLine( "/b4_inc_state save def\n/dict_count countdictstack def\n/op_count count 1 sub def\nuserdict begin" );
530 ImplWriteLine( "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath" );
531 ImplWriteLine( "/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if" );
533 ImplWriteLine( "/bdef {bind def} bind def" ); // the new operator bdef is created
535 ImplWriteLine( "/c {setgray} bdef" );
537 ImplWriteLine( "/c {setrgbcolor} bdef" );
538 ImplWriteLine( "/l {neg lineto} bdef" );
539 ImplWriteLine( "/rl {neg rlineto} bdef" );
540 ImplWriteLine( "/lc {setlinecap} bdef" );
541 ImplWriteLine( "/lj {setlinejoin} bdef" );
542 ImplWriteLine( "/lw {setlinewidth} bdef" );
543 ImplWriteLine( "/ml {setmiterlimit} bdef" );
544 ImplWriteLine( "/ld {setdash} bdef" );
545 ImplWriteLine( "/m {neg moveto} bdef" );
546 ImplWriteLine( "/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef" );
547 ImplWriteLine( "/r {rotate} bdef" );
548 ImplWriteLine( "/t {neg translate} bdef" );
549 ImplWriteLine( "/s {scale} bdef" );
550 ImplWriteLine( "/sw {show} bdef" );
551 ImplWriteLine( "/gs {gsave} bdef" );
552 ImplWriteLine( "/gr {grestore} bdef" );
554 ImplWriteLine( "/f {findfont dup length dict begin" ); // Setfont
555 ImplWriteLine( "{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def" );
556 ImplWriteLine( "currentdict end /NFont exch definefont pop /NFont findfont} bdef" );
558 ImplWriteLine( "/p {closepath} bdef" );
559 ImplWriteLine( "/sf {scalefont setfont} bdef" );
561 ImplWriteLine( "/ef {eofill}bdef" ); // close path and fill
562 ImplWriteLine( "/pc {closepath stroke}bdef" ); // close path and draw
563 ImplWriteLine( "/ps {stroke}bdef" ); // draw current path
564 ImplWriteLine( "/pum {matrix currentmatrix}bdef" ); // pushes the current matrix
565 ImplWriteLine( "/pom {setmatrix}bdef" ); // pops the matrix
566 ImplWriteLine( "/bs {/aString exch def /nXOfs exch def /nWidth exch def currentpoint nXOfs 0 rmoveto pum nWidth aString stringwidth pop div 1 scale aString show pom moveto} bdef" );
567 ImplWriteLine( "%%EndResource" );
568 ImplWriteLine( "%%EndProlog" );
569 ImplWriteLine( "%%BeginSetup" );
570 ImplWriteLine( "%%EndSetup" );
571 ImplWriteLine( "%%Page: 1 1" );
572 ImplWriteLine( "%%BeginPageSetup" );
573 ImplWriteLine( "%%EndPageSetup" );
574 ImplWriteLine( "pum" );
575 ImplScale( static_cast<double>(aSizePoint
.Width()) / static_cast<double>(pMTF
->GetPrefSize().Width()), static_cast<double>(aSizePoint
.Height()) / static_cast<double>(pMTF
->GetPrefSize().Height()) );
576 ImplWriteDouble( 0 );
577 ImplWriteDouble( -pMTF
->GetPrefSize().Height() );
578 ImplWriteLine( "t" );
579 ImplWriteLine( "/tm matrix currentmatrix def" );
582 void PSWriter::ImplWriteEpilog()
584 ImplTranslate( 0, nBoundingY2
);
585 ImplWriteLine( "pom" );
586 ImplWriteLine( "count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore" );
588 ImplWriteLine( "%%PageTrailer" );
589 ImplWriteLine( "%%Trailer" );
591 ImplWriteLine( "%%EOF" );
594 void PSWriter::ImplWriteActions( const GDIMetaFile
& rMtf
, VirtualDevice
& rVDev
)
596 tools::PolyPolygon aFillPath
;
598 for( size_t nCurAction
= 0, nCount
= rMtf
.GetActionSize(); nCurAction
< nCount
; nCurAction
++ )
600 MetaAction
* pMA
= rMtf
.GetAction( nCurAction
);
602 switch( pMA
->GetType() )
604 case MetaActionType::NONE
:
607 case MetaActionType::PIXEL
:
609 Color
aOldLineColor( aLineColor
);
610 aLineColor
= static_cast<const MetaPixelAction
*>(pMA
)->GetColor();
611 ImplWriteLineColor( PS_SPACE
);
612 ImplMoveTo( static_cast<const MetaPixelAction
*>(pMA
)->GetPoint() );
613 ImplLineTo( static_cast<const MetaPixelAction
*>(pMA
)->GetPoint() );
615 aLineColor
= aOldLineColor
;
619 case MetaActionType::POINT
:
621 ImplWriteLineColor( PS_SPACE
);
622 ImplMoveTo( static_cast<const MetaPointAction
*>(pMA
)->GetPoint() );
623 ImplLineTo( static_cast<const MetaPointAction
*>(pMA
)->GetPoint() );
628 case MetaActionType::LINE
:
630 const LineInfo
& rLineInfo
= static_cast<const MetaLineAction
*>(pMA
)->GetLineInfo();
631 ImplWriteLineInfo( rLineInfo
);
634 ImplWriteLineColor( PS_SPACE
);
635 ImplMoveTo( static_cast<const MetaLineAction
*>(pMA
)->GetStartPoint() );
636 ImplLineTo( static_cast<const MetaLineAction
*>(pMA
)->GetEndPoint() );
642 case MetaActionType::RECT
:
644 ImplRect( static_cast<const MetaRectAction
*>(pMA
)->GetRect() );
648 case MetaActionType::ROUNDRECT
:
649 ImplRect( static_cast<const MetaRoundRectAction
*>(pMA
)->GetRect() );
652 case MetaActionType::ELLIPSE
:
654 tools::Rectangle aRect
= static_cast<const MetaEllipseAction
*>(pMA
)->GetRect();
655 Point aCenter
= aRect
.Center();
656 tools::Polygon
aPoly( aCenter
, aRect
.GetWidth() / 2, aRect
.GetHeight() / 2 );
657 tools::PolyPolygon
aPolyPoly( aPoly
);
658 ImplPolyPoly( aPolyPoly
);
662 case MetaActionType::ARC
:
664 tools::Polygon
aPoly( static_cast<const MetaArcAction
*>(pMA
)->GetRect(), static_cast<const MetaArcAction
*>(pMA
)->GetStartPoint(),
665 static_cast<const MetaArcAction
*>(pMA
)->GetEndPoint(), PolyStyle::Arc
);
666 tools::PolyPolygon
aPolyPoly( aPoly
);
667 ImplPolyPoly( aPolyPoly
);
671 case MetaActionType::PIE
:
673 tools::Polygon
aPoly( static_cast<const MetaPieAction
*>(pMA
)->GetRect(), static_cast<const MetaPieAction
*>(pMA
)->GetStartPoint(),
674 static_cast<const MetaPieAction
*>(pMA
)->GetEndPoint(), PolyStyle::Pie
);
675 tools::PolyPolygon
aPolyPoly( aPoly
);
676 ImplPolyPoly( aPolyPoly
);
680 case MetaActionType::CHORD
:
682 tools::Polygon
aPoly( static_cast<const MetaChordAction
*>(pMA
)->GetRect(), static_cast<const MetaChordAction
*>(pMA
)->GetStartPoint(),
683 static_cast<const MetaChordAction
*>(pMA
)->GetEndPoint(), PolyStyle::Chord
);
684 tools::PolyPolygon
aPolyPoly( aPoly
);
685 ImplPolyPoly( aPolyPoly
);
689 case MetaActionType::POLYLINE
:
691 tools::Polygon
aPoly( static_cast<const MetaPolyLineAction
*>(pMA
)->GetPolygon() );
692 const LineInfo
& rLineInfo
= static_cast<const MetaPolyLineAction
*>(pMA
)->GetLineInfo();
693 ImplWriteLineInfo( rLineInfo
);
695 if(basegfx::B2DLineJoin::NONE
== rLineInfo
.GetLineJoin()
696 && rLineInfo
.GetWidth() > 1)
698 // emulate B2DLineJoin::NONE by creating single edges
699 const sal_uInt16
nPoints(aPoly
.GetSize());
700 const bool bCurve(aPoly
.HasFlags());
702 for(sal_uInt16
a(0); a
+ 1 < nPoints
; a
++)
705 && PolyFlags::Normal
!= aPoly
.GetFlags(a
+ 1)
707 && PolyFlags::Normal
!= aPoly
.GetFlags(a
+ 2)
710 const tools::Polygon
aSnippet(4,
711 aPoly
.GetConstPointAry() + a
,
712 aPoly
.GetConstFlagAry() + a
);
713 ImplPolyLine(aSnippet
);
718 const tools::Polygon
aSnippet(2,
719 aPoly
.GetConstPointAry() + a
);
720 ImplPolyLine(aSnippet
);
726 ImplPolyLine( aPoly
);
731 case MetaActionType::POLYGON
:
733 tools::PolyPolygon
aPolyPoly( static_cast<const MetaPolygonAction
*>(pMA
)->GetPolygon() );
734 ImplPolyPoly( aPolyPoly
);
738 case MetaActionType::POLYPOLYGON
:
740 ImplPolyPoly( static_cast<const MetaPolyPolygonAction
*>(pMA
)->GetPolyPolygon() );
744 case MetaActionType::TEXT
:
746 const MetaTextAction
* pA
= static_cast<const MetaTextAction
*>(pMA
);
748 OUString aUniStr
= pA
->GetText().copy( pA
->GetIndex(), pA
->GetLen() );
749 Point
aPoint( pA
->GetPoint() );
751 ImplText( aUniStr
, aPoint
, {}, {}, 0, rVDev
);
755 case MetaActionType::TEXTRECT
:
757 OSL_FAIL( "Unsupported action: TextRect...Action!" );
761 case MetaActionType::STRETCHTEXT
:
763 const MetaStretchTextAction
* pA
= static_cast<const MetaStretchTextAction
*>(pMA
);
764 OUString aUniStr
= pA
->GetText().copy( pA
->GetIndex(), pA
->GetLen() );
765 Point
aPoint( pA
->GetPoint() );
767 ImplText( aUniStr
, aPoint
, {}, {}, pA
->GetWidth(), rVDev
);
771 case MetaActionType::TEXTARRAY
:
773 const MetaTextArrayAction
* pA
= static_cast<const MetaTextArrayAction
*>(pMA
);
774 OUString aUniStr
= pA
->GetText().copy( pA
->GetIndex(), pA
->GetLen() );
775 Point
aPoint( pA
->GetPoint() );
777 ImplText( aUniStr
, aPoint
, pA
->GetDXArray(), pA
->GetKashidaArray(), 0, rVDev
);
781 case MetaActionType::BMP
:
783 Bitmap aBitmap
= static_cast<const MetaBmpAction
*>(pMA
)->GetBitmap();
785 aBitmap
.Convert( BmpConversion::N8BitGreys
);
786 Point aPoint
= static_cast<const MetaBmpAction
*>(pMA
)->GetPoint();
787 Size
aSize( rVDev
.PixelToLogic( aBitmap
.GetSizePixel() ) );
788 ImplBmp( &aBitmap
, nullptr, aPoint
, aSize
.Width(), aSize
.Height() );
792 case MetaActionType::BMPSCALE
:
794 Bitmap aBitmap
= static_cast<const MetaBmpScaleAction
*>(pMA
)->GetBitmap();
796 aBitmap
.Convert( BmpConversion::N8BitGreys
);
797 Point aPoint
= static_cast<const MetaBmpScaleAction
*>(pMA
)->GetPoint();
798 Size aSize
= static_cast<const MetaBmpScaleAction
*>(pMA
)->GetSize();
799 ImplBmp( &aBitmap
, nullptr, aPoint
, aSize
.Width(), aSize
.Height() );
803 case MetaActionType::BMPSCALEPART
:
805 Bitmap
aBitmap( static_cast<const MetaBmpScalePartAction
*>(pMA
)->GetBitmap() );
806 aBitmap
.Crop( tools::Rectangle( static_cast<const MetaBmpScalePartAction
*>(pMA
)->GetSrcPoint(),
807 static_cast<const MetaBmpScalePartAction
*>(pMA
)->GetSrcSize() ) );
809 aBitmap
.Convert( BmpConversion::N8BitGreys
);
810 Point aPoint
= static_cast<const MetaBmpScalePartAction
*>(pMA
)->GetDestPoint();
811 Size aSize
= static_cast<const MetaBmpScalePartAction
*>(pMA
)->GetDestSize();
812 ImplBmp( &aBitmap
, nullptr, aPoint
, aSize
.Width(), aSize
.Height() );
816 case MetaActionType::BMPEX
:
818 BitmapEx
aBitmapEx( static_cast<MetaBmpExAction
*>(pMA
)->GetBitmapEx() );
819 Bitmap
aBitmap( aBitmapEx
.GetBitmap() );
821 aBitmap
.Convert( BmpConversion::N8BitGreys
);
822 const AlphaMask
& aMask( aBitmapEx
.GetAlphaMask() );
823 Point
aPoint( static_cast<const MetaBmpExAction
*>(pMA
)->GetPoint() );
824 Size
aSize( rVDev
.PixelToLogic( aBitmap
.GetSizePixel() ) );
825 ImplBmp( &aBitmap
, &aMask
, aPoint
, aSize
.Width(), aSize
.Height() );
829 case MetaActionType::BMPEXSCALE
:
831 BitmapEx
aBitmapEx( static_cast<MetaBmpExScaleAction
*>(pMA
)->GetBitmapEx() );
832 Bitmap
aBitmap( aBitmapEx
.GetBitmap() );
834 aBitmap
.Convert( BmpConversion::N8BitGreys
);
835 const AlphaMask
& aMask( aBitmapEx
.GetAlphaMask() );
836 Point aPoint
= static_cast<const MetaBmpExScaleAction
*>(pMA
)->GetPoint();
837 Size
aSize( static_cast<const MetaBmpExScaleAction
*>(pMA
)->GetSize() );
838 ImplBmp( &aBitmap
, &aMask
, aPoint
, aSize
.Width(), aSize
.Height() );
842 case MetaActionType::BMPEXSCALEPART
:
844 BitmapEx
aBitmapEx( static_cast<const MetaBmpExScalePartAction
*>(pMA
)->GetBitmapEx() );
845 aBitmapEx
.Crop( tools::Rectangle( static_cast<const MetaBmpExScalePartAction
*>(pMA
)->GetSrcPoint(),
846 static_cast<const MetaBmpExScalePartAction
*>(pMA
)->GetSrcSize() ) );
847 Bitmap
aBitmap( aBitmapEx
.GetBitmap() );
849 aBitmap
.Convert( BmpConversion::N8BitGreys
);
850 AlphaMask
aMask( aBitmapEx
.GetAlphaMask() );
851 Point aPoint
= static_cast<const MetaBmpExScalePartAction
*>(pMA
)->GetDestPoint();
852 Size aSize
= static_cast<const MetaBmpExScalePartAction
*>(pMA
)->GetDestSize();
853 ImplBmp( &aBitmap
, &aMask
, aPoint
, aSize
.Width(), aSize
.Height() );
857 // Unsupported Actions
858 case MetaActionType::MASK
:
859 case MetaActionType::MASKSCALE
:
860 case MetaActionType::MASKSCALEPART
:
862 OSL_FAIL( "Unsupported action: MetaMask...Action!" );
866 case MetaActionType::GRADIENT
:
868 tools::PolyPolygon
aPolyPoly( static_cast<const MetaGradientAction
*>(pMA
)->GetRect() );
869 ImplWriteGradient( aPolyPoly
, static_cast<const MetaGradientAction
*>(pMA
)->GetGradient(), rVDev
);
873 case MetaActionType::GRADIENTEX
:
875 tools::PolyPolygon
aPolyPoly( static_cast<const MetaGradientExAction
*>(pMA
)->GetPolyPolygon() );
876 ImplWriteGradient( aPolyPoly
, static_cast<const MetaGradientExAction
*>(pMA
)->GetGradient(), rVDev
);
880 case MetaActionType::HATCH
:
882 ScopedVclPtrInstance
< VirtualDevice
> l_pVirDev
;
885 l_pVirDev
->SetMapMode( rVDev
.GetMapMode() );
886 l_pVirDev
->AddHatchActions( static_cast<const MetaHatchAction
*>(pMA
)->GetPolyPolygon(),
887 static_cast<const MetaHatchAction
*>(pMA
)->GetHatch(), aTmpMtf
);
888 ImplWriteActions( aTmpMtf
, rVDev
);
892 case MetaActionType::WALLPAPER
:
894 const MetaWallpaperAction
* pA
= static_cast<const MetaWallpaperAction
*>(pMA
);
895 tools::Rectangle aRect
= pA
->GetRect();
896 const Wallpaper
& aWallpaper
= pA
->GetWallpaper();
898 if ( aWallpaper
.IsBitmap() )
900 BitmapEx aBitmapEx
= aWallpaper
.GetBitmap();
901 const Bitmap
& aBitmap( aBitmapEx
.GetBitmap() );
902 if ( aBitmapEx
.IsAlpha() )
904 if ( aWallpaper
.IsGradient() )
910 const AlphaMask
& aMask( aBitmapEx
.GetAlphaMask() );
911 ImplBmp( &aBitmap
, &aMask
, Point( aRect
.Left(), aRect
.Top() ), aRect
.GetWidth(), aRect
.GetHeight() );
914 ImplBmp( &aBitmap
, nullptr, Point( aRect
.Left(), aRect
.Top() ), aRect
.GetWidth(), aRect
.GetHeight() );
919 else if ( aWallpaper
.IsGradient() )
927 aColor
= aWallpaper
.GetColor();
928 ImplRectFill( aRect
);
933 case MetaActionType::ISECTRECTCLIPREGION
:
935 const MetaISectRectClipRegionAction
* pA
= static_cast<const MetaISectRectClipRegionAction
*>(pMA
);
936 vcl::Region
aRegion( pA
->GetRect() );
937 ImplSetClipRegion( aRegion
);
941 case MetaActionType::CLIPREGION
:
943 const MetaClipRegionAction
* pA
= static_cast<const MetaClipRegionAction
*>(pMA
);
944 const vcl::Region
& aRegion( pA
->GetRegion() );
945 ImplSetClipRegion( aRegion
);
949 case MetaActionType::ISECTREGIONCLIPREGION
:
951 const MetaISectRegionClipRegionAction
* pA
= static_cast<const MetaISectRegionClipRegionAction
*>(pMA
);
952 const vcl::Region
& aRegion( pA
->GetRegion() );
953 ImplSetClipRegion( aRegion
);
957 case MetaActionType::MOVECLIPREGION
:
963 case MetaActionType::LINECOLOR
:
965 if ( static_cast<const MetaLineColorAction
*>(pMA
)->IsSetting() )
968 aLineColor
= static_cast<const MetaLineColorAction
*>(pMA
)->GetColor();
975 case MetaActionType::FILLCOLOR
:
977 if ( static_cast<const MetaFillColorAction
*>(pMA
)->IsSetting() )
980 aFillColor
= static_cast<const MetaFillColorAction
*>(pMA
)->GetColor();
987 case MetaActionType::TEXTCOLOR
:
989 aTextColor
= static_cast<const MetaTextColorAction
*>(pMA
)->GetColor();
993 case MetaActionType::TEXTFILLCOLOR
:
995 if ( static_cast<const MetaTextFillColorAction
*>(pMA
)->IsSetting() )
997 bTextFillColor
= true;
998 aTextFillColor
= static_cast<const MetaTextFillColorAction
*>(pMA
)->GetColor();
1001 bTextFillColor
= false;
1005 case MetaActionType::TEXTALIGN
:
1007 eTextAlign
= static_cast<const MetaTextAlignAction
*>(pMA
)->GetTextAlign();
1011 case MetaActionType::MAPMODE
:
1013 pMA
->Execute( &rVDev
);
1014 ImplGetMapMode( rVDev
.GetMapMode() );
1018 case MetaActionType::FONT
:
1020 maFont
= static_cast<const MetaFontAction
*>(pMA
)->GetFont();
1021 rVDev
.SetFont( maFont
);
1025 case MetaActionType::PUSH
:
1027 rVDev
.Push(static_cast<const MetaPushAction
*>(pMA
)->GetFlags() );
1028 StackMember
* pGS
= new StackMember
;
1029 pGS
->pSucc
= pGDIStack
;
1031 pGS
->aDashArray
= aDashArray
;
1032 pGS
->eJoinType
= eJoinType
;
1033 pGS
->eLineCap
= eLineCap
;
1034 pGS
->fLineWidth
= fLineWidth
;
1035 pGS
->fMiterLimit
= fMiterLimit
;
1036 pGS
->eTextAlign
= eTextAlign
;
1037 pGS
->aGlobalCol
= aColor
;
1038 pGS
->bLineCol
= bLineColor
;
1039 pGS
->aLineCol
= aLineColor
;
1040 pGS
->bFillCol
= bFillColor
;
1041 pGS
->aFillCol
= aFillColor
;
1042 pGS
->aTextCol
= aTextColor
;
1043 pGS
->bTextFillCol
= bTextFillColor
;
1044 pGS
->aTextFillCol
= aTextFillColor
;
1045 pGS
->aBackgroundCol
= aBackgroundColor
;
1046 pGS
->aFont
= maFont
;
1047 mnLatestPush
= mpPS
->Tell();
1048 ImplWriteLine( "gs" );
1052 case MetaActionType::POP
:
1057 StackMember
* pGS
= pGDIStack
;
1058 pGDIStack
= pGS
->pSucc
;
1059 aDashArray
= pGS
->aDashArray
;
1060 eJoinType
= pGS
->eJoinType
;
1061 eLineCap
= pGS
->eLineCap
;
1062 fLineWidth
= pGS
->fLineWidth
;
1063 fMiterLimit
= pGS
->fMiterLimit
;
1064 eTextAlign
= pGS
->eTextAlign
;
1065 aColor
= pGS
->aGlobalCol
;
1066 bLineColor
= pGS
->bLineCol
;
1067 aLineColor
= pGS
->aLineCol
;
1068 bFillColor
= pGS
->bFillCol
;
1069 aFillColor
= pGS
->aFillCol
;
1070 aTextColor
= pGS
->aTextCol
;
1071 bTextFillColor
= pGS
->bTextFillCol
;
1072 aTextFillColor
= pGS
->aTextFillCol
;
1073 aBackgroundColor
= pGS
->aBackgroundCol
;
1074 maFont
= pGS
->aFont
;
1075 maLastFont
= vcl::Font(); // set maLastFont != maFont -> so that
1077 sal_uInt32 nCurrentPos
= mpPS
->Tell();
1078 if ( nCurrentPos
- 3 == mnLatestPush
)
1080 mpPS
->Seek( mnLatestPush
);
1081 ImplWriteLine( " " );
1082 mpPS
->Seek( mnLatestPush
);
1085 ImplWriteLine( "gr" );
1090 case MetaActionType::EPS
:
1092 GfxLink aGfxLink
= static_cast<const MetaEPSAction
*>(pMA
)->GetLink();
1093 const GDIMetaFile
aSubstitute( static_cast<const MetaEPSAction
*>(pMA
)->GetSubstitute() );
1095 bool bLevelConflict
= false;
1096 sal_uInt8
* pSource
= const_cast<sal_uInt8
*>(aGfxLink
.GetData());
1097 sal_uInt32 nSize
= aGfxLink
.GetDataSize();
1098 sal_uInt32 nParseThis
= POSTSCRIPT_BOUNDINGSEARCH
;
1099 if ( nSize
< 64 ) // assuming eps is larger than 64 bytes
1101 if ( nParseThis
> nSize
)
1104 if ( pSource
&& ( mnLevel
== 1 ) )
1106 sal_uInt8
* pFound
= ImplSearchEntry( pSource
, reinterpret_cast<sal_uInt8
const *>("%%LanguageLevel:"), nParseThis
- 10, 16 );
1109 sal_uInt8 k
, i
= 10;
1114 if ( ( k
> '0' ) && ( k
<= '9' ) )
1118 bLevelConflict
= true;
1119 mbLevelWarning
= true;
1126 if ( !bLevelConflict
)
1128 double nBoundingBox
[4];
1129 if ( pSource
&& ImplGetBoundingBox( nBoundingBox
, pSource
, nParseThis
) )
1131 Point aPoint
= static_cast<const MetaEPSAction
*>(pMA
)->GetPoint();
1132 Size aSize
= static_cast<const MetaEPSAction
*>(pMA
)->GetSize();
1134 MapMode
aMapMode( aSubstitute
.GetPrefMapMode() );
1135 Size
aOutSize( OutputDevice::LogicToLogic( aSize
, rVDev
.GetMapMode(), aMapMode
) );
1136 Point
aOrigin( OutputDevice::LogicToLogic( aPoint
, rVDev
.GetMapMode(), aMapMode
) );
1137 aOrigin
.AdjustY(aOutSize
.Height() );
1138 aMapMode
.SetOrigin( aOrigin
);
1139 aMapMode
.SetScaleX( Fraction(aOutSize
.Width() / ( nBoundingBox
[ 2 ] - nBoundingBox
[ 0 ] )) );
1140 aMapMode
.SetScaleY( Fraction(aOutSize
.Height() / ( nBoundingBox
[ 3 ] - nBoundingBox
[ 1 ] )) );
1141 ImplWriteLine( "gs" );
1142 ImplGetMapMode( aMapMode
);
1143 ImplWriteLine( "%%BeginDocument:" );
1144 mpPS
->WriteBytes(pSource
, aGfxLink
.GetDataSize());
1145 ImplWriteLine( "%%EndDocument\ngr" );
1151 case MetaActionType::Transparent
:
1157 case MetaActionType::RASTEROP
:
1159 pMA
->Execute( &rVDev
);
1163 case MetaActionType::FLOATTRANSPARENT
:
1165 const MetaFloatTransparentAction
* pA
= static_cast<const MetaFloatTransparentAction
*>(pMA
);
1167 GDIMetaFile
aTmpMtf( pA
->GetGDIMetaFile() );
1168 Point
aSrcPt( aTmpMtf
.GetPrefMapMode().GetOrigin() );
1169 const Size
aSrcSize( aTmpMtf
.GetPrefSize() );
1170 const Point
aDestPt( pA
->GetPoint() );
1171 const Size
aDestSize( pA
->GetSize() );
1172 const double fScaleX
= aSrcSize
.Width() ? static_cast<double>(aDestSize
.Width()) / aSrcSize
.Width() : 1.0;
1173 const double fScaleY
= aSrcSize
.Height() ? static_cast<double>(aDestSize
.Height()) / aSrcSize
.Height() : 1.0;
1174 tools::Long nMoveX
, nMoveY
;
1176 if( fScaleX
!= 1.0 || fScaleY
!= 1.0 )
1178 aTmpMtf
.Scale( fScaleX
, fScaleY
);
1179 aSrcPt
.setX(basegfx::fround
<tools::Long
>(aSrcPt
.X() * fScaleX
));
1180 aSrcPt
.setY(basegfx::fround
<tools::Long
>(aSrcPt
.Y() * fScaleY
));
1183 nMoveX
= aDestPt
.X() - aSrcPt
.X();
1184 nMoveY
= aDestPt
.Y() - aSrcPt
.Y();
1186 if( nMoveX
|| nMoveY
)
1187 aTmpMtf
.Move( nMoveX
, nMoveY
);
1189 ImplWriteActions( aTmpMtf
, rVDev
);
1193 case MetaActionType::COMMENT
:
1195 const MetaCommentAction
* pA
= static_cast<const MetaCommentAction
*>(pMA
);
1196 if ( pA
->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN") )
1198 const MetaGradientExAction
* pGradAction
= nullptr;
1199 while( ++nCurAction
< nCount
)
1201 MetaAction
* pAction
= rMtf
.GetAction( nCurAction
);
1202 if( pAction
->GetType() == MetaActionType::GRADIENTEX
)
1203 pGradAction
= static_cast<const MetaGradientExAction
*>(pAction
);
1204 else if( ( pAction
->GetType() == MetaActionType::COMMENT
) &&
1205 ( static_cast<const MetaCommentAction
*>(pAction
)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END") ) )
1212 ImplWriteGradient( pGradAction
->GetPolyPolygon(), pGradAction
->GetGradient(), rVDev
);
1214 else if ( pA
->GetComment() == "XPATHFILL_SEQ_END" )
1216 if ( aFillPath
.Count() )
1218 aFillPath
= tools::PolyPolygon();
1219 ImplWriteLine( "gr" );
1224 const sal_uInt8
* pData
= pA
->GetData();
1227 SvMemoryStream
aMemStm( const_cast<sal_uInt8
*>(pData
), pA
->GetDataSize(), StreamMode::READ
);
1228 bool bSkipSequence
= false;
1231 if( pA
->GetComment() == "XPATHSTROKE_SEQ_BEGIN" )
1233 sSeqEnd
= "XPATHSTROKE_SEQ_END"_ostr
;
1234 SvtGraphicStroke aStroke
;
1235 ReadSvtGraphicStroke( aMemStm
, aStroke
);
1237 tools::Polygon aPath
;
1238 aStroke
.getPath( aPath
);
1240 tools::PolyPolygon aStartArrow
;
1241 tools::PolyPolygon aEndArrow
;
1242 double fStrokeWidth( aStroke
.getStrokeWidth() );
1243 SvtGraphicStroke::JoinType
eJT( aStroke
.getJoinType() );
1244 SvtGraphicStroke::DashArray l_aDashArray
;
1246 aStroke
.getStartArrow( aStartArrow
);
1247 aStroke
.getEndArrow( aEndArrow
);
1248 aStroke
.getDashArray( l_aDashArray
);
1250 bSkipSequence
= true;
1251 if ( l_aDashArray
.size() > 11 ) // ps dasharray limit is 11
1252 bSkipSequence
= false;
1253 if ( aStartArrow
.Count() || aEndArrow
.Count() )
1254 bSkipSequence
= false;
1255 if ( static_cast<sal_uInt32
>(eJT
) > 2 )
1256 bSkipSequence
= false;
1257 if ( !l_aDashArray
.empty() && ( fStrokeWidth
!= 0.0 ) )
1258 bSkipSequence
= false;
1259 if ( bSkipSequence
)
1261 ImplWriteLineInfo( fStrokeWidth
, aStroke
.getMiterLimit(),
1262 aStroke
.getCapType(), eJT
, std::move(l_aDashArray
) );
1263 ImplPolyLine( aPath
);
1266 else if (pA
->GetComment() == "XPATHFILL_SEQ_BEGIN")
1268 sSeqEnd
= "XPATHFILL_SEQ_END"_ostr
;
1269 SvtGraphicFill aFill
;
1270 ReadSvtGraphicFill( aMemStm
, aFill
);
1271 switch( aFill
.getFillType() )
1273 case SvtGraphicFill::fillSolid
:
1275 bSkipSequence
= true;
1276 tools::PolyPolygon aPolyPoly
;
1277 aFill
.getPath( aPolyPoly
);
1278 sal_uInt16 i
, nPolyCount
= aPolyPoly
.Count();
1281 aFillColor
= aFill
.getFillColor();
1282 ImplWriteFillColor( PS_SPACE
);
1283 for ( i
= 0; i
< nPolyCount
; )
1285 ImplAddPath( aPolyPoly
.GetObject( i
) );
1286 if ( ++i
< nPolyCount
)
1288 mpPS
->WriteOString( "p" );
1290 ImplExecMode( PS_RET
);
1293 mpPS
->WriteOString( "p ef" );
1295 ImplExecMode( PS_RET
);
1300 case SvtGraphicFill::fillTexture
:
1302 aFill
.getPath( aFillPath
);
1304 /* normally an object filling is consisting of three MetaActions:
1305 MetaBitmapAction using RasterOp xor,
1306 MetaPolyPolygonAction using RasterOp rop_0
1307 MetaBitmapAction using RasterOp xor
1309 Because RasterOps cannot been used in Postscript, we have to
1310 replace these actions. The MetaComment "XPATHFILL_SEQ_BEGIN" is
1311 providing the clippath of the object. The following loop is
1312 trying to find the bitmap that is matching the clippath, so that
1313 only one bitmap is exported, otherwise if the bitmap is not
1314 locatable, all metaactions are played normally.
1316 sal_uInt32 nCommentStartAction
= nCurAction
;
1317 sal_uInt32 nBitmapCount
= 0;
1318 sal_uInt32 nBitmapAction
= 0;
1321 while( bOk
&& ( ++nCurAction
< nCount
) )
1323 MetaAction
* pAction
= rMtf
.GetAction( nCurAction
);
1324 switch( pAction
->GetType() )
1326 case MetaActionType::BMPSCALE
:
1327 case MetaActionType::BMPSCALEPART
:
1328 case MetaActionType::BMPEXSCALE
:
1329 case MetaActionType::BMPEXSCALEPART
:
1332 nBitmapAction
= nCurAction
;
1335 case MetaActionType::COMMENT
:
1337 if (static_cast<const MetaCommentAction
*>(pAction
)->GetComment() == "XPATHFILL_SEQ_END")
1344 if( nBitmapCount
== 2 )
1346 ImplWriteLine( "gs" );
1347 ImplIntersect( aFillPath
);
1348 GDIMetaFile aTempMtf
;
1349 aTempMtf
.AddAction( rMtf
.GetAction( nBitmapAction
)->Clone() );
1350 ImplWriteActions( aTempMtf
, rVDev
);
1351 ImplWriteLine( "gr" );
1352 aFillPath
= tools::PolyPolygon();
1355 nCurAction
= nCommentStartAction
+ 1;
1359 case SvtGraphicFill::fillGradient
:
1360 aFill
.getPath( aFillPath
);
1363 case SvtGraphicFill::fillHatch
:
1366 if ( aFillPath
.Count() )
1368 ImplWriteLine( "gs" );
1369 ImplIntersect( aFillPath
);
1372 if ( bSkipSequence
)
1374 while( ++nCurAction
< nCount
)
1376 pMA
= rMtf
.GetAction( nCurAction
);
1377 if ( pMA
->GetType() == MetaActionType::COMMENT
)
1379 OString
sComment( static_cast<MetaCommentAction
*>(pMA
)->GetComment() );
1380 if ( sComment
== sSeqEnd
)
1394 inline void PSWriter::ImplWritePoint( const Point
& rPoint
)
1396 ImplWriteDouble( rPoint
.X() );
1397 ImplWriteDouble( rPoint
.Y() );
1400 void PSWriter::ImplMoveTo( const Point
& rPoint
)
1402 ImplWritePoint( rPoint
);
1403 ImplWriteByte( 'm' );
1404 ImplExecMode( PS_SPACE
);
1407 void PSWriter::ImplLineTo( const Point
& rPoint
, NMode nMode
)
1409 ImplWritePoint( rPoint
);
1410 ImplWriteByte( 'l' );
1411 ImplExecMode( nMode
);
1414 void PSWriter::ImplCurveTo( const Point
& rP1
, const Point
& rP2
, const Point
& rP3
, NMode nMode
)
1416 ImplWritePoint( rP1
);
1417 ImplWritePoint( rP2
);
1418 ImplWritePoint( rP3
);
1419 mpPS
->WriteOString( "ct " );
1420 ImplExecMode( nMode
);
1423 void PSWriter::ImplTranslate( const double& fX
, const double& fY
)
1425 ImplWriteDouble( fX
);
1426 ImplWriteDouble( fY
);
1427 ImplWriteByte( 't' );
1428 ImplExecMode( PS_RET
);
1431 void PSWriter::ImplScale( const double& fX
, const double& fY
)
1433 ImplWriteDouble( fX
);
1434 ImplWriteDouble( fY
);
1435 ImplWriteByte( 's' );
1436 ImplExecMode( PS_RET
);
1439 void PSWriter::ImplRect( const tools::Rectangle
& rRect
)
1442 ImplRectFill( rRect
);
1445 double nWidth
= rRect
.GetWidth();
1446 double nHeight
= rRect
.GetHeight();
1448 ImplWriteLineColor( PS_SPACE
);
1449 ImplMoveTo( rRect
.TopLeft() );
1450 ImplWriteDouble( nWidth
);
1451 mpPS
->WriteOString( "0 rl 0 " );
1452 ImplWriteDouble( nHeight
);
1453 mpPS
->WriteOString( "rl " );
1454 ImplWriteDouble( nWidth
);
1455 mpPS
->WriteOString( "neg 0 rl " );
1456 ImplClosePathDraw();
1458 mpPS
->WriteUChar( 10 );
1462 void PSWriter::ImplRectFill( const tools::Rectangle
& rRect
)
1464 double nWidth
= rRect
.GetWidth();
1465 double nHeight
= rRect
.GetHeight();
1467 ImplWriteFillColor( PS_SPACE
);
1468 ImplMoveTo( rRect
.TopLeft() );
1469 ImplWriteDouble( nWidth
);
1470 mpPS
->WriteOString( "0 rl 0 " );
1471 ImplWriteDouble( nHeight
);
1472 mpPS
->WriteOString( "rl " );
1473 ImplWriteDouble( nWidth
);
1474 mpPS
->WriteOString( "neg 0 rl ef " );
1475 mpPS
->WriteOString( "p ef" );
1477 ImplExecMode( PS_RET
);
1480 void PSWriter::ImplAddPath( const tools::Polygon
& rPolygon
)
1482 sal_uInt16 nPointCount
= rPolygon
.GetSize();
1483 if ( nPointCount
<= 1 )
1487 ImplMoveTo( rPolygon
.GetPoint( 0 ) );
1488 while ( i
< nPointCount
)
1490 if ( ( rPolygon
.GetFlags( i
) == PolyFlags::Control
)
1491 && ( ( i
+ 2 ) < nPointCount
)
1492 && ( rPolygon
.GetFlags( i
+ 1 ) == PolyFlags::Control
)
1493 && ( rPolygon
.GetFlags( i
+ 2 ) != PolyFlags::Control
) )
1495 ImplCurveTo( rPolygon
[ i
], rPolygon
[ i
+ 1 ], rPolygon
[ i
+ 2 ], PS_WRAP
);
1499 ImplLineTo( rPolygon
.GetPoint( i
++ ), PS_SPACE
| PS_WRAP
);
1503 void PSWriter::ImplIntersect( const tools::PolyPolygon
& rPolyPoly
)
1505 sal_uInt16 i
, nPolyCount
= rPolyPoly
.Count();
1506 for ( i
= 0; i
< nPolyCount
; )
1508 ImplAddPath( rPolyPoly
.GetObject( i
) );
1509 if ( ++i
< nPolyCount
)
1511 mpPS
->WriteOString( "p" );
1513 ImplExecMode( PS_RET
);
1516 ImplWriteLine( "eoclip newpath" );
1519 void PSWriter::ImplWriteGradient( const tools::PolyPolygon
& rPolyPoly
, const Gradient
& rGradient
, VirtualDevice
& rVDev
)
1521 ScopedVclPtrInstance
< VirtualDevice
> l_pVDev
;
1522 GDIMetaFile aTmpMtf
;
1523 l_pVDev
->SetMapMode( rVDev
.GetMapMode() );
1524 Gradient
aGradient(rGradient
);
1525 aGradient
.AddGradientActions( rPolyPoly
.GetBoundRect(), aTmpMtf
);
1526 ImplWriteActions( aTmpMtf
, rVDev
);
1529 void PSWriter::ImplPolyPoly( const tools::PolyPolygon
& rPolyPoly
, bool bTextOutline
)
1531 sal_uInt16 i
, nPolyCount
= rPolyPoly
.Count();
1535 if ( bFillColor
|| bTextOutline
)
1538 ImplWriteTextColor( PS_SPACE
);
1540 ImplWriteFillColor( PS_SPACE
);
1541 for ( i
= 0; i
< nPolyCount
; )
1543 ImplAddPath( rPolyPoly
.GetObject( i
) );
1544 if ( ++i
< nPolyCount
)
1546 mpPS
->WriteOString( "p" );
1548 ImplExecMode( PS_RET
);
1551 mpPS
->WriteOString( "p ef" );
1553 ImplExecMode( PS_RET
);
1557 ImplWriteLineColor( PS_SPACE
);
1558 for ( i
= 0; i
< nPolyCount
; i
++ )
1559 ImplAddPath( rPolyPoly
.GetObject( i
) );
1560 ImplClosePathDraw();
1564 void PSWriter::ImplPolyLine( const tools::Polygon
& rPoly
)
1569 ImplWriteLineColor( PS_SPACE
);
1570 sal_uInt16 i
, nPointCount
= rPoly
.GetSize();
1574 if ( nPointCount
> 1 )
1576 ImplMoveTo( rPoly
.GetPoint( 0 ) );
1578 while ( i
< nPointCount
)
1580 if ( ( rPoly
.GetFlags( i
) == PolyFlags::Control
)
1581 && ( ( i
+ 2 ) < nPointCount
)
1582 && ( rPoly
.GetFlags( i
+ 1 ) == PolyFlags::Control
)
1583 && ( rPoly
.GetFlags( i
+ 2 ) != PolyFlags::Control
) )
1585 ImplCurveTo( rPoly
[ i
], rPoly
[ i
+ 1 ], rPoly
[ i
+ 2 ], PS_WRAP
);
1589 ImplLineTo( rPoly
.GetPoint( i
++ ), PS_SPACE
| PS_WRAP
);
1593 // #104645# explicitly close path if polygon is closed
1594 if( rPoly
[ 0 ] == rPoly
[ nPointCount
-1 ] )
1595 ImplClosePathDraw();
1600 void PSWriter::ImplSetClipRegion( vcl::Region
const & rClipRegion
)
1602 if ( rClipRegion
.IsEmpty() )
1605 RectangleVector aRectangles
;
1606 rClipRegion
.GetRegionRectangles(aRectangles
);
1608 for (auto const& rectangle
: aRectangles
)
1610 double nX1(rectangle
.Left());
1611 double nY1(rectangle
.Top());
1612 double nX2(rectangle
.Right());
1613 double nY2(rectangle
.Bottom());
1615 ImplWriteDouble( nX1
);
1616 ImplWriteDouble( nY1
);
1617 ImplWriteByte( 'm' );
1618 ImplWriteDouble( nX2
);
1619 ImplWriteDouble( nY1
);
1620 ImplWriteByte( 'l' );
1621 ImplWriteDouble( nX2
);
1622 ImplWriteDouble( nY2
);
1623 ImplWriteByte( 'l' );
1624 ImplWriteDouble( nX1
);
1625 ImplWriteDouble( nY2
);
1626 ImplWriteByte( 'l' );
1627 ImplWriteDouble( nX1
);
1628 ImplWriteDouble( nY1
);
1629 ImplWriteByte( 'l', PS_SPACE
| PS_WRAP
);
1632 ImplWriteLine( "eoclip newpath" );
1635 // possible gfx formats:
1637 // level 1: grayscale 8 bit
1640 // level 2: grayscale 8 bit
1641 // color 1(pal), 4(pal), 8(pal), 24 Bit
1644 void PSWriter::ImplBmp( Bitmap
const * pBitmap
, AlphaMask
const * pAlphaMaskBitmap
, const Point
& rPoint
, double nXWidth
, double nYHeightOrg
)
1649 sal_Int32 nHeightOrg
= pBitmap
->GetSizePixel().Height();
1650 sal_Int32 nHeightLeft
= nHeightOrg
;
1651 tools::Long nWidth
= pBitmap
->GetSizePixel().Width();
1652 Point
aSourcePos( rPoint
);
1654 while ( nHeightLeft
)
1656 Bitmap
aTileBitmap( *pBitmap
);
1657 tools::Long nHeight
= nHeightLeft
;
1658 double nYHeight
= nYHeightOrg
;
1660 bool bDoTrans
= false;
1662 tools::Rectangle aRect
;
1663 vcl::Region aRegion
;
1665 if ( pAlphaMaskBitmap
)
1670 if ( mnLevel
== 1 && nHeight
> 10 )
1672 aRect
= tools::Rectangle( Point( 0, nHeightOrg
- nHeightLeft
), Size( nWidth
, nHeight
) );
1673 aRegion
= pAlphaMaskBitmap
->CreateRegion( COL_ALPHA_OPAQUE
, aRect
);
1677 RectangleVector aRectangleVector
;
1678 aRegion
.GetRegionRectangles(aRectangleVector
);
1680 if ( aRectangleVector
.size() * 5 > 1000 )
1691 if ( nHeight
!= nHeightOrg
)
1693 nYHeight
= nYHeightOrg
* nHeight
/ nHeightOrg
;
1694 aTileBitmap
.Crop( tools::Rectangle( Point( 0, nHeightOrg
- nHeightLeft
), Size( nWidth
, nHeight
) ) );
1698 ImplWriteLine( "gs\npum" );
1699 ImplTranslate( aSourcePos
.X(), aSourcePos
.Y() );
1700 ImplScale( nXWidth
/ nWidth
, nYHeight
/ nHeight
);
1702 RectangleVector aRectangles
;
1703 aRegion
.GetRegionRectangles(aRectangles
);
1704 const tools::Long
nMoveVertical(nHeightLeft
- nHeightOrg
);
1706 for (auto & rectangle
: aRectangles
)
1708 rectangle
.Move(0, nMoveVertical
);
1710 ImplWriteLong( rectangle
.Left() );
1711 ImplWriteLong( rectangle
.Top() );
1712 ImplWriteByte( 'm' );
1713 ImplWriteLong( rectangle
.Right() + 1 );
1714 ImplWriteLong( rectangle
.Top() );
1715 ImplWriteByte( 'l' );
1716 ImplWriteLong( rectangle
.Right() + 1 );
1717 ImplWriteLong( rectangle
.Bottom() + 1 );
1718 ImplWriteByte( 'l' );
1719 ImplWriteLong( rectangle
.Left() );
1720 ImplWriteLong( rectangle
.Bottom() + 1 );
1721 ImplWriteByte( 'l' );
1722 ImplWriteByte( 'p', PS_SPACE
| PS_WRAP
);
1725 ImplWriteLine( "eoclip newpath" );
1726 ImplWriteLine( "pom" );
1728 BitmapScopedReadAccess
pAcc(aTileBitmap
);
1731 ImplWriteLine( "pum" );
1733 ImplTranslate( aSourcePos
.X(), aSourcePos
.Y() + nYHeight
);
1734 ImplScale( nXWidth
, nYHeight
);
1735 if ( mnLevel
== 1 ) // level 1 is always grayscale !!!
1737 ImplWriteLong( nWidth
);
1738 ImplWriteLong( nHeight
);
1739 mpPS
->WriteOString( "8 [" );
1740 ImplWriteLong( nWidth
);
1741 mpPS
->WriteOString( "0 0 " );
1742 ImplWriteLong( -nHeight
);
1744 ImplWriteLong( nHeight
);
1745 ImplWriteLine( "]" );
1746 mpPS
->WriteOString( "{currentfile " );
1747 ImplWriteLong( nWidth
);
1748 ImplWriteLine( "string readhexstring pop}" );
1749 ImplWriteLine( "image" );
1750 for ( tools::Long y
= 0; y
< nHeight
; y
++ )
1752 Scanline pScanlineRead
= pAcc
->GetScanline( y
);
1753 for ( tools::Long x
= 0; x
< nWidth
; x
++ )
1755 ImplWriteHexByte( pAcc
->GetIndexFromData( pScanlineRead
, x
) );
1758 mpPS
->WriteUChar( 10 );
1764 ImplWriteLine( "/DeviceGray setcolorspace" );
1765 ImplWriteLine( "<<" );
1766 ImplWriteLine( "/ImageType 1" );
1767 mpPS
->WriteOString( "/Width " );
1768 ImplWriteLong( nWidth
, PS_RET
);
1769 mpPS
->WriteOString( "/Height " );
1770 ImplWriteLong( nHeight
, PS_RET
);
1771 ImplWriteLine( "/BitsPerComponent 8" );
1772 ImplWriteLine( "/Decode[0 1]" );
1773 mpPS
->WriteOString( "/ImageMatrix[" );
1774 ImplWriteLong( nWidth
);
1775 mpPS
->WriteOString( "0 0 " );
1776 ImplWriteLong( -nHeight
);
1778 ImplWriteLong( nHeight
, PS_NONE
);
1779 ImplWriteByte( ']', PS_RET
);
1780 ImplWriteLine( "/DataSource currentfile" );
1781 ImplWriteLine( "/ASCIIHexDecode filter" );
1782 if ( mbCompression
)
1783 ImplWriteLine( "/LZWDecode filter" );
1784 ImplWriteLine( ">>" );
1785 ImplWriteLine( "image" );
1786 if ( mbCompression
)
1789 for ( tools::Long y
= 0; y
< nHeight
; y
++ )
1791 Scanline pScanlineRead
= pAcc
->GetScanline( y
);
1792 for ( tools::Long x
= 0; x
< nWidth
; x
++ )
1794 Compress( pAcc
->GetIndexFromData( pScanlineRead
, x
) );
1801 for ( tools::Long y
= 0; y
< nHeight
; y
++ )
1803 Scanline pScanlineRead
= pAcc
->GetScanline( y
);
1804 for ( tools::Long x
= 0; x
< nWidth
; x
++ )
1806 ImplWriteHexByte( pAcc
->GetIndexFromData( pScanlineRead
, x
) );
1813 // have we to write a palette ?
1815 if ( pAcc
->HasPalette() )
1817 ImplWriteLine( "[/Indexed /DeviceRGB " );
1818 ImplWriteLong( pAcc
->GetPaletteEntryCount() - 1, PS_RET
);
1819 ImplWriteByte( '<', PS_NONE
);
1820 for ( sal_uInt16 i
= 0; i
< pAcc
->GetPaletteEntryCount(); i
++ )
1822 BitmapColor aBitmapColor
= pAcc
->GetPaletteColor( i
);
1823 ImplWriteHexByte( aBitmapColor
.GetRed(), PS_NONE
);
1824 ImplWriteHexByte( aBitmapColor
.GetGreen(), PS_NONE
);
1825 ImplWriteHexByte( aBitmapColor
.GetBlue(), PS_SPACE
| PS_WRAP
);
1827 ImplWriteByte( '>', PS_RET
);
1829 ImplWriteLine( "] setcolorspace" );
1830 ImplWriteLine( "<<" );
1831 ImplWriteLine( "/ImageType 1" );
1832 mpPS
->WriteOString( "/Width " );
1833 ImplWriteLong( nWidth
, PS_RET
);
1834 mpPS
->WriteOString( "/Height " );
1835 ImplWriteLong( nHeight
, PS_RET
);
1836 ImplWriteLine( "/BitsPerComponent 8" );
1837 ImplWriteLine( "/Decode[0 255]" );
1838 mpPS
->WriteOString( "/ImageMatrix[" );
1839 ImplWriteLong( nWidth
);
1840 mpPS
->WriteOString( "0 0 " );
1841 ImplWriteLong( -nHeight
);
1843 ImplWriteLong( nHeight
, PS_NONE
);
1844 ImplWriteByte( ']', PS_RET
);
1845 ImplWriteLine( "/DataSource currentfile" );
1846 ImplWriteLine( "/ASCIIHexDecode filter" );
1847 if ( mbCompression
)
1848 ImplWriteLine( "/LZWDecode filter" );
1849 ImplWriteLine( ">>" );
1850 ImplWriteLine( "image" );
1851 if ( mbCompression
)
1854 for ( tools::Long y
= 0; y
< nHeight
; y
++ )
1856 Scanline pScanlineRead
= pAcc
->GetScanline( y
);
1857 for ( tools::Long x
= 0; x
< nWidth
; x
++ )
1859 Compress( pAcc
->GetIndexFromData( pScanlineRead
, x
) );
1866 for ( tools::Long y
= 0; y
< nHeight
; y
++ )
1868 Scanline pScanlineRead
= pAcc
->GetScanline( y
);
1869 for ( tools::Long x
= 0; x
< nWidth
; x
++ )
1871 ImplWriteHexByte( pAcc
->GetIndexFromData( pScanlineRead
, x
) );
1876 else // 24 bit color
1878 ImplWriteLine( "/DeviceRGB setcolorspace" );
1879 ImplWriteLine( "<<" );
1880 ImplWriteLine( "/ImageType 1" );
1881 mpPS
->WriteOString( "/Width " );
1882 ImplWriteLong( nWidth
, PS_RET
);
1883 mpPS
->WriteOString( "/Height " );
1884 ImplWriteLong( nHeight
, PS_RET
);
1885 ImplWriteLine( "/BitsPerComponent 8" );
1886 ImplWriteLine( "/Decode[0 1 0 1 0 1]" );
1887 mpPS
->WriteOString( "/ImageMatrix[" );
1888 ImplWriteLong( nWidth
);
1889 mpPS
->WriteOString( "0 0 " );
1890 ImplWriteLong( -nHeight
);
1892 ImplWriteLong( nHeight
, PS_NONE
);
1893 ImplWriteByte( ']', PS_RET
);
1894 ImplWriteLine( "/DataSource currentfile" );
1895 ImplWriteLine( "/ASCIIHexDecode filter" );
1896 if ( mbCompression
)
1897 ImplWriteLine( "/LZWDecode filter" );
1898 ImplWriteLine( ">>" );
1899 ImplWriteLine( "image" );
1900 if ( mbCompression
)
1903 for ( tools::Long y
= 0; y
< nHeight
; y
++ )
1905 Scanline pScanlineRead
= pAcc
->GetScanline( y
);
1906 for ( tools::Long x
= 0; x
< nWidth
; x
++ )
1908 const BitmapColor
aBitmapColor( pAcc
->GetPixelFromData( pScanlineRead
, x
) );
1909 Compress( aBitmapColor
.GetRed() );
1910 Compress( aBitmapColor
.GetGreen() );
1911 Compress( aBitmapColor
.GetBlue() );
1918 for ( tools::Long y
= 0; y
< nHeight
; y
++ )
1920 Scanline pScanline
= pAcc
->GetScanline( y
);
1921 for ( tools::Long x
= 0; x
< nWidth
; x
++ )
1923 const BitmapColor
aBitmapColor( pAcc
->GetPixelFromData( pScanline
, x
) );
1924 ImplWriteHexByte( aBitmapColor
.GetRed() );
1925 ImplWriteHexByte( aBitmapColor
.GetGreen() );
1926 ImplWriteHexByte( aBitmapColor
.GetBlue() );
1932 ImplWriteLine( ">" ); // in Level 2 the dictionary needs to be closed (eod)
1935 ImplWriteLine( "gr" );
1937 ImplWriteLine( "pom" );
1940 nHeightLeft
-= nHeight
;
1944 aSourcePos
.setY( static_cast<tools::Long
>( rPoint
.Y() + ( nYHeightOrg
* ( nHeightOrg
- nHeightLeft
) ) / nHeightOrg
) );
1949 void PSWriter::ImplWriteCharacter( char nChar
)
1956 ImplWriteByte( sal_uInt8('\\'), PS_NONE
);
1958 ImplWriteByte( static_cast<sal_uInt8
>(nChar
), PS_NONE
);
1961 void PSWriter::ImplWriteString( const OString
& rString
, VirtualDevice
const & rVDev
, KernArraySpan pDXArry
, bool bStretch
)
1963 sal_Int32 nLen
= rString
.getLength();
1967 if ( !pDXArry
.empty() )
1971 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
1974 nx
= pDXArry
[ i
- 1 ];
1975 ImplWriteDouble( bStretch
? nx
: rVDev
.GetTextWidth( OUString(rString
[i
]) ) );
1976 ImplWriteDouble( nx
);
1977 ImplWriteLine( "(", PS_NONE
);
1978 ImplWriteCharacter( rString
[i
] );
1979 ImplWriteLine( ") bs" );
1984 ImplWriteByte( '(', PS_NONE
);
1985 for (sal_Int32 i
= 0; i
< nLen
; ++i
)
1986 ImplWriteCharacter( rString
[i
] );
1987 ImplWriteLine( ") sw" );
1991 void PSWriter::ImplText( const OUString
& rUniString
, const Point
& rPos
, KernArraySpan pDXArry
, std::span
<const sal_Bool
> pKashidaArry
, sal_Int32 nWidth
, VirtualDevice
const & rVDev
)
1993 if ( rUniString
.isEmpty() )
1995 if ( mnTextMode
== 0 ) // using glyph outlines
1997 vcl::Font
aNotRotatedFont( maFont
);
1998 aNotRotatedFont
.SetOrientation( 0_deg10
);
2000 ScopedVclPtrInstance
< VirtualDevice
> pVirDev(DeviceFormat::WITHOUT_ALPHA
);
2001 pVirDev
->SetMapMode( rVDev
.GetMapMode() );
2002 pVirDev
->SetFont( aNotRotatedFont
);
2003 pVirDev
->SetTextAlign( eTextAlign
);
2005 Degree10 nRotation
= maFont
.GetOrientation();
2006 tools::Polygon
aPolyDummy( 1 );
2011 aPolyDummy
.SetPoint( aPos
, 0 );
2012 aPolyDummy
.Rotate( rPos
, nRotation
);
2013 aPos
= aPolyDummy
.GetPoint( 0 );
2015 bool bOldLineColor
= bLineColor
;
2017 std::vector
<tools::PolyPolygon
> aPolyPolyVec
;
2018 if ( pVirDev
->GetTextOutlines( aPolyPolyVec
, rUniString
, 0, 0, -1, nWidth
, pDXArry
, pKashidaArry
) )
2020 // always adjust text position to match baseline alignment
2021 ImplWriteLine( "pum" );
2022 ImplWriteDouble( aPos
.X() );
2023 ImplWriteDouble( aPos
.Y() );
2024 ImplWriteLine( "t" );
2027 ImplWriteF( nRotation
.get(), 1 );
2028 mpPS
->WriteOString( "r " );
2030 for (auto const& elem
: aPolyPolyVec
)
2031 ImplPolyPoly( elem
, true );
2032 ImplWriteLine( "pom" );
2034 bLineColor
= bOldLineColor
;
2036 else if ( ( mnTextMode
== 1 ) || ( mnTextMode
== 2 ) ) // normal text output
2038 if ( mnTextMode
== 2 ) // forcing output one complete text packet, by
2039 pDXArry
= {}; // ignoring the kerning array
2040 ImplSetAttrForText( rPos
);
2041 OString
aStr(OUStringToOString(rUniString
,
2042 maFont
.GetCharSet()));
2043 ImplWriteString( aStr
, rVDev
, pDXArry
, nWidth
!= 0 );
2044 if ( maFont
.GetOrientation() )
2045 ImplWriteLine( "gr" );
2049 void PSWriter::ImplSetAttrForText( const Point
& rPoint
)
2051 Point
aPoint( rPoint
);
2053 Degree10 nRotation
= maFont
.GetOrientation();
2054 ImplWriteTextColor(PS_RET
);
2056 Size aSize
= maFont
.GetFontSize();
2058 if ( maLastFont
!= maFont
)
2060 if ( maFont
.GetPitch() == PITCH_FIXED
) // a little bit font selection
2061 ImplDefineFont( "Courier", "Oblique" );
2062 else if ( maFont
.GetCharSet() == RTL_TEXTENCODING_SYMBOL
)
2063 ImplWriteLine( "/Symbol findfont" );
2064 else if ( maFont
.GetFamilyType() == FAMILY_SWISS
)
2065 ImplDefineFont( "Helvetica", "Oblique" );
2067 ImplDefineFont( "Times", "Italic" );
2069 maLastFont
= maFont
;
2070 aSize
= maFont
.GetFontSize();
2071 ImplWriteDouble( aSize
.Height() );
2072 mpPS
->WriteOString( "sf " );
2074 if ( eTextAlign
!= ALIGN_BASELINE
)
2075 { // PostScript does not know about FontAlignment
2076 if ( eTextAlign
== ALIGN_TOP
) // -> so I assume that
2077 aPoint
.AdjustY( aSize
.Height() * 4 / 5 ); // the area under the baseline
2078 else if ( eTextAlign
== ALIGN_BOTTOM
) // is about 20% of the font size
2079 aPoint
.AdjustY( -( aSize
.Height() / 5 ) );
2081 ImplMoveTo( aPoint
);
2084 mpPS
->WriteOString( "gs " );
2085 ImplWriteF( nRotation
.get(), 1 );
2086 mpPS
->WriteOString( "r " );
2090 void PSWriter::ImplDefineFont( const char* pOriginalName
, const char* pItalic
)
2092 mpPS
->WriteUChar( '/' ); //convert the font pOriginalName using ISOLatin1Encoding
2093 mpPS
->WriteOString( pOriginalName
);
2094 switch ( maFont
.GetWeight() )
2096 case WEIGHT_SEMIBOLD
:
2098 case WEIGHT_ULTRABOLD
:
2100 mpPS
->WriteOString( "-Bold" );
2101 if ( maFont
.GetItalic() != ITALIC_NONE
)
2102 mpPS
->WriteOString( pItalic
);
2105 if ( maFont
.GetItalic() != ITALIC_NONE
)
2106 mpPS
->WriteOString( pItalic
);
2109 ImplWriteLine( " f" );
2112 void PSWriter::ImplClosePathDraw()
2114 mpPS
->WriteOString( "pc" );
2116 ImplExecMode( PS_RET
);
2119 void PSWriter::ImplPathDraw()
2121 mpPS
->WriteOString( "ps" );
2123 ImplExecMode( PS_RET
);
2127 inline void PSWriter::ImplWriteLineColor( NMode nMode
)
2129 if ( aColor
!= aLineColor
)
2131 aColor
= aLineColor
;
2132 ImplWriteColor( nMode
);
2136 inline void PSWriter::ImplWriteFillColor( NMode nMode
)
2138 if ( aColor
!= aFillColor
)
2140 aColor
= aFillColor
;
2141 ImplWriteColor( nMode
);
2145 inline void PSWriter::ImplWriteTextColor( NMode nMode
)
2147 if ( aColor
!= aTextColor
)
2149 aColor
= aTextColor
;
2150 ImplWriteColor( nMode
);
2154 void PSWriter::ImplWriteColor( NMode nMode
)
2158 // writes the Color (grayscale) as a Number from 0.000 up to 1.000
2160 ImplWriteF( 1000 * ( aColor
.GetRed() * 77 + aColor
.GetGreen() * 151 +
2161 aColor
.GetBlue() * 28 + 1 ) / 65536, 3, nMode
);
2165 ImplWriteB1 ( aColor
.GetRed() );
2166 ImplWriteB1 ( aColor
.GetGreen() );
2167 ImplWriteB1 ( aColor
.GetBlue() );
2169 mpPS
->WriteOString( "c" ); // ( c is defined as setrgbcolor or setgray )
2170 ImplExecMode( nMode
);
2173 void PSWriter::ImplGetMapMode( const MapMode
& rMapMode
)
2175 ImplWriteLine( "tm setmatrix" );
2176 double fScaleX(rMapMode
.GetScaleX());
2177 double fScaleY(rMapMode
.GetScaleY());
2178 if (o3tl::Length l
= MapToO3tlLength(rMapMode
.GetMapUnit(), o3tl::Length::invalid
);
2179 l
!= o3tl::Length::invalid
)
2181 fScaleX
= o3tl::convert(fScaleX
, l
, o3tl::Length::mm100
);
2182 fScaleY
= o3tl::convert(fScaleY
, l
, o3tl::Length::mm100
);
2184 ImplTranslate( rMapMode
.GetOrigin().X() * fScaleX
, rMapMode
.GetOrigin().Y() * fScaleY
);
2185 ImplScale( fScaleX
, fScaleY
);
2188 inline void PSWriter::ImplExecMode( NMode nMode
)
2190 if ( nMode
& PS_WRAP
)
2192 if ( mnCursorPos
>= PS_LINESIZE
)
2195 mpPS
->WriteUChar( 0xa );
2199 if ( nMode
& PS_SPACE
)
2201 mpPS
->WriteUChar( 32 );
2204 if ( nMode
& PS_RET
)
2206 mpPS
->WriteUChar( 0xa );
2211 inline void PSWriter::ImplWriteLine( const char* pString
, NMode nMode
)
2214 while ( pString
[ i
] )
2216 mpPS
->WriteUChar( pString
[ i
++ ] );
2219 ImplExecMode( nMode
);
2222 void PSWriter::ImplWriteLineInfo( double fLWidth
, double fMLimit
,
2223 SvtGraphicStroke::CapType eLCap
,
2224 SvtGraphicStroke::JoinType eJoin
,
2225 SvtGraphicStroke::DashArray
&& rLDash
)
2227 if ( fLineWidth
!= fLWidth
)
2229 fLineWidth
= fLWidth
;
2230 ImplWriteDouble( fLineWidth
);
2231 ImplWriteLine( "lw", PS_SPACE
);
2233 if ( eLineCap
!= eLCap
)
2236 ImplWriteLong( static_cast<sal_Int32
>(eLineCap
) );
2237 ImplWriteLine( "lc", PS_SPACE
);
2239 if ( eJoinType
!= eJoin
)
2242 ImplWriteLong( static_cast<sal_Int32
>(eJoinType
) );
2243 ImplWriteLine( "lj", PS_SPACE
);
2245 if ( eJoinType
== SvtGraphicStroke::joinMiter
)
2247 if ( fMiterLimit
!= fMLimit
)
2249 fMiterLimit
= fMLimit
;
2250 ImplWriteDouble( fMiterLimit
);
2251 ImplWriteLine( "ml", PS_SPACE
);
2254 if ( aDashArray
!= rLDash
)
2256 aDashArray
= std::move(rLDash
);
2257 sal_uInt32 j
, i
= aDashArray
.size();
2258 ImplWriteLine( "[", PS_SPACE
);
2259 for ( j
= 0; j
< i
; j
++ )
2260 ImplWriteDouble( aDashArray
[ j
] );
2261 ImplWriteLine( "] 0 ld" );
2265 void PSWriter::ImplWriteLineInfo( const LineInfo
& rLineInfo
)
2267 std::vector
< double > l_aDashArray
;
2268 if ( rLineInfo
.GetStyle() == LineStyle::Dash
)
2269 l_aDashArray
= rLineInfo
.GetDotDashArray();
2270 const double fLWidth(( ( rLineInfo
.GetWidth() + 1 ) + ( rLineInfo
.GetWidth() + 1 ) ) * 0.5);
2271 SvtGraphicStroke::JoinType
aJoinType(SvtGraphicStroke::joinMiter
);
2272 SvtGraphicStroke::CapType
aCapType(SvtGraphicStroke::capButt
);
2274 switch(rLineInfo
.GetLineJoin())
2276 case basegfx::B2DLineJoin::NONE
:
2277 // do NOT use SvtGraphicStroke::joinNone here
2278 // since it will be written as numerical value directly
2279 // and is NOT a valid EPS value
2281 case basegfx::B2DLineJoin::Miter
:
2282 aJoinType
= SvtGraphicStroke::joinMiter
;
2284 case basegfx::B2DLineJoin::Bevel
:
2285 aJoinType
= SvtGraphicStroke::joinBevel
;
2287 case basegfx::B2DLineJoin::Round
:
2288 aJoinType
= SvtGraphicStroke::joinRound
;
2291 switch(rLineInfo
.GetLineCap())
2293 default: /* css::drawing::LineCap_BUTT */
2295 aCapType
= SvtGraphicStroke::capButt
;
2298 case css::drawing::LineCap_ROUND
:
2300 aCapType
= SvtGraphicStroke::capRound
;
2303 case css::drawing::LineCap_SQUARE
:
2305 aCapType
= SvtGraphicStroke::capSquare
;
2310 ImplWriteLineInfo( fLWidth
, fMiterLimit
, aCapType
, aJoinType
, std::move(l_aDashArray
) );
2313 void PSWriter::ImplWriteLong(sal_Int32 nNumber
, NMode nMode
)
2315 const OString
aNumber(OString::number(nNumber
));
2316 mnCursorPos
+= aNumber
.getLength();
2317 mpPS
->WriteOString( aNumber
);
2318 ImplExecMode(nMode
);
2321 void PSWriter::ImplWriteDouble( double fNumber
)
2323 sal_Int32 nPTemp
= static_cast<sal_Int32
>(fNumber
);
2324 sal_Int32 nATemp
= std::abs( static_cast<sal_Int32
>( ( fNumber
- nPTemp
) * 100000 ) );
2326 if ( !nPTemp
&& nATemp
&& ( fNumber
< 0.0 ) )
2327 mpPS
->WriteChar( '-' );
2329 const OString
aNumber1(OString::number(nPTemp
));
2330 mpPS
->WriteOString( aNumber1
);
2331 mnCursorPos
+= aNumber1
.getLength();
2336 mpPS
->WriteUChar( '.' );
2338 const OString
aNumber2(OString::number(nATemp
));
2340 sal_Int16 n
, nLen
= aNumber2
.getLength();
2343 mnCursorPos
+= 6 - nLen
;
2344 for ( n
= 0; n
< ( 5 - nLen
); n
++ )
2346 mpPS
->WriteUChar( '0' );
2349 mnCursorPos
+= nLen
;
2350 for ( n
= 0; n
< nLen
; n
++ )
2352 mpPS
->WriteChar( aNumber2
[n
] );
2354 if ( aNumber2
[n
] != '0' )
2358 mpPS
->SeekRel( zCount
);
2360 ImplExecMode( PS_SPACE
);
2363 /// Writes the number to stream: nNumber / ( 10^nCount )
2364 void PSWriter::ImplWriteF( sal_Int32 nNumber
, sal_uInt8 nCount
, NMode nMode
)
2368 mpPS
->WriteUChar( '-' );
2372 const OString
aScaleFactor(OString::number(nNumber
));
2373 sal_uInt32 nLen
= aScaleFactor
.getLength();
2374 sal_Int32
const nStSize
= (nCount
+ 1) - nLen
;
2375 static_assert(sizeof(nStSize
) == sizeof((nCount
+ 1) - nLen
)); // tdf#134667
2378 mpPS
->WriteUChar( '0' );
2383 mpPS
->WriteUChar( '.' );
2384 for (sal_Int32 i
= 1; i
< nStSize
; ++i
)
2386 mpPS
->WriteUChar( '0' );
2390 mnCursorPos
+= nLen
;
2391 for( sal_uInt32 n
= 0; n
< nLen
; n
++ )
2393 if ( n
== nLen
- nCount
)
2395 mpPS
->WriteUChar( '.' );
2398 mpPS
->WriteChar( aScaleFactor
[n
] );
2400 ImplExecMode( nMode
);
2403 void PSWriter::ImplWriteByte( sal_uInt8 nNumb
, NMode nMode
)
2405 mpPS
->WriteUChar( nNumb
);
2407 ImplExecMode( nMode
);
2410 void PSWriter::ImplWriteHexByte( sal_uInt8 nNumb
, NMode nMode
)
2412 if ( ( nNumb
>> 4 ) > 9 )
2413 mpPS
->WriteUChar( ( nNumb
>> 4 ) + 'A' - 10 );
2415 mpPS
->WriteUChar( ( nNumb
>> 4 ) + '0' );
2417 if ( ( nNumb
& 0xf ) > 9 )
2418 mpPS
->WriteUChar( ( nNumb
& 0xf ) + 'A' - 10 );
2420 mpPS
->WriteUChar( ( nNumb
& 0xf ) + '0' );
2422 ImplExecMode( nMode
);
2425 // writes the sal_uInt8 nNumb as a Number from 0.000 up to 1.000
2427 void PSWriter::ImplWriteB1( sal_uInt8 nNumb
)
2429 ImplWriteF( 1000 * ( nNumb
+ 1 ) / 256 );
2432 inline void PSWriter::WriteBits( sal_uInt16 nCode
, sal_uInt16 nCodeLen
)
2434 dwShift
|= ( nCode
<< ( nOffset
- nCodeLen
) );
2435 nOffset
-= nCodeLen
;
2436 while ( nOffset
< 24 )
2438 ImplWriteHexByte( static_cast<sal_uInt8
>( dwShift
>> 24 ) );
2442 if ( nCode
== 257 && nOffset
!= 32 )
2443 ImplWriteHexByte( static_cast<sal_uInt8
>( dwShift
>> 24 ) );
2446 void PSWriter::StartCompression()
2451 nClearCode
= 1 << nDataSize
;
2452 nEOICode
= nClearCode
+ 1;
2453 nTableSize
= nEOICode
+ 1;
2454 nCodeSize
= nDataSize
+ 1;
2456 nOffset
= 32; // number of free unused in dwShift
2459 pTable
.reset(new PSLZWCTreeNode
[ 4096 ]);
2461 for ( i
= 0; i
< 4096; i
++ )
2463 pTable
[ i
].pBrother
= pTable
[ i
].pFirstChild
= nullptr;
2464 pTable
[ i
].nCode
= i
;
2465 pTable
[ i
].nValue
= static_cast<sal_uInt8
>( i
);
2468 WriteBits( nClearCode
, nCodeSize
);
2471 void PSWriter::Compress( sal_uInt8 nCompThis
)
2479 pPrefix
= pTable
.get() + nCompThis
;
2484 for( p
= pPrefix
->pFirstChild
; p
!= nullptr; p
= p
->pBrother
)
2486 if ( p
->nValue
== nV
)
2494 WriteBits( pPrefix
->nCode
, nCodeSize
);
2496 if ( nTableSize
== 409 )
2498 WriteBits( nClearCode
, nCodeSize
);
2500 for ( i
= 0; i
< nClearCode
; i
++ )
2501 pTable
[ i
].pFirstChild
= nullptr;
2503 nCodeSize
= nDataSize
+ 1;
2504 nTableSize
= nEOICode
+ 1;
2508 if( nTableSize
== static_cast<sal_uInt16
>( ( 1 << nCodeSize
) - 1 ) )
2511 p
= pTable
.get() + ( nTableSize
++ );
2512 p
->pBrother
= pPrefix
->pFirstChild
;
2513 pPrefix
->pFirstChild
= p
;
2515 p
->pFirstChild
= nullptr;
2518 pPrefix
= pTable
.get() + nV
;
2523 void PSWriter::EndCompression()
2526 WriteBits( pPrefix
->nCode
, nCodeSize
);
2528 WriteBits( nEOICode
, nCodeSize
);
2532 sal_uInt8
* PSWriter::ImplSearchEntry( sal_uInt8
* pSource
, sal_uInt8
const * pDest
, sal_uInt32 nComp
, sal_uInt32 nSize
)
2534 while ( nComp
-- >= nSize
)
2537 for ( i
= 0; i
< nSize
; i
++ )
2539 if ( ( pSource
[i
]&~0x20 ) != ( pDest
[i
]&~0x20 ) )
2549 bool PSWriter::ImplGetBoundingBox( double* nNumb
, sal_uInt8
* pSource
, sal_uInt32 nSize
)
2551 bool bRetValue
= false;
2552 sal_uInt32 nBytesRead
;
2554 if ( nSize
< 256 ) // we assume that the file is greater than 256 bytes
2557 if ( nSize
< POSTSCRIPT_BOUNDINGSEARCH
)
2560 nBytesRead
= POSTSCRIPT_BOUNDINGSEARCH
;
2562 sal_uInt8
* pDest
= ImplSearchEntry( pSource
, reinterpret_cast<sal_uInt8
const *>("%%BoundingBox:"), nBytesRead
, 14 );
2565 int nSecurityCount
= 100; // only 100 bytes following the bounding box will be checked
2566 nNumb
[0] = nNumb
[1] = nNumb
[2] = nNumb
[3] = 0;
2568 for ( int i
= 0; ( i
< 4 ) && nSecurityCount
; i
++ )
2571 bool bDivision
= false;
2572 bool bNegative
= false;
2575 while ( ( --nSecurityCount
) && ( ( *pDest
== ' ' ) || ( *pDest
== 0x9 ) ) )
2577 sal_uInt8 nByte
= *pDest
;
2578 while ( nSecurityCount
&& ( nByte
!= ' ' ) && ( nByte
!= 0x9 ) && ( nByte
!= 0xd ) && ( nByte
!= 0xa ) )
2592 if ( ( nByte
< '0' ) || ( nByte
> '9' ) )
2593 nSecurityCount
= 1; // error parsing the bounding box values
2599 nNumb
[i
] += nByte
- '0';
2607 nNumb
[i
] = -nNumb
[i
];
2608 if ( bDivision
&& ( nDivision
!= 1 ) )
2609 nNumb
[i
] /= nDivision
;
2611 if ( nSecurityCount
)
2617 //================== GraphicExport - the exported function ===================
2619 bool ExportEpsGraphic(SvStream
& rStream
, const Graphic
& rGraphic
, FilterConfigItem
* pFilterConfigItem
)
2622 return aPSWriter
.WritePS(rGraphic
, rStream
, pFilterConfigItem
);
2625 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */