LibreOffice Module vcl (master)  1
eps.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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 <unotools/resmgr.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/metaact.hxx>
28 #include <vcl/graph.hxx>
29 #include <vcl/BitmapReadAccess.hxx>
30 #include <vcl/region.hxx>
31 #include <vcl/font.hxx>
32 #include <vcl/virdev.hxx>
33 #include <vcl/cvtgrf.hxx>
34 #include <vcl/gradient.hxx>
35 #include <unotools/configmgr.hxx>
36 #include <vcl/FilterConfigItem.hxx>
37 #include <vcl/graphictools.hxx>
38 #include <vcl/weld.hxx>
39 #include <strings.hrc>
40 #include <osl/diagnose.h>
41 #include <com/sun/star/task/XStatusIndicator.hpp>
42 
43 #include <cstdlib>
44 #include <memory>
45 
46 using namespace ::com::sun::star::uno;
47 
48 #define POSTSCRIPT_BOUNDINGSEARCH 0x1000 // we only try to get the BoundingBox
49  // in the first 4096 bytes
50 
51 #define EPS_PREVIEW_TIFF 1
52 #define EPS_PREVIEW_EPSI 2
53 
54 #define PS_LINESIZE 70 // maximum number of characters a line in the output
55 
56 // -----------------------------field-types------------------------------
57 
58 namespace {
59 
60 struct StackMember
61 {
62  struct StackMember * pSucc;
63  Color aGlobalCol;
64  bool bLineCol;
65  Color aLineCol;
66  bool bFillCol;
67  Color aFillCol;
68  Color aTextCol;
69  bool bTextFillCol;
70  Color aTextFillCol;
71  Color aBackgroundCol;
72  vcl::Font aFont;
73  TextAlign eTextAlign;
74 
75  double fLineWidth;
76  double fMiterLimit;
79  SvtGraphicStroke::DashArray aDashArray;
80 };
81 
82 struct PSLZWCTreeNode
83 {
84 
85  PSLZWCTreeNode* pBrother; // next node who has the same father
86  PSLZWCTreeNode* pFirstChild; // first son
87  sal_uInt16 nCode; // The code for the string of pixel values, which arises if... <missing comment>
88  sal_uInt16 nValue; // the pixel value
89 };
90 
91 enum NMode {PS_NONE = 0x00, PS_SPACE = 0x01, PS_RET = 0x02, PS_WRAP = 0x04}; // formatting mode: action which is inserted behind the output
92 inline NMode operator|(NMode a, NMode b)
93 {
94  return static_cast<NMode>(static_cast<sal_uInt8>(a) | static_cast<sal_uInt8>(b));
95 }
96 
97 class PSWriter
98 {
99 private:
100  bool mbStatus;
101  bool mbLevelWarning; // if there any embedded eps file which was not exported
102  sal_uInt32 mnLatestPush; // offset to streamposition, where last push was done
103 
104  tools::Long mnLevel; // dialog options
105  bool mbGrayScale;
106  bool mbCompression;
107  sal_Int32 mnPreview;
108  sal_Int32 mnTextMode;
109 
110  SvStream* mpPS;
111  const GDIMetaFile* pMTF;
112  std::unique_ptr<GDIMetaFile>
113  pAMTF; // only created if Graphics is not a Metafile
115  pVDev;
116 
117  double nBoundingX2; // this represents the bounding box
118  double nBoundingY2;
119 
120  StackMember* pGDIStack;
121  sal_uInt32 mnCursorPos; // current cursor position in output
122  Color aColor; // current color which is used for output
123  bool bLineColor;
124  Color aLineColor; // current GDIMetafile color settings
125  bool bFillColor;
126  Color aFillColor;
127  Color aTextColor;
128  bool bTextFillColor;
129  Color aTextFillColor;
130  Color aBackgroundColor;
131  TextAlign eTextAlign;
132 
133  double fLineWidth;
134  double fMiterLimit;
135  SvtGraphicStroke::CapType eLineCap;
136  SvtGraphicStroke::JoinType eJoinType;
137  SvtGraphicStroke::DashArray aDashArray;
138 
139  vcl::Font maFont;
140  vcl::Font maLastFont;
141  sal_uInt8 nNextChrSetId; // first unused ChrSet-Id
142 
143  std::unique_ptr<PSLZWCTreeNode[]> pTable; // LZW compression data
144  PSLZWCTreeNode* pPrefix; // the compression is as same as the TIFF compression
145  sal_uInt16 nDataSize;
146  sal_uInt16 nClearCode;
147  sal_uInt16 nEOICode;
148  sal_uInt16 nTableSize;
149  sal_uInt16 nCodeSize;
150  sal_uInt32 nOffset;
151  sal_uInt32 dwShift;
152 
153  css::uno::Reference< css::task::XStatusIndicator > xStatusIndicator;
154 
155  void ImplWriteProlog( const Graphic* pPreviewEPSI );
156  void ImplWriteEpilog();
157  void ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev );
158 
159  // this method makes LF's, space inserting and word wrapping as used in all nMode
160  // parameters
161  inline void ImplExecMode( NMode nMode );
162 
163  // writes char[] + LF to stream
164  inline void ImplWriteLine( const char*, NMode nMode = PS_RET );
165 
166  // writes ( nNumb / 10^nCount ) in ASCII format to stream
167  void ImplWriteF( sal_Int32 nNumb, sal_uInt8 nCount = 3, NMode nMode = PS_SPACE );
168 
169  // writes a double in ASCII format to stream
170  void ImplWriteDouble( double );
171 
172  // writes a long in ASCII format to stream
173  void ImplWriteLong( sal_Int32 nNumb, NMode nMode = PS_SPACE );
174 
175  // writes a byte in ASCII format to stream
176  void ImplWriteByte( sal_uInt8 nNumb, NMode nMode = PS_SPACE );
177 
178  // writes a byte in ASCII (hex) format to stream
179  void ImplWriteHexByte( sal_uInt8 nNumb, NMode nMode = PS_WRAP );
180 
181  // writes nNumb as number from 0.000 till 1.000 in ASCII format to stream
182  void ImplWriteB1( sal_uInt8 nNumb );
183 
184  inline void ImplWritePoint( const Point& );
185  void ImplMoveTo( const Point& );
186  void ImplLineTo( const Point&, NMode nMode = PS_SPACE );
187  void ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, NMode nMode );
188  void ImplTranslate( const double& fX, const double& fY );
189  void ImplScale( const double& fX, const double& fY );
190 
191  void ImplAddPath( const tools::Polygon & rPolygon );
192  void ImplWriteLineInfo( double fLineWidth, double fMiterLimit, SvtGraphicStroke::CapType eLineCap,
193  SvtGraphicStroke::JoinType eJoinType, SvtGraphicStroke::DashArray const & rDashArray );
194  void ImplWriteLineInfo( const LineInfo& rLineInfo );
195  void ImplRect( const tools::Rectangle & rRectangle );
196  void ImplRectFill ( const tools::Rectangle & rRectangle );
197  void ImplWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev );
198  void ImplIntersect( const tools::PolyPolygon& rPolyPoly );
199  void ImplPolyPoly( const tools::PolyPolygon & rPolyPolygon, bool bTextOutline = false );
200  void ImplPolyLine( const tools::Polygon & rPolygon );
201 
202  void ImplSetClipRegion( vcl::Region const & rRegion );
203  void ImplBmp( Bitmap const *, Bitmap const *, const Point &, double nWidth, double nHeight );
204  void ImplText( const OUString& rUniString, const Point& rPos, const tools::Long* pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev );
205  void ImplSetAttrForText( const Point & rPoint );
206  void ImplWriteCharacter( char );
207  void ImplWriteString( const OString&, VirtualDevice const & rVDev, const tools::Long* pDXArry, bool bStretch );
208  void ImplDefineFont( const char*, const char* );
209 
210  void ImplClosePathDraw();
211  void ImplPathDraw();
212 
213  inline void ImplWriteLineColor( NMode nMode );
214  inline void ImplWriteFillColor( NMode nMode );
215  inline void ImplWriteTextColor( NMode nMode );
216  void ImplWriteColor( NMode nMode );
217 
218  static double ImplGetScaling( const MapMode& );
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 );
222  // LZW methods
223  void StartCompression();
224  void Compress( sal_uInt8 nSrc );
225  void EndCompression();
226  inline void WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen );
227 
228 public:
229  bool WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* );
230  PSWriter();
231 };
232 
233 }
234 
235 //========================== methods from PSWriter ==========================
236 
237 
238 PSWriter::PSWriter()
239  : mbStatus(false)
240  , mbLevelWarning(false)
241  , mnLatestPush(0)
242  , mnLevel(0)
243  , mbGrayScale(false)
244  , mbCompression(false)
245  , mnPreview(0)
246  , mnTextMode(0)
247  , mpPS(nullptr)
248  , pMTF(nullptr)
249  , pVDev()
250  , nBoundingX2(0)
251  , nBoundingY2(0)
252  , pGDIStack(nullptr)
253  , mnCursorPos(0)
254  , aColor()
255  , bLineColor(false)
256  , aLineColor()
257  , bFillColor(false)
258  , aFillColor()
259  , aTextColor()
260  , bTextFillColor(false)
261  , aTextFillColor()
262  , aBackgroundColor()
263  , eTextAlign()
264  , fLineWidth(0)
265  , fMiterLimit(0)
266  , eLineCap()
267  , eJoinType()
268  , aDashArray()
269  , maFont()
270  , maLastFont()
271  , nNextChrSetId(0)
272  , pPrefix(nullptr)
273  , nDataSize(0)
274  , nClearCode(0)
275  , nEOICode(0)
276  , nTableSize(0)
277  , nCodeSize(0)
278  , nOffset(0)
279  , dwShift(0)
280  , xStatusIndicator()
281 {
282 }
283 
284 bool PSWriter::WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* pFilterConfigItem )
285 {
286  sal_uInt32 nStreamPosition = 0, nPSPosition = 0; // -Wall warning, unset, check
287 
288  mbStatus = true;
289  mnPreview = 0;
290  mbLevelWarning = false;
291  mnLatestPush = 0xEFFFFFFE;
292 
293  if ( pFilterConfigItem )
294  {
295  xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
296  if ( xStatusIndicator.is() )
297  {
298  xStatusIndicator->start( OUString(), 100 );
299  }
300  }
301 
302  mpPS = &rTargetStream;
303  mpPS->SetEndian( SvStreamEndian::LITTLE );
304 
305  // default values for the dialog options
306  mnLevel = 2;
307  mbGrayScale = false;
308 #ifdef UNX // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
309  mbCompression = false;
310 #else
311  mbCompression = true;
312 #endif
313  mnTextMode = 0; // default0 : export glyph outlines
314 
315  // try to get the dialog selection
316  if ( pFilterConfigItem )
317  {
318 #ifdef UNX // don't put binary tiff preview ahead of postscript code by default on unix as ghostscript is unable to read it
319  mnPreview = pFilterConfigItem->ReadInt32( "Preview", 0 );
320 #else
321  mnPreview = pFilterConfigItem->ReadInt32( "Preview", 1 );
322 #endif
323  mnLevel = pFilterConfigItem->ReadInt32( "Version", 2 );
324  if ( mnLevel != 1 )
325  mnLevel = 2;
326  mbGrayScale = pFilterConfigItem->ReadInt32( "ColorFormat", 1 ) == 2;
327 #ifdef UNX // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
328  mbCompression = pFilterConfigItem->ReadInt32( "CompressionMode", 0 ) != 0;
329 #else
330  mbCompression = pFilterConfigItem->ReadInt32( "CompressionMode", 1 ) == 1;
331 #endif
332  mnTextMode = pFilterConfigItem->ReadInt32( "TextMode", 0 );
333  if ( mnTextMode > 2 )
334  mnTextMode = 0;
335  }
336 
337  // compression is not available for Level 1
338  if ( mnLevel == 1 )
339  {
340  mbGrayScale = true;
341  mbCompression = false;
342  }
343 
344  if ( mnPreview & EPS_PREVIEW_TIFF )
345  {
346  rTargetStream.WriteUInt32( 0xC6D3D0C5 );
347  nStreamPosition = rTargetStream.Tell();
348  rTargetStream.WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
349  .WriteUInt32( nStreamPosition + 26 ).WriteUInt32( 0 ).WriteUInt16( 0xffff );
350 
351  ErrCode nErrCode;
352  if ( mbGrayScale )
353  {
354  BitmapEx aTempBitmapEx( rGraphic.GetBitmapEx() );
355  aTempBitmapEx.Convert( BmpConversion::N8BitGreys );
356  nErrCode = GraphicConverter::Export( rTargetStream, aTempBitmapEx, ConvertDataFormat::TIF ) ;
357  }
358  else
359  nErrCode = GraphicConverter::Export( rTargetStream, rGraphic, ConvertDataFormat::TIF ) ;
360 
361  if ( nErrCode == ERRCODE_NONE )
362  {
363  nPSPosition = rTargetStream.TellEnd();
364  rTargetStream.Seek( nStreamPosition + 20 );
365  rTargetStream.WriteUInt32( nPSPosition - 30 ); // size of tiff gfx
366  rTargetStream.Seek( nPSPosition );
367  }
368  else
369  {
370  mnPreview &=~ EPS_PREVIEW_TIFF;
371  rTargetStream.Seek( nStreamPosition - 4 );
372  }
373  }
374 
375  // global default value setting
376  StackMember* pGS;
377 
378  if (rGraphic.GetType() == GraphicType::GdiMetafile)
379  pMTF = &rGraphic.GetGDIMetaFile();
380  else if (rGraphic.GetGDIMetaFile().GetActionSize())
381  {
382  pAMTF.reset( new GDIMetaFile( rGraphic.GetGDIMetaFile() ) );
383  pMTF = pAMTF.get();
384  }
385  else
386  {
387  BitmapEx aBmp( rGraphic.GetBitmapEx() );
388  pAMTF.reset( new GDIMetaFile );
390  pAMTF->Record( pTmpVDev );
391  pTmpVDev->DrawBitmapEx( Point(), aBmp );
392  pAMTF->Stop();
393  pAMTF->SetPrefSize( aBmp.GetSizePixel() );
394  pMTF = pAMTF.get();
395  }
396  pVDev->SetMapMode( pMTF->GetPrefMapMode() );
397  nBoundingX2 = pMTF->GetPrefSize().Width();
398  nBoundingY2 = pMTF->GetPrefSize().Height();
399 
400  pGDIStack = nullptr;
401  aColor = COL_TRANSPARENT;
402  bLineColor = true;
403  aLineColor = COL_BLACK;
404  bFillColor = true;
405  aFillColor = COL_WHITE;
406  bTextFillColor = true;
407  aTextFillColor = COL_BLACK;
408  fLineWidth = 1;
409  fMiterLimit = 15; // use same limit as most graphic systems and basegfx
410  eLineCap = SvtGraphicStroke::capButt;
411  eJoinType = SvtGraphicStroke::joinMiter;
412  aBackgroundColor = COL_WHITE;
413  eTextAlign = ALIGN_BASELINE;
414 
415  nNextChrSetId = 1;
416 
417  if( pMTF->GetActionSize() )
418  {
419  ImplWriteProlog( ( mnPreview & EPS_PREVIEW_EPSI ) ? &rGraphic : nullptr );
420  mnCursorPos = 0;
421  ImplWriteActions( *pMTF, *pVDev );
422  ImplWriteEpilog();
423  if ( mnPreview & EPS_PREVIEW_TIFF )
424  {
425  sal_uInt32 nPosition = rTargetStream.Tell();
426  rTargetStream.Seek( nStreamPosition );
427  rTargetStream.WriteUInt32( nPSPosition );
428  rTargetStream.WriteUInt32( nPosition - nPSPosition );
429  rTargetStream.Seek( nPosition );
430  }
431  while( pGDIStack )
432  {
433  pGS=pGDIStack;
434  pGDIStack=pGS->pSucc;
435  delete pGS;
436  }
437  }
438  else
439  mbStatus = false;
440 
441  if ( mbStatus && mbLevelWarning && pFilterConfigItem )
442  {
443  std::locale loc = Translate::Create("flt");
444  std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
446  Translate::get(KEY_VERSION_CHECK, loc)));
447  xInfoBox->run();
448  }
449 
450  if ( xStatusIndicator.is() )
451  xStatusIndicator->end();
452 
453  return mbStatus;
454 }
455 
456 void PSWriter::ImplWriteProlog( const Graphic* pPreview )
457 {
458  ImplWriteLine( "%!PS-Adobe-3.0 EPSF-3.0 " );
459  mpPS->WriteCharPtr( "%%BoundingBox: " ); // BoundingBox
460  ImplWriteLong( 0 );
461  ImplWriteLong( 0 );
462  Size aSizePoint = OutputDevice::LogicToLogic( pMTF->GetPrefSize(),
463  pMTF->GetPrefMapMode(), MapMode(MapUnit::MapPoint));
464  ImplWriteLong( aSizePoint.Width() );
465  ImplWriteLong( aSizePoint.Height() ,PS_RET );
466  ImplWriteLine( "%%Pages: 0" );
467  OUString aCreator( "%%Creator: " + utl::ConfigManager::getProductName() + " " +
469  ImplWriteLine( OUStringToOString( aCreator, RTL_TEXTENCODING_UTF8 ).getStr() );
470  ImplWriteLine( "%%Title: none" );
471  ImplWriteLine( "%%CreationDate: none" );
472 
473 // defaults
474 
475  mpPS->WriteCharPtr( "%%LanguageLevel: " ); // Language level
476  ImplWriteLong( mnLevel, PS_RET );
477  if ( !mbGrayScale && mnLevel == 1 )
478  ImplWriteLine( "%%Extensions: CMYK" ); // CMYK extension is to set in color mode in level 1
479  ImplWriteLine( "%%EndComments" );
480  if ( pPreview && aSizePoint.Width() && aSizePoint.Height() )
481  {
482  Size aSizeBitmap( ( aSizePoint.Width() + 7 ) & ~7, aSizePoint.Height() );
483  Bitmap aTmpBitmap( pPreview->GetBitmapEx().GetBitmap() );
484  aTmpBitmap.Scale( aSizeBitmap, BmpScaleFlag::BestQuality );
485  aTmpBitmap.Convert( BmpConversion::N1BitThreshold );
486  BitmapReadAccess* pAcc = aTmpBitmap.AcquireReadAccess();
487  if ( pAcc )
488  {
489  mpPS->WriteCharPtr( "%%BeginPreview: " ); // BoundingBox
490  ImplWriteLong( aSizeBitmap.Width() );
491  ImplWriteLong( aSizeBitmap.Height() );
492  mpPS->WriteCharPtr( "1 " );
493  sal_Int32 nLines = aSizeBitmap.Width() / 312;
494  if ( ( nLines * 312 ) != aSizeBitmap.Width() )
495  nLines++;
496  nLines *= aSizeBitmap.Height();
497  ImplWriteLong( nLines );
498  sal_Int32 nCount2, nCount = 4;
499  const BitmapColor aBlack( pAcc->GetBestMatchingColor( COL_BLACK ) );
500  for ( tools::Long nY = 0; nY < aSizeBitmap.Height(); nY++ )
501  {
502  nCount2 = 0;
503  char nVal = 0;
504  Scanline pScanline = pAcc->GetScanline( nY );
505  for ( tools::Long nX = 0; nX < aSizeBitmap.Width(); nX++ )
506  {
507  if ( !nCount2 )
508  {
509  ImplExecMode( PS_RET );
510  mpPS->WriteCharPtr( "%" );
511  nCount2 = 312;
512  }
513  nVal <<= 1;
514  if ( pAcc->GetPixelFromData( pScanline, nX ) == aBlack )
515  nVal |= 1;
516  if ( ! ( --nCount ) )
517  {
518  if ( nVal > 9 )
519  nVal += 'A' - 10;
520  else
521  nVal += '0';
522  mpPS->WriteChar( nVal );
523  nVal = 0;
524  nCount += 4;
525  }
526  nCount2--;
527  }
528  }
529  Bitmap::ReleaseAccess( pAcc );
530  ImplExecMode( PS_RET );
531  ImplWriteLine( "%%EndPreview" );
532  }
533  }
534  ImplWriteLine( "%%BeginProlog" );
535  ImplWriteLine( "%%BeginResource: procset SDRes-Prolog 1.0 0" );
536 
537 // BEGIN EPSF
538  ImplWriteLine( "/b4_inc_state save def\n/dict_count countdictstack def\n/op_count count 1 sub def\nuserdict begin" );
539  ImplWriteLine( "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath" );
540  ImplWriteLine( "/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if" );
541 
542  ImplWriteLine( "/bdef {bind def} bind def" ); // the new operator bdef is created
543  if ( mbGrayScale )
544  ImplWriteLine( "/c {setgray} bdef" );
545  else
546  ImplWriteLine( "/c {setrgbcolor} bdef" );
547  ImplWriteLine( "/l {neg lineto} bdef" );
548  ImplWriteLine( "/rl {neg rlineto} bdef" );
549  ImplWriteLine( "/lc {setlinecap} bdef" );
550  ImplWriteLine( "/lj {setlinejoin} bdef" );
551  ImplWriteLine( "/lw {setlinewidth} bdef" );
552  ImplWriteLine( "/ml {setmiterlimit} bdef" );
553  ImplWriteLine( "/ld {setdash} bdef" );
554  ImplWriteLine( "/m {neg moveto} bdef" );
555  ImplWriteLine( "/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef" );
556  ImplWriteLine( "/r {rotate} bdef" );
557  ImplWriteLine( "/t {neg translate} bdef" );
558  ImplWriteLine( "/s {scale} bdef" );
559  ImplWriteLine( "/sw {show} bdef" );
560  ImplWriteLine( "/gs {gsave} bdef" );
561  ImplWriteLine( "/gr {grestore} bdef" );
562 
563  ImplWriteLine( "/f {findfont dup length dict begin" ); // Setfont
564  ImplWriteLine( "{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def" );
565  ImplWriteLine( "currentdict end /NFont exch definefont pop /NFont findfont} bdef" );
566 
567  ImplWriteLine( "/p {closepath} bdef" );
568  ImplWriteLine( "/sf {scalefont setfont} bdef" );
569 
570  ImplWriteLine( "/ef {eofill}bdef" ); // close path and fill
571  ImplWriteLine( "/pc {closepath stroke}bdef" ); // close path and draw
572  ImplWriteLine( "/ps {stroke}bdef" ); // draw current path
573  ImplWriteLine( "/pum {matrix currentmatrix}bdef" ); // pushes the current matrix
574  ImplWriteLine( "/pom {setmatrix}bdef" ); // pops the matrix
575  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" );
576  ImplWriteLine( "%%EndResource" );
577  ImplWriteLine( "%%EndProlog" );
578  ImplWriteLine( "%%BeginSetup" );
579  ImplWriteLine( "%%EndSetup" );
580  ImplWriteLine( "%%Page: 1 1" );
581  ImplWriteLine( "%%BeginPageSetup" );
582  ImplWriteLine( "%%EndPageSetup" );
583  ImplWriteLine( "pum" );
584  ImplScale( static_cast<double>(aSizePoint.Width()) / static_cast<double>(pMTF->GetPrefSize().Width()), static_cast<double>(aSizePoint.Height()) / static_cast<double>(pMTF->GetPrefSize().Height()) );
585  ImplWriteDouble( 0 );
586  ImplWriteDouble( -pMTF->GetPrefSize().Height() );
587  ImplWriteLine( "t" );
588  ImplWriteLine( "/tm matrix currentmatrix def" );
589 }
590 
591 void PSWriter::ImplWriteEpilog()
592 {
593  ImplTranslate( 0, nBoundingY2 );
594  ImplWriteLine( "pom" );
595  ImplWriteLine( "count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore" );
596 
597  ImplWriteLine( "%%PageTrailer" );
598  ImplWriteLine( "%%Trailer" );
599 
600  ImplWriteLine( "%%EOF" );
601 }
602 
603 void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev )
604 {
605  tools::PolyPolygon aFillPath;
606 
607  for( size_t nCurAction = 0, nCount = rMtf.GetActionSize(); nCurAction < nCount; nCurAction++ )
608  {
609  MetaAction* pMA = rMtf.GetAction( nCurAction );
610 
611  switch( pMA->GetType() )
612  {
613  case MetaActionType::NONE :
614  break;
615 
616  case MetaActionType::PIXEL :
617  {
618  Color aOldLineColor( aLineColor );
619  aLineColor = static_cast<const MetaPixelAction*>(pMA)->GetColor();
620  ImplWriteLineColor( PS_SPACE );
621  ImplMoveTo( static_cast<const MetaPixelAction*>(pMA)->GetPoint() );
622  ImplLineTo( static_cast<const MetaPixelAction*>(pMA)->GetPoint() );
623  ImplPathDraw();
624  aLineColor = aOldLineColor;
625  }
626  break;
627 
628  case MetaActionType::POINT :
629  {
630  ImplWriteLineColor( PS_SPACE );
631  ImplMoveTo( static_cast<const MetaPointAction*>(pMA)->GetPoint() );
632  ImplLineTo( static_cast<const MetaPointAction*>(pMA)->GetPoint() );
633  ImplPathDraw();
634  }
635  break;
636 
637  case MetaActionType::LINE :
638  {
639  const LineInfo& rLineInfo = static_cast<const MetaLineAction*>(pMA)->GetLineInfo();
640  ImplWriteLineInfo( rLineInfo );
641  if ( bLineColor )
642  {
643  ImplWriteLineColor( PS_SPACE );
644  ImplMoveTo( static_cast<const MetaLineAction*>(pMA)->GetStartPoint() );
645  ImplLineTo( static_cast<const MetaLineAction*>(pMA )->GetEndPoint() );
646  ImplPathDraw();
647  }
648  }
649  break;
650 
651  case MetaActionType::RECT :
652  {
653  ImplRect( static_cast<const MetaRectAction*>(pMA)->GetRect() );
654  }
655  break;
656 
658  ImplRect( static_cast<const MetaRoundRectAction*>(pMA)->GetRect() );
659  break;
660 
662  {
663  tools::Rectangle aRect = static_cast<const MetaEllipseAction*>(pMA)->GetRect();
664  Point aCenter = aRect.Center();
665  tools::Polygon aPoly( aCenter, aRect.GetWidth() / 2, aRect.GetHeight() / 2 );
666  tools::PolyPolygon aPolyPoly( aPoly );
667  ImplPolyPoly( aPolyPoly );
668  }
669  break;
670 
671  case MetaActionType::ARC :
672  {
673  tools::Polygon aPoly( static_cast<const MetaArcAction*>(pMA)->GetRect(), static_cast<const MetaArcAction*>(pMA)->GetStartPoint(),
674  static_cast<const MetaArcAction*>(pMA)->GetEndPoint(), PolyStyle::Arc );
675  tools::PolyPolygon aPolyPoly( aPoly );
676  ImplPolyPoly( aPolyPoly );
677  }
678  break;
679 
680  case MetaActionType::PIE :
681  {
682  tools::Polygon aPoly( static_cast<const MetaPieAction*>(pMA)->GetRect(), static_cast<const MetaPieAction*>(pMA)->GetStartPoint(),
683  static_cast<const MetaPieAction*>(pMA)->GetEndPoint(), PolyStyle::Pie );
684  tools::PolyPolygon aPolyPoly( aPoly );
685  ImplPolyPoly( aPolyPoly );
686  }
687  break;
688 
689  case MetaActionType::CHORD :
690  {
691  tools::Polygon aPoly( static_cast<const MetaChordAction*>(pMA)->GetRect(), static_cast<const MetaChordAction*>(pMA)->GetStartPoint(),
692  static_cast<const MetaChordAction*>(pMA)->GetEndPoint(), PolyStyle::Chord );
693  tools::PolyPolygon aPolyPoly( aPoly );
694  ImplPolyPoly( aPolyPoly );
695  }
696  break;
697 
699  {
700  tools::Polygon aPoly( static_cast<const MetaPolyLineAction*>(pMA)->GetPolygon() );
701  const LineInfo& rLineInfo = static_cast<const MetaPolyLineAction*>(pMA)->GetLineInfo();
702  ImplWriteLineInfo( rLineInfo );
703 
704  if(basegfx::B2DLineJoin::NONE == rLineInfo.GetLineJoin()
705  && rLineInfo.GetWidth() > 1)
706  {
707  // emulate B2DLineJoin::NONE by creating single edges
708  const sal_uInt16 nPoints(aPoly.GetSize());
709  const bool bCurve(aPoly.HasFlags());
710 
711  for(sal_uInt16 a(0); a + 1 < nPoints; a++)
712  {
713  if(bCurve
714  && PolyFlags::Normal != aPoly.GetFlags(a + 1)
715  && a + 2 < nPoints
716  && PolyFlags::Normal != aPoly.GetFlags(a + 2)
717  && a + 3 < nPoints)
718  {
719  const tools::Polygon aSnippet(4,
720  aPoly.GetConstPointAry() + a,
721  aPoly.GetConstFlagAry() + a);
722  ImplPolyLine(aSnippet);
723  a += 2;
724  }
725  else
726  {
727  const tools::Polygon aSnippet(2,
728  aPoly.GetConstPointAry() + a);
729  ImplPolyLine(aSnippet);
730  }
731  }
732  }
733  else
734  {
735  ImplPolyLine( aPoly );
736  }
737  }
738  break;
739 
741  {
742  tools::PolyPolygon aPolyPoly( static_cast<const MetaPolygonAction*>(pMA)->GetPolygon() );
743  ImplPolyPoly( aPolyPoly );
744  }
745  break;
746 
748  {
749  ImplPolyPoly( static_cast<const MetaPolyPolygonAction*>(pMA)->GetPolyPolygon() );
750  }
751  break;
752 
754  {
755  const MetaTextAction * pA = static_cast<const MetaTextAction*>(pMA);
756 
757  OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
758  Point aPoint( pA->GetPoint() );
759 
760  ImplText( aUniStr, aPoint, nullptr, 0, rVDev );
761  }
762  break;
763 
765  {
766  OSL_FAIL( "Unsupported action: TextRect...Action!" );
767  }
768  break;
769 
771  {
772  const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pMA);
773  OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
774  Point aPoint( pA->GetPoint() );
775 
776  ImplText( aUniStr, aPoint, nullptr, pA->GetWidth(), rVDev );
777  }
778  break;
779 
781  {
782  const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pMA);
783  OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
784  Point aPoint( pA->GetPoint() );
785 
786  ImplText( aUniStr, aPoint, pA->GetDXArray(), 0, rVDev );
787  }
788  break;
789 
790  case MetaActionType::BMP :
791  {
792  Bitmap aBitmap = static_cast<const MetaBmpAction*>(pMA)->GetBitmap();
793  if ( mbGrayScale )
795  Point aPoint = static_cast<const MetaBmpAction*>(pMA)->GetPoint();
796  Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
797  ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
798  }
799  break;
800 
802  {
803  Bitmap aBitmap = static_cast<const MetaBmpScaleAction*>(pMA)->GetBitmap();
804  if ( mbGrayScale )
806  Point aPoint = static_cast<const MetaBmpScaleAction*>(pMA)->GetPoint();
807  Size aSize = static_cast<const MetaBmpScaleAction*>(pMA)->GetSize();
808  ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
809  }
810  break;
811 
813  {
814  Bitmap aBitmap( static_cast<const MetaBmpScalePartAction*>(pMA)->GetBitmap() );
815  aBitmap.Crop( tools::Rectangle( static_cast<const MetaBmpScalePartAction*>(pMA)->GetSrcPoint(),
816  static_cast<const MetaBmpScalePartAction*>(pMA)->GetSrcSize() ) );
817  if ( mbGrayScale )
819  Point aPoint = static_cast<const MetaBmpScalePartAction*>(pMA)->GetDestPoint();
820  Size aSize = static_cast<const MetaBmpScalePartAction*>(pMA)->GetDestSize();
821  ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
822  }
823  break;
824 
825  case MetaActionType::BMPEX :
826  {
827  BitmapEx aBitmapEx( static_cast<MetaBmpExAction*>(pMA)->GetBitmapEx() );
828  Bitmap aBitmap( aBitmapEx.GetBitmap() );
829  if ( mbGrayScale )
831  Bitmap aMask( aBitmapEx.GetMask() );
832  Point aPoint( static_cast<const MetaBmpExAction*>(pMA)->GetPoint() );
833  Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
834  ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
835  }
836  break;
837 
839  {
840  BitmapEx aBitmapEx( static_cast<MetaBmpExScaleAction*>(pMA)->GetBitmapEx() );
841  Bitmap aBitmap( aBitmapEx.GetBitmap() );
842  if ( mbGrayScale )
844  Bitmap aMask( aBitmapEx.GetMask() );
845  Point aPoint = static_cast<const MetaBmpExScaleAction*>(pMA)->GetPoint();
846  Size aSize( static_cast<const MetaBmpExScaleAction*>(pMA)->GetSize() );
847  ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
848  }
849  break;
850 
852  {
853  BitmapEx aBitmapEx( static_cast<const MetaBmpExScalePartAction*>(pMA)->GetBitmapEx() );
854  aBitmapEx.Crop( tools::Rectangle( static_cast<const MetaBmpExScalePartAction*>(pMA)->GetSrcPoint(),
855  static_cast<const MetaBmpExScalePartAction*>(pMA)->GetSrcSize() ) );
856  Bitmap aBitmap( aBitmapEx.GetBitmap() );
857  if ( mbGrayScale )
859  Bitmap aMask( aBitmapEx.GetMask() );
860  Point aPoint = static_cast<const MetaBmpExScalePartAction*>(pMA)->GetDestPoint();
861  Size aSize = static_cast<const MetaBmpExScalePartAction*>(pMA)->GetDestSize();
862  ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
863  }
864  break;
865 
866  // Unsupported Actions
870  {
871  OSL_FAIL( "Unsupported action: MetaMask...Action!" );
872  }
873  break;
874 
876  {
877  tools::PolyPolygon aPolyPoly( static_cast<const MetaGradientAction*>(pMA)->GetRect() );
878  ImplWriteGradient( aPolyPoly, static_cast<const MetaGradientAction*>(pMA)->GetGradient(), rVDev );
879  }
880  break;
881 
883  {
884  tools::PolyPolygon aPolyPoly( static_cast<const MetaGradientExAction*>(pMA)->GetPolyPolygon() );
885  ImplWriteGradient( aPolyPoly, static_cast<const MetaGradientExAction*>(pMA)->GetGradient(), rVDev );
886  }
887  break;
888 
889  case MetaActionType::HATCH :
890  {
892  GDIMetaFile aTmpMtf;
893 
894  l_pVirDev->SetMapMode( rVDev.GetMapMode() );
895  l_pVirDev->AddHatchActions( static_cast<const MetaHatchAction*>(pMA)->GetPolyPolygon(),
896  static_cast<const MetaHatchAction*>(pMA)->GetHatch(), aTmpMtf );
897  ImplWriteActions( aTmpMtf, rVDev );
898  }
899  break;
900 
902  {
903  const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pMA);
904  tools::Rectangle aRect = pA->GetRect();
905  const Wallpaper& aWallpaper = pA->GetWallpaper();
906 
907  if ( aWallpaper.IsBitmap() )
908  {
909  BitmapEx aBitmapEx = aWallpaper.GetBitmap();
910  Bitmap aBitmap( aBitmapEx.GetBitmap() );
911  if ( aBitmapEx.IsTransparent() )
912  {
913  if ( aWallpaper.IsGradient() )
914  {
915 
916  // gradient action
917 
918  }
919  Bitmap aMask( aBitmapEx.GetMask() );
920  ImplBmp( &aBitmap, &aMask, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
921  }
922  else
923  ImplBmp( &aBitmap, nullptr, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
924 
925  // wallpaper Style
926 
927  }
928  else if ( aWallpaper.IsGradient() )
929  {
930 
931  // gradient action
932 
933  }
934  else
935  {
936  aColor = aWallpaper.GetColor();
937  ImplRectFill( aRect );
938  }
939  }
940  break;
941 
943  {
944  const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pMA);
945  vcl::Region aRegion( pA->GetRect() );
946  ImplSetClipRegion( aRegion );
947  }
948  break;
949 
951  {
952  const MetaClipRegionAction* pA = static_cast<const MetaClipRegionAction*>(pMA);
953  const vcl::Region& aRegion( pA->GetRegion() );
954  ImplSetClipRegion( aRegion );
955  }
956  break;
957 
959  {
960  const MetaISectRegionClipRegionAction* pA = static_cast<const MetaISectRegionClipRegionAction*>(pMA);
961  const vcl::Region& aRegion( pA->GetRegion() );
962  ImplSetClipRegion( aRegion );
963  }
964  break;
965 
967  {
968  // TODO: Implement!
969  }
970  break;
971 
973  {
974  if ( static_cast<const MetaLineColorAction*>(pMA)->IsSetting() )
975  {
976  bLineColor = true;
977  aLineColor = static_cast<const MetaLineColorAction*>(pMA)->GetColor();
978  }
979  else
980  bLineColor = false;
981  }
982  break;
983 
985  {
986  if ( static_cast<const MetaFillColorAction*>(pMA)->IsSetting() )
987  {
988  bFillColor = true;
989  aFillColor = static_cast<const MetaFillColorAction*>(pMA)->GetColor();
990  }
991  else
992  bFillColor = false;
993  }
994  break;
995 
997  {
998  aTextColor = static_cast<const MetaTextColorAction*>(pMA)->GetColor();
999  }
1000  break;
1001 
1003  {
1004  if ( static_cast<const MetaTextFillColorAction*>(pMA)->IsSetting() )
1005  {
1006  bTextFillColor = true;
1007  aTextFillColor = static_cast<const MetaTextFillColorAction*>(pMA)->GetColor();
1008  }
1009  else
1010  bTextFillColor = false;
1011  }
1012  break;
1013 
1015  {
1016  eTextAlign = static_cast<const MetaTextAlignAction*>(pMA)->GetTextAlign();
1017  }
1018  break;
1019 
1021  {
1022  pMA->Execute( &rVDev );
1023  ImplGetMapMode( rVDev.GetMapMode() );
1024  }
1025  break;
1026 
1027  case MetaActionType::FONT :
1028  {
1029  maFont = static_cast<const MetaFontAction*>(pMA)->GetFont();
1030  rVDev.SetFont( maFont );
1031  }
1032  break;
1033 
1034  case MetaActionType::PUSH :
1035  {
1036  rVDev.Push(static_cast<const MetaPushAction*>(pMA)->GetFlags() );
1037  StackMember* pGS = new StackMember;
1038  pGS->pSucc = pGDIStack;
1039  pGDIStack = pGS;
1040  pGS->aDashArray = aDashArray;
1041  pGS->eJoinType = eJoinType;
1042  pGS->eLineCap = eLineCap;
1043  pGS->fLineWidth = fLineWidth;
1044  pGS->fMiterLimit = fMiterLimit;
1045  pGS->eTextAlign = eTextAlign;
1046  pGS->aGlobalCol = aColor;
1047  pGS->bLineCol = bLineColor;
1048  pGS->aLineCol = aLineColor;
1049  pGS->bFillCol = bFillColor;
1050  pGS->aFillCol = aFillColor;
1051  pGS->aTextCol = aTextColor;
1052  pGS->bTextFillCol = bTextFillColor;
1053  pGS->aTextFillCol = aTextFillColor;
1054  pGS->aBackgroundCol = aBackgroundColor;
1055  pGS->aFont = maFont;
1056  mnLatestPush = mpPS->Tell();
1057  ImplWriteLine( "gs" );
1058  }
1059  break;
1060 
1061  case MetaActionType::POP :
1062  {
1063  rVDev.Pop();
1064  if( pGDIStack )
1065  {
1066  StackMember* pGS = pGDIStack;
1067  pGDIStack = pGS->pSucc;
1068  aDashArray = pGS->aDashArray;
1069  eJoinType = pGS->eJoinType;
1070  eLineCap = pGS->eLineCap;
1071  fLineWidth = pGS->fLineWidth;
1072  fMiterLimit = pGS->fMiterLimit;
1073  eTextAlign = pGS->eTextAlign;
1074  aColor = pGS->aGlobalCol;
1075  bLineColor = pGS->bLineCol;
1076  aLineColor = pGS->aLineCol;
1077  bFillColor = pGS->bFillCol;
1078  aFillColor = pGS->aFillCol;
1079  aTextColor = pGS->aTextCol;
1080  bTextFillColor = pGS->bTextFillCol;
1081  aTextFillColor = pGS->aTextFillCol;
1082  aBackgroundColor = pGS->aBackgroundCol;
1083  maFont = pGS->aFont;
1084  maLastFont = vcl::Font(); // set maLastFont != maFont -> so that
1085  delete pGS;
1086  sal_uInt32 nCurrentPos = mpPS->Tell();
1087  if ( nCurrentPos - 3 == mnLatestPush )
1088  {
1089  mpPS->Seek( mnLatestPush );
1090  ImplWriteLine( " " );
1091  mpPS->Seek( mnLatestPush );
1092  }
1093  else
1094  ImplWriteLine( "gr" );
1095  }
1096  }
1097  break;
1098 
1099  case MetaActionType::EPS :
1100  {
1101  GfxLink aGfxLink = static_cast<const MetaEPSAction*>(pMA)->GetLink();
1102  const GDIMetaFile aSubstitute( static_cast<const MetaEPSAction*>(pMA)->GetSubstitute() );
1103 
1104  bool bLevelConflict = false;
1105  sal_uInt8* pSource = const_cast<sal_uInt8*>(aGfxLink.GetData());
1106  sal_uInt32 nSize = aGfxLink.GetDataSize();
1107  sal_uInt32 nParseThis = POSTSCRIPT_BOUNDINGSEARCH;
1108  if ( nSize < 64 ) // assuming eps is larger than 64 bytes
1109  pSource = nullptr;
1110  if ( nParseThis > nSize )
1111  nParseThis = nSize;
1112 
1113  if ( pSource && ( mnLevel == 1 ) )
1114  {
1115  sal_uInt8* pFound = ImplSearchEntry( pSource, reinterpret_cast<sal_uInt8 const *>("%%LanguageLevel:"), nParseThis - 10, 16 );
1116  if ( pFound )
1117  {
1118  sal_uInt8 k, i = 10;
1119  pFound += 16;
1120  while ( --i )
1121  {
1122  k = *pFound++;
1123  if ( ( k > '0' ) && ( k <= '9' ) )
1124  {
1125  if ( k != '1' )
1126  {
1127  bLevelConflict = true;
1128  mbLevelWarning = true;
1129  }
1130  break;
1131  }
1132  }
1133  }
1134  }
1135  if ( !bLevelConflict )
1136  {
1137  double nBoundingBox[4];
1138  if ( pSource && ImplGetBoundingBox( nBoundingBox, pSource, nParseThis ) )
1139  {
1140  Point aPoint = static_cast<const MetaEPSAction*>(pMA)->GetPoint();
1141  Size aSize = static_cast<const MetaEPSAction*>(pMA)->GetSize();
1142 
1143  MapMode aMapMode( aSubstitute.GetPrefMapMode() );
1144  Size aOutSize( OutputDevice::LogicToLogic( aSize, rVDev.GetMapMode(), aMapMode ) );
1145  Point aOrigin( OutputDevice::LogicToLogic( aPoint, rVDev.GetMapMode(), aMapMode ) );
1146  aOrigin.AdjustY(aOutSize.Height() );
1147  aMapMode.SetOrigin( aOrigin );
1148  aMapMode.SetScaleX( Fraction(aOutSize.Width() / ( nBoundingBox[ 2 ] - nBoundingBox[ 0 ] )) );
1149  aMapMode.SetScaleY( Fraction(aOutSize.Height() / ( nBoundingBox[ 3 ] - nBoundingBox[ 1 ] )) );
1150  ImplWriteLine( "gs" );
1151  ImplGetMapMode( aMapMode );
1152  ImplWriteLine( "%%BeginDocument:" );
1153  mpPS->WriteBytes(pSource, aGfxLink.GetDataSize());
1154  ImplWriteLine( "%%EndDocument\ngr" );
1155  }
1156  }
1157  }
1158  break;
1159 
1161  {
1162  // TODO: implement!
1163  }
1164  break;
1165 
1167  {
1168  pMA->Execute( &rVDev );
1169  }
1170  break;
1171 
1173  {
1174  const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pMA);
1175 
1176  GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
1177  Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
1178  const Size aSrcSize( aTmpMtf.GetPrefSize() );
1179  const Point aDestPt( pA->GetPoint() );
1180  const Size aDestSize( pA->GetSize() );
1181  const double fScaleX = aSrcSize.Width() ? static_cast<double>(aDestSize.Width()) / aSrcSize.Width() : 1.0;
1182  const double fScaleY = aSrcSize.Height() ? static_cast<double>(aDestSize.Height()) / aSrcSize.Height() : 1.0;
1183  tools::Long nMoveX, nMoveY;
1184 
1185  if( fScaleX != 1.0 || fScaleY != 1.0 )
1186  {
1187  aTmpMtf.Scale( fScaleX, fScaleY );
1188  aSrcPt.setX( FRound( aSrcPt.X() * fScaleX ) );
1189  aSrcPt.setY( FRound( aSrcPt.Y() * fScaleY ) );
1190  }
1191 
1192  nMoveX = aDestPt.X() - aSrcPt.X();
1193  nMoveY = aDestPt.Y() - aSrcPt.Y();
1194 
1195  if( nMoveX || nMoveY )
1196  aTmpMtf.Move( nMoveX, nMoveY );
1197 
1198  ImplWriteActions( aTmpMtf, rVDev );
1199  }
1200  break;
1201 
1203  {
1204  const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pMA);
1205  if ( pA->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN") )
1206  {
1207  const MetaGradientExAction* pGradAction = nullptr;
1208  while( ++nCurAction < nCount )
1209  {
1210  MetaAction* pAction = rMtf.GetAction( nCurAction );
1211  if( pAction->GetType() == MetaActionType::GRADIENTEX )
1212  pGradAction = static_cast<const MetaGradientExAction*>(pAction);
1213  else if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
1214  ( static_cast<const MetaCommentAction*>(pAction)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END") ) )
1215  {
1216  break;
1217  }
1218  }
1219 
1220  if( pGradAction )
1221  ImplWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), rVDev );
1222  }
1223  else if ( pA->GetComment() == "XPATHFILL_SEQ_END" )
1224  {
1225  if ( aFillPath.Count() )
1226  {
1227  aFillPath = tools::PolyPolygon();
1228  ImplWriteLine( "gr" );
1229  }
1230  }
1231  else
1232  {
1233  const sal_uInt8* pData = pA->GetData();
1234  if ( pData )
1235  {
1236  SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pData), pA->GetDataSize(), StreamMode::READ );
1237  bool bSkipSequence = false;
1238  OString sSeqEnd;
1239 
1240  if( pA->GetComment() == "XPATHSTROKE_SEQ_BEGIN" )
1241  {
1242  sSeqEnd = "XPATHSTROKE_SEQ_END";
1243  SvtGraphicStroke aStroke;
1244  ReadSvtGraphicStroke( aMemStm, aStroke );
1245 
1246  tools::Polygon aPath;
1247  aStroke.getPath( aPath );
1248 
1249  tools::PolyPolygon aStartArrow;
1250  tools::PolyPolygon aEndArrow;
1251  double fStrokeWidth( aStroke.getStrokeWidth() );
1252  SvtGraphicStroke::JoinType eJT( aStroke.getJoinType() );
1253  SvtGraphicStroke::DashArray l_aDashArray;
1254 
1255  aStroke.getStartArrow( aStartArrow );
1256  aStroke.getEndArrow( aEndArrow );
1257  aStroke.getDashArray( l_aDashArray );
1258 
1259  bSkipSequence = true;
1260  if ( l_aDashArray.size() > 11 ) // ps dasharray limit is 11
1261  bSkipSequence = false;
1262  if ( aStartArrow.Count() || aEndArrow.Count() )
1263  bSkipSequence = false;
1264  if ( static_cast<sal_uInt32>(eJT) > 2 )
1265  bSkipSequence = false;
1266  if ( !l_aDashArray.empty() && ( fStrokeWidth != 0.0 ) )
1267  bSkipSequence = false;
1268  if ( bSkipSequence )
1269  {
1270  ImplWriteLineInfo( fStrokeWidth, aStroke.getMiterLimit(),
1271  aStroke.getCapType(), eJT, l_aDashArray );
1272  ImplPolyLine( aPath );
1273  }
1274  }
1275  else if (pA->GetComment() == "XPATHFILL_SEQ_BEGIN")
1276  {
1277  sSeqEnd = "XPATHFILL_SEQ_END";
1278  SvtGraphicFill aFill;
1279  ReadSvtGraphicFill( aMemStm, aFill );
1280  switch( aFill.getFillType() )
1281  {
1283  {
1284  bSkipSequence = true;
1285  tools::PolyPolygon aPolyPoly;
1286  aFill.getPath( aPolyPoly );
1287  sal_uInt16 i, nPolyCount = aPolyPoly.Count();
1288  if ( nPolyCount )
1289  {
1290  aFillColor = aFill.getFillColor();
1291  ImplWriteFillColor( PS_SPACE );
1292  for ( i = 0; i < nPolyCount; )
1293  {
1294  ImplAddPath( aPolyPoly.GetObject( i ) );
1295  if ( ++i < nPolyCount )
1296  {
1297  mpPS->WriteCharPtr( "p" );
1298  mnCursorPos += 2;
1299  ImplExecMode( PS_RET );
1300  }
1301  }
1302  mpPS->WriteCharPtr( "p ef" );
1303  mnCursorPos += 4;
1304  ImplExecMode( PS_RET );
1305  }
1306  }
1307  break;
1308 
1310  {
1311  aFill.getPath( aFillPath );
1312 
1313  /* normally an object filling is consisting of three MetaActions:
1314  MetaBitmapAction using RasterOp xor,
1315  MetaPolyPolygonAction using RasterOp rop_0
1316  MetaBitmapAction using RasterOp xor
1317 
1318  Because RasterOps cannot been used in Postscript, we have to
1319  replace these actions. The MetaComment "XPATHFILL_SEQ_BEGIN" is
1320  providing the clippath of the object. The following loop is
1321  trying to find the bitmap that is matching the clippath, so that
1322  only one bitmap is exported, otherwise if the bitmap is not
1323  locatable, all metaactions are played normally.
1324  */
1325  sal_uInt32 nCommentStartAction = nCurAction;
1326  sal_uInt32 nBitmapCount = 0;
1327  sal_uInt32 nBitmapAction = 0;
1328 
1329  bool bOk = true;
1330  while( bOk && ( ++nCurAction < nCount ) )
1331  {
1332  MetaAction* pAction = rMtf.GetAction( nCurAction );
1333  switch( pAction->GetType() )
1334  {
1339  {
1340  nBitmapCount++;
1341  nBitmapAction = nCurAction;
1342  }
1343  break;
1345  {
1346  if (static_cast<const MetaCommentAction*>(pAction)->GetComment() == "XPATHFILL_SEQ_END")
1347  bOk = false;
1348  }
1349  break;
1350  default: break;
1351  }
1352  }
1353  if( nBitmapCount == 2 )
1354  {
1355  ImplWriteLine( "gs" );
1356  ImplIntersect( aFillPath );
1357  GDIMetaFile aTempMtf;
1358  aTempMtf.AddAction( rMtf.GetAction( nBitmapAction )->Clone() );
1359  ImplWriteActions( aTempMtf, rVDev );
1360  ImplWriteLine( "gr" );
1361  aFillPath = tools::PolyPolygon();
1362  }
1363  else
1364  nCurAction = nCommentStartAction + 1;
1365  }
1366  break;
1367 
1369  aFill.getPath( aFillPath );
1370  break;
1371 
1373  break;
1374  }
1375  if ( aFillPath.Count() )
1376  {
1377  ImplWriteLine( "gs" );
1378  ImplIntersect( aFillPath );
1379  }
1380  }
1381  if ( bSkipSequence )
1382  {
1383  while( ++nCurAction < nCount )
1384  {
1385  pMA = rMtf.GetAction( nCurAction );
1386  if ( pMA->GetType() == MetaActionType::COMMENT )
1387  {
1388  OString sComment( static_cast<MetaCommentAction*>(pMA)->GetComment() );
1389  if ( sComment == sSeqEnd )
1390  break;
1391  }
1392  }
1393  }
1394  }
1395  }
1396  }
1397  break;
1398  default: break;
1399  }
1400  }
1401 }
1402 
1403 inline void PSWriter::ImplWritePoint( const Point& rPoint )
1404 {
1405  ImplWriteDouble( rPoint.X() );
1406  ImplWriteDouble( rPoint.Y() );
1407 }
1408 
1409 void PSWriter::ImplMoveTo( const Point& rPoint )
1410 {
1411  ImplWritePoint( rPoint );
1412  ImplWriteByte( 'm' );
1413  ImplExecMode( PS_SPACE );
1414 }
1415 
1416 void PSWriter::ImplLineTo( const Point& rPoint, NMode nMode )
1417 {
1418  ImplWritePoint( rPoint );
1419  ImplWriteByte( 'l' );
1420  ImplExecMode( nMode );
1421 }
1422 
1423 void PSWriter::ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, NMode nMode )
1424 {
1425  ImplWritePoint( rP1 );
1426  ImplWritePoint( rP2 );
1427  ImplWritePoint( rP3 );
1428  mpPS->WriteCharPtr( "ct " );
1429  ImplExecMode( nMode );
1430 }
1431 
1432 void PSWriter::ImplTranslate( const double& fX, const double& fY )
1433 {
1434  ImplWriteDouble( fX );
1435  ImplWriteDouble( fY );
1436  ImplWriteByte( 't' );
1437  ImplExecMode( PS_RET );
1438 }
1439 
1440 void PSWriter::ImplScale( const double& fX, const double& fY )
1441 {
1442  ImplWriteDouble( fX );
1443  ImplWriteDouble( fY );
1444  ImplWriteByte( 's' );
1445  ImplExecMode( PS_RET );
1446 }
1447 
1448 void PSWriter::ImplRect( const tools::Rectangle & rRect )
1449 {
1450  if ( bFillColor )
1451  ImplRectFill( rRect );
1452  if ( bLineColor )
1453  {
1454  double nWidth = rRect.GetWidth();
1455  double nHeight = rRect.GetHeight();
1456 
1457  ImplWriteLineColor( PS_SPACE );
1458  ImplMoveTo( rRect.TopLeft() );
1459  ImplWriteDouble( nWidth );
1460  mpPS->WriteCharPtr( "0 rl 0 " );
1461  ImplWriteDouble( nHeight );
1462  mpPS->WriteCharPtr( "rl " );
1463  ImplWriteDouble( nWidth );
1464  mpPS->WriteCharPtr( "neg 0 rl " );
1465  ImplClosePathDraw();
1466  }
1467  mpPS->WriteUChar( 10 );
1468  mnCursorPos = 0;
1469 }
1470 
1471 void PSWriter::ImplRectFill( const tools::Rectangle & rRect )
1472 {
1473  double nWidth = rRect.GetWidth();
1474  double nHeight = rRect.GetHeight();
1475 
1476  ImplWriteFillColor( PS_SPACE );
1477  ImplMoveTo( rRect.TopLeft() );
1478  ImplWriteDouble( nWidth );
1479  mpPS->WriteCharPtr( "0 rl 0 " );
1480  ImplWriteDouble( nHeight );
1481  mpPS->WriteCharPtr( "rl " );
1482  ImplWriteDouble( nWidth );
1483  mpPS->WriteCharPtr( "neg 0 rl ef " );
1484  mpPS->WriteCharPtr( "p ef" );
1485  mnCursorPos += 2;
1486  ImplExecMode( PS_RET );
1487 }
1488 
1489 void PSWriter::ImplAddPath( const tools::Polygon & rPolygon )
1490 {
1491  sal_uInt16 nPointCount = rPolygon.GetSize();
1492  if ( nPointCount <= 1 )
1493  return;
1494 
1495  sal_uInt16 i = 1;
1496  ImplMoveTo( rPolygon.GetPoint( 0 ) );
1497  while ( i < nPointCount )
1498  {
1499  if ( ( rPolygon.GetFlags( i ) == PolyFlags::Control )
1500  && ( ( i + 2 ) < nPointCount )
1501  && ( rPolygon.GetFlags( i + 1 ) == PolyFlags::Control )
1502  && ( rPolygon.GetFlags( i + 2 ) != PolyFlags::Control ) )
1503  {
1504  ImplCurveTo( rPolygon[ i ], rPolygon[ i + 1 ], rPolygon[ i + 2 ], PS_WRAP );
1505  i += 3;
1506  }
1507  else
1508  ImplLineTo( rPolygon.GetPoint( i++ ), PS_SPACE | PS_WRAP );
1509  }
1510 }
1511 
1512 void PSWriter::ImplIntersect( const tools::PolyPolygon& rPolyPoly )
1513 {
1514  sal_uInt16 i, nPolyCount = rPolyPoly.Count();
1515  for ( i = 0; i < nPolyCount; )
1516  {
1517  ImplAddPath( rPolyPoly.GetObject( i ) );
1518  if ( ++i < nPolyCount )
1519  {
1520  mpPS->WriteCharPtr( "p" );
1521  mnCursorPos += 2;
1522  ImplExecMode( PS_RET );
1523  }
1524  }
1525  ImplWriteLine( "eoclip newpath" );
1526 }
1527 
1528 void PSWriter::ImplWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev )
1529 {
1531  GDIMetaFile aTmpMtf;
1532  l_pVDev->SetMapMode( rVDev.GetMapMode() );
1533  l_pVDev->AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf );
1534  ImplWriteActions( aTmpMtf, rVDev );
1535 }
1536 
1537 void PSWriter::ImplPolyPoly( const tools::PolyPolygon & rPolyPoly, bool bTextOutline )
1538 {
1539  sal_uInt16 i, nPolyCount = rPolyPoly.Count();
1540  if ( !nPolyCount )
1541  return;
1542 
1543  if ( bFillColor || bTextOutline )
1544  {
1545  if ( bTextOutline )
1546  ImplWriteTextColor( PS_SPACE );
1547  else
1548  ImplWriteFillColor( PS_SPACE );
1549  for ( i = 0; i < nPolyCount; )
1550  {
1551  ImplAddPath( rPolyPoly.GetObject( i ) );
1552  if ( ++i < nPolyCount )
1553  {
1554  mpPS->WriteCharPtr( "p" );
1555  mnCursorPos += 2;
1556  ImplExecMode( PS_RET );
1557  }
1558  }
1559  mpPS->WriteCharPtr( "p ef" );
1560  mnCursorPos += 4;
1561  ImplExecMode( PS_RET );
1562  }
1563  if ( bLineColor )
1564  {
1565  ImplWriteLineColor( PS_SPACE );
1566  for ( i = 0; i < nPolyCount; i++ )
1567  ImplAddPath( rPolyPoly.GetObject( i ) );
1568  ImplClosePathDraw();
1569  }
1570 }
1571 
1572 void PSWriter::ImplPolyLine( const tools::Polygon & rPoly )
1573 {
1574  if ( !bLineColor )
1575  return;
1576 
1577  ImplWriteLineColor( PS_SPACE );
1578  sal_uInt16 i, nPointCount = rPoly.GetSize();
1579  if ( !nPointCount )
1580  return;
1581 
1582  if ( nPointCount > 1 )
1583  {
1584  ImplMoveTo( rPoly.GetPoint( 0 ) );
1585  i = 1;
1586  while ( i < nPointCount )
1587  {
1588  if ( ( rPoly.GetFlags( i ) == PolyFlags::Control )
1589  && ( ( i + 2 ) < nPointCount )
1590  && ( rPoly.GetFlags( i + 1 ) == PolyFlags::Control )
1591  && ( rPoly.GetFlags( i + 2 ) != PolyFlags::Control ) )
1592  {
1593  ImplCurveTo( rPoly[ i ], rPoly[ i + 1 ], rPoly[ i + 2 ], PS_WRAP );
1594  i += 3;
1595  }
1596  else
1597  ImplLineTo( rPoly.GetPoint( i++ ), PS_SPACE | PS_WRAP );
1598  }
1599  }
1600 
1601  // #104645# explicitly close path if polygon is closed
1602  if( rPoly[ 0 ] == rPoly[ nPointCount-1 ] )
1603  ImplClosePathDraw();
1604  else
1605  ImplPathDraw();
1606 }
1607 
1608 void PSWriter::ImplSetClipRegion( vcl::Region const & rClipRegion )
1609 {
1610  if ( rClipRegion.IsEmpty() )
1611  return;
1612 
1613  RectangleVector aRectangles;
1614  rClipRegion.GetRegionRectangles(aRectangles);
1615 
1616  for (auto const& rectangle : aRectangles)
1617  {
1618  double nX1(rectangle.Left());
1619  double nY1(rectangle.Top());
1620  double nX2(rectangle.Right());
1621  double nY2(rectangle.Bottom());
1622 
1623  ImplWriteDouble( nX1 );
1624  ImplWriteDouble( nY1 );
1625  ImplWriteByte( 'm' );
1626  ImplWriteDouble( nX2 );
1627  ImplWriteDouble( nY1 );
1628  ImplWriteByte( 'l' );
1629  ImplWriteDouble( nX2 );
1630  ImplWriteDouble( nY2 );
1631  ImplWriteByte( 'l' );
1632  ImplWriteDouble( nX1 );
1633  ImplWriteDouble( nY2 );
1634  ImplWriteByte( 'l' );
1635  ImplWriteDouble( nX1 );
1636  ImplWriteDouble( nY1 );
1637  ImplWriteByte( 'l', PS_SPACE | PS_WRAP );
1638  }
1639 
1640  ImplWriteLine( "eoclip newpath" );
1641 }
1642 
1643 // possible gfx formats:
1644 //
1645 // level 1: grayscale 8 bit
1646 // color 24 bit
1647 //
1648 // level 2: grayscale 8 bit
1649 // color 1(pal), 4(pal), 8(pal), 24 Bit
1650 //
1651 
1652 void PSWriter::ImplBmp( Bitmap const * pBitmap, Bitmap const * pMaskBitmap, const Point & rPoint, double nXWidth, double nYHeightOrg )
1653 {
1654  if ( !pBitmap )
1655  return;
1656 
1657  sal_Int32 nHeightOrg = pBitmap->GetSizePixel().Height();
1658  sal_Int32 nHeightLeft = nHeightOrg;
1659  tools::Long nWidth = pBitmap->GetSizePixel().Width();
1660  Point aSourcePos( rPoint );
1661 
1662  while ( nHeightLeft )
1663  {
1664  Bitmap aTileBitmap( *pBitmap );
1665  tools::Long nHeight = nHeightLeft;
1666  double nYHeight = nYHeightOrg;
1667 
1668  bool bDoTrans = false;
1669 
1670  tools::Rectangle aRect;
1671  vcl::Region aRegion;
1672 
1673  if ( pMaskBitmap )
1674  {
1675  bDoTrans = true;
1676  while (true)
1677  {
1678  if ( mnLevel == 1 && nHeight > 10 )
1679  nHeight = 8;
1680  aRect = tools::Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) );
1681  aRegion = pMaskBitmap->CreateRegion( COL_BLACK, aRect );
1682 
1683  if( mnLevel == 1 )
1684  {
1685  RectangleVector aRectangleVector;
1686  aRegion.GetRegionRectangles(aRectangleVector);
1687 
1688  if ( aRectangleVector.size() * 5 > 1000 )
1689  {
1690  nHeight >>= 1;
1691  if ( nHeight < 2 )
1692  return;
1693  continue;
1694  }
1695  }
1696  break;
1697  }
1698  }
1699  if ( nHeight != nHeightOrg )
1700  {
1701  nYHeight = nYHeightOrg * nHeight / nHeightOrg;
1702  aTileBitmap.Crop( tools::Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) ) );
1703  }
1704  if ( bDoTrans )
1705  {
1706  ImplWriteLine( "gs\npum" );
1707  ImplTranslate( aSourcePos.X(), aSourcePos.Y() );
1708  ImplScale( nXWidth / nWidth, nYHeight / nHeight );
1709 
1710  RectangleVector aRectangles;
1711  aRegion.GetRegionRectangles(aRectangles);
1712  const tools::Long nMoveVertical(nHeightLeft - nHeightOrg);
1713 
1714  for (auto & rectangle : aRectangles)
1715  {
1716  rectangle.Move(0, nMoveVertical);
1717 
1718  ImplWriteLong( rectangle.Left() );
1719  ImplWriteLong( rectangle.Top() );
1720  ImplWriteByte( 'm' );
1721  ImplWriteLong( rectangle.Right() + 1 );
1722  ImplWriteLong( rectangle.Top() );
1723  ImplWriteByte( 'l' );
1724  ImplWriteLong( rectangle.Right() + 1 );
1725  ImplWriteLong( rectangle.Bottom() + 1 );
1726  ImplWriteByte( 'l' );
1727  ImplWriteLong( rectangle.Left() );
1728  ImplWriteLong( rectangle.Bottom() + 1 );
1729  ImplWriteByte( 'l' );
1730  ImplWriteByte( 'p', PS_SPACE | PS_WRAP );
1731  }
1732 
1733  ImplWriteLine( "eoclip newpath" );
1734  ImplWriteLine( "pom" );
1735  }
1736  BitmapReadAccess* pAcc = aTileBitmap.AcquireReadAccess();
1737 
1738  if (!bDoTrans )
1739  ImplWriteLine( "pum" );
1740 
1741  ImplTranslate( aSourcePos.X(), aSourcePos.Y() + nYHeight );
1742  ImplScale( nXWidth, nYHeight );
1743  if ( mnLevel == 1 ) // level 1 is always grayscale !!!
1744  {
1745  ImplWriteLong( nWidth );
1746  ImplWriteLong( nHeight );
1747  mpPS->WriteCharPtr( "8 [" );
1748  ImplWriteLong( nWidth );
1749  mpPS->WriteCharPtr( "0 0 " );
1750  ImplWriteLong( -nHeight );
1751  ImplWriteLong( 0 );
1752  ImplWriteLong( nHeight );
1753  ImplWriteLine( "]" );
1754  mpPS->WriteCharPtr( "{currentfile " );
1755  ImplWriteLong( nWidth );
1756  ImplWriteLine( "string readhexstring pop}" );
1757  ImplWriteLine( "image" );
1758  for ( tools::Long y = 0; y < nHeight; y++ )
1759  {
1760  Scanline pScanlineRead = pAcc->GetScanline( y );
1761  for ( tools::Long x = 0; x < nWidth; x++ )
1762  {
1763  ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
1764  }
1765  }
1766  mpPS->WriteUChar( 10 );
1767  }
1768  else // Level 2
1769  {
1770  if ( mbGrayScale )
1771  {
1772  ImplWriteLine( "/DeviceGray setcolorspace" );
1773  ImplWriteLine( "<<" );
1774  ImplWriteLine( "/ImageType 1" );
1775  mpPS->WriteCharPtr( "/Width " );
1776  ImplWriteLong( nWidth, PS_RET );
1777  mpPS->WriteCharPtr( "/Height " );
1778  ImplWriteLong( nHeight, PS_RET );
1779  ImplWriteLine( "/BitsPerComponent 8" );
1780  ImplWriteLine( "/Decode[0 1]" );
1781  mpPS->WriteCharPtr( "/ImageMatrix[" );
1782  ImplWriteLong( nWidth );
1783  mpPS->WriteCharPtr( "0 0 " );
1784  ImplWriteLong( -nHeight );
1785  ImplWriteLong( 0 );
1786  ImplWriteLong( nHeight, PS_NONE );
1787  ImplWriteByte( ']', PS_RET );
1788  ImplWriteLine( "/DataSource currentfile" );
1789  ImplWriteLine( "/ASCIIHexDecode filter" );
1790  if ( mbCompression )
1791  ImplWriteLine( "/LZWDecode filter" );
1792  ImplWriteLine( ">>" );
1793  ImplWriteLine( "image" );
1794  if ( mbCompression )
1795  {
1796  StartCompression();
1797  for ( tools::Long y = 0; y < nHeight; y++ )
1798  {
1799  Scanline pScanlineRead = pAcc->GetScanline( y );
1800  for ( tools::Long x = 0; x < nWidth; x++ )
1801  {
1802  Compress( pAcc->GetIndexFromData( pScanlineRead, x ) );
1803  }
1804  }
1805  EndCompression();
1806  }
1807  else
1808  {
1809  for ( tools::Long y = 0; y < nHeight; y++ )
1810  {
1811  Scanline pScanlineRead = pAcc->GetScanline( y );
1812  for ( tools::Long x = 0; x < nWidth; x++ )
1813  {
1814  ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
1815  }
1816  }
1817  }
1818  }
1819  else
1820  {
1821  // have we to write a palette ?
1822 
1823  if ( pAcc->HasPalette() )
1824  {
1825  ImplWriteLine( "[/Indexed /DeviceRGB " );
1826  ImplWriteLong( pAcc->GetPaletteEntryCount() - 1, PS_RET );
1827  ImplWriteByte( '<', PS_NONE );
1828  for ( sal_uInt16 i = 0; i < pAcc->GetPaletteEntryCount(); i++ )
1829  {
1830  BitmapColor aBitmapColor = pAcc->GetPaletteColor( i );
1831  ImplWriteHexByte( aBitmapColor.GetRed(), PS_NONE );
1832  ImplWriteHexByte( aBitmapColor.GetGreen(), PS_NONE );
1833  ImplWriteHexByte( aBitmapColor.GetBlue(), PS_SPACE | PS_WRAP );
1834  }
1835  ImplWriteByte( '>', PS_RET );
1836 
1837  ImplWriteLine( "] setcolorspace" );
1838  ImplWriteLine( "<<" );
1839  ImplWriteLine( "/ImageType 1" );
1840  mpPS->WriteCharPtr( "/Width " );
1841  ImplWriteLong( nWidth, PS_RET );
1842  mpPS->WriteCharPtr( "/Height " );
1843  ImplWriteLong( nHeight, PS_RET );
1844  ImplWriteLine( "/BitsPerComponent 8" );
1845  ImplWriteLine( "/Decode[0 255]" );
1846  mpPS->WriteCharPtr( "/ImageMatrix[" );
1847  ImplWriteLong( nWidth );
1848  mpPS->WriteCharPtr( "0 0 " );
1849  ImplWriteLong( -nHeight );
1850  ImplWriteLong( 0);
1851  ImplWriteLong( nHeight, PS_NONE );
1852  ImplWriteByte( ']', PS_RET );
1853  ImplWriteLine( "/DataSource currentfile" );
1854  ImplWriteLine( "/ASCIIHexDecode filter" );
1855  if ( mbCompression )
1856  ImplWriteLine( "/LZWDecode filter" );
1857  ImplWriteLine( ">>" );
1858  ImplWriteLine( "image" );
1859  if ( mbCompression )
1860  {
1861  StartCompression();
1862  for ( tools::Long y = 0; y < nHeight; y++ )
1863  {
1864  Scanline pScanlineRead = pAcc->GetScanline( y );
1865  for ( tools::Long x = 0; x < nWidth; x++ )
1866  {
1867  Compress( pAcc->GetIndexFromData( pScanlineRead, x ) );
1868  }
1869  }
1870  EndCompression();
1871  }
1872  else
1873  {
1874  for ( tools::Long y = 0; y < nHeight; y++ )
1875  {
1876  Scanline pScanlineRead = pAcc->GetScanline( y );
1877  for ( tools::Long x = 0; x < nWidth; x++ )
1878  {
1879  ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
1880  }
1881  }
1882  }
1883  }
1884  else // 24 bit color
1885  {
1886  ImplWriteLine( "/DeviceRGB setcolorspace" );
1887  ImplWriteLine( "<<" );
1888  ImplWriteLine( "/ImageType 1" );
1889  mpPS->WriteCharPtr( "/Width " );
1890  ImplWriteLong( nWidth, PS_RET );
1891  mpPS->WriteCharPtr( "/Height " );
1892  ImplWriteLong( nHeight, PS_RET );
1893  ImplWriteLine( "/BitsPerComponent 8" );
1894  ImplWriteLine( "/Decode[0 1 0 1 0 1]" );
1895  mpPS->WriteCharPtr( "/ImageMatrix[" );
1896  ImplWriteLong( nWidth );
1897  mpPS->WriteCharPtr( "0 0 " );
1898  ImplWriteLong( -nHeight );
1899  ImplWriteLong( 0 );
1900  ImplWriteLong( nHeight, PS_NONE );
1901  ImplWriteByte( ']', PS_RET );
1902  ImplWriteLine( "/DataSource currentfile" );
1903  ImplWriteLine( "/ASCIIHexDecode filter" );
1904  if ( mbCompression )
1905  ImplWriteLine( "/LZWDecode filter" );
1906  ImplWriteLine( ">>" );
1907  ImplWriteLine( "image" );
1908  if ( mbCompression )
1909  {
1910  StartCompression();
1911  for ( tools::Long y = 0; y < nHeight; y++ )
1912  {
1913  Scanline pScanlineRead = pAcc->GetScanline( y );
1914  for ( tools::Long x = 0; x < nWidth; x++ )
1915  {
1916  const BitmapColor aBitmapColor( pAcc->GetPixelFromData( pScanlineRead, x ) );
1917  Compress( aBitmapColor.GetRed() );
1918  Compress( aBitmapColor.GetGreen() );
1919  Compress( aBitmapColor.GetBlue() );
1920  }
1921  }
1922  EndCompression();
1923  }
1924  else
1925  {
1926  for ( tools::Long y = 0; y < nHeight; y++ )
1927  {
1928  Scanline pScanline = pAcc->GetScanline( y );
1929  for ( tools::Long x = 0; x < nWidth; x++ )
1930  {
1931  const BitmapColor aBitmapColor( pAcc->GetPixelFromData( pScanline, x ) );
1932  ImplWriteHexByte( aBitmapColor.GetRed() );
1933  ImplWriteHexByte( aBitmapColor.GetGreen() );
1934  ImplWriteHexByte( aBitmapColor.GetBlue() );
1935  }
1936  }
1937  }
1938  }
1939  }
1940  ImplWriteLine( ">" ); // in Level 2 the dictionary needs to be closed (eod)
1941  }
1942  if ( bDoTrans )
1943  ImplWriteLine( "gr" );
1944  else
1945  ImplWriteLine( "pom" );
1946 
1947  Bitmap::ReleaseAccess( pAcc );
1948  nHeightLeft -= nHeight;
1949  if ( nHeightLeft )
1950  {
1951  nHeightLeft++;
1952  aSourcePos.setY( static_cast<tools::Long>( rPoint.Y() + ( nYHeightOrg * ( nHeightOrg - nHeightLeft ) ) / nHeightOrg ) );
1953  }
1954  }
1955 }
1956 
1957 void PSWriter::ImplWriteCharacter( char nChar )
1958 {
1959  switch( nChar )
1960  {
1961  case '(' :
1962  case ')' :
1963  case '\\' :
1964  ImplWriteByte( sal_uInt8('\\'), PS_NONE );
1965  }
1966  ImplWriteByte( static_cast<sal_uInt8>(nChar), PS_NONE );
1967 }
1968 
1969 void PSWriter::ImplWriteString( const OString& rString, VirtualDevice const & rVDev, const tools::Long* pDXArry, bool bStretch )
1970 {
1971  sal_Int32 nLen = rString.getLength();
1972  if ( !nLen )
1973  return;
1974 
1975  if ( pDXArry )
1976  {
1977  double nx = 0;
1978 
1979  for (sal_Int32 i = 0; i < nLen; ++i)
1980  {
1981  if ( i > 0 )
1982  nx = pDXArry[ i - 1 ];
1983  ImplWriteDouble( bStretch ? nx : rVDev.GetTextWidth( OUString(rString[i]) ) );
1984  ImplWriteDouble( nx );
1985  ImplWriteLine( "(", PS_NONE );
1986  ImplWriteCharacter( rString[i] );
1987  ImplWriteLine( ") bs" );
1988  }
1989  }
1990  else
1991  {
1992  ImplWriteByte( '(', PS_NONE );
1993  for (sal_Int32 i = 0; i < nLen; ++i)
1994  ImplWriteCharacter( rString[i] );
1995  ImplWriteLine( ") sw" );
1996  }
1997 }
1998 
1999 void PSWriter::ImplText( const OUString& rUniString, const Point& rPos, const tools::Long* pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev )
2000 {
2001  if ( rUniString.isEmpty() )
2002  return;
2003  if ( mnTextMode == 0 ) // using glyph outlines
2004  {
2005  vcl::Font aNotRotatedFont( maFont );
2006  aNotRotatedFont.SetOrientation( 0_deg10 );
2007 
2009  pVirDev->SetMapMode( rVDev.GetMapMode() );
2010  pVirDev->SetFont( aNotRotatedFont );
2011  pVirDev->SetTextAlign( eTextAlign );
2012 
2013  Degree10 nRotation = maFont.GetOrientation();
2014  tools::Polygon aPolyDummy( 1 );
2015 
2016  Point aPos( rPos );
2017  if ( nRotation )
2018  {
2019  aPolyDummy.SetPoint( aPos, 0 );
2020  aPolyDummy.Rotate( rPos, nRotation );
2021  aPos = aPolyDummy.GetPoint( 0 );
2022  }
2023  bool bOldLineColor = bLineColor;
2024  bLineColor = false;
2025  std::vector<tools::PolyPolygon> aPolyPolyVec;
2026  if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniString, 0, 0, -1, nWidth, pDXArry ) )
2027  {
2028  // always adjust text position to match baseline alignment
2029  ImplWriteLine( "pum" );
2030  ImplWriteDouble( aPos.X() );
2031  ImplWriteDouble( aPos.Y() );
2032  ImplWriteLine( "t" );
2033  if ( nRotation )
2034  {
2035  ImplWriteF( nRotation.get(), 1 );
2036  mpPS->WriteCharPtr( "r " );
2037  }
2038  for (auto const& elem : aPolyPolyVec)
2039  ImplPolyPoly( elem, true );
2040  ImplWriteLine( "pom" );
2041  }
2042  bLineColor = bOldLineColor;
2043  }
2044  else if ( ( mnTextMode == 1 ) || ( mnTextMode == 2 ) ) // normal text output
2045  {
2046  if ( mnTextMode == 2 ) // forcing output one complete text packet, by
2047  pDXArry = nullptr; // ignoring the kerning array
2048  ImplSetAttrForText( rPos );
2049  OString aStr(OUStringToOString(rUniString,
2050  maFont.GetCharSet()));
2051  ImplWriteString( aStr, rVDev, pDXArry, nWidth != 0 );
2052  if ( maFont.GetOrientation() )
2053  ImplWriteLine( "gr" );
2054  }
2055 }
2056 
2057 void PSWriter::ImplSetAttrForText( const Point& rPoint )
2058 {
2059  Point aPoint( rPoint );
2060 
2061  Degree10 nRotation = maFont.GetOrientation();
2062  ImplWriteTextColor(PS_RET);
2063 
2064  Size aSize = maFont.GetFontSize();
2065 
2066  if ( maLastFont != maFont )
2067  {
2068  if ( maFont.GetPitch() == PITCH_FIXED ) // a little bit font selection
2069  ImplDefineFont( "Courier", "Oblique" );
2070  else if ( maFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
2071  ImplWriteLine( "/Symbol findfont" );
2072  else if ( maFont.GetFamilyType() == FAMILY_SWISS )
2073  ImplDefineFont( "Helvetica", "Oblique" );
2074  else
2075  ImplDefineFont( "Times", "Italic" );
2076 
2077  maLastFont = maFont;
2078  aSize = maFont.GetFontSize();
2079  ImplWriteDouble( aSize.Height() );
2080  mpPS->WriteCharPtr( "sf " );
2081  }
2082  if ( eTextAlign != ALIGN_BASELINE )
2083  { // PostScript does not know about FontAlignment
2084  if ( eTextAlign == ALIGN_TOP ) // -> so I assume that
2085  aPoint.AdjustY( aSize.Height() * 4 / 5 ); // the area under the baseline
2086  else if ( eTextAlign == ALIGN_BOTTOM ) // is about 20% of the font size
2087  aPoint.AdjustY( -( aSize.Height() / 5 ) );
2088  }
2089  ImplMoveTo( aPoint );
2090  if ( nRotation )
2091  {
2092  mpPS->WriteCharPtr( "gs " );
2093  ImplWriteF( nRotation.get(), 1 );
2094  mpPS->WriteCharPtr( "r " );
2095  }
2096 }
2097 
2098 void PSWriter::ImplDefineFont( const char* pOriginalName, const char* pItalic )
2099 {
2100  mpPS->WriteUChar( '/' ); //convert the font pOriginalName using ISOLatin1Encoding
2101  mpPS->WriteCharPtr( pOriginalName );
2102  switch ( maFont.GetWeight() )
2103  {
2104  case WEIGHT_SEMIBOLD :
2105  case WEIGHT_BOLD :
2106  case WEIGHT_ULTRABOLD :
2107  case WEIGHT_BLACK :
2108  mpPS->WriteCharPtr( "-Bold" );
2109  if ( maFont.GetItalic() != ITALIC_NONE )
2110  mpPS->WriteCharPtr( pItalic );
2111  break;
2112  default:
2113  if ( maFont.GetItalic() != ITALIC_NONE )
2114  mpPS->WriteCharPtr( pItalic );
2115  break;
2116  }
2117  ImplWriteLine( " f" );
2118 }
2119 
2120 void PSWriter::ImplClosePathDraw()
2121 {
2122  mpPS->WriteCharPtr( "pc" );
2123  mnCursorPos += 2;
2124  ImplExecMode( PS_RET );
2125 }
2126 
2127 void PSWriter::ImplPathDraw()
2128 {
2129  mpPS->WriteCharPtr( "ps" );
2130  mnCursorPos += 2;
2131  ImplExecMode( PS_RET );
2132 }
2133 
2134 
2135 inline void PSWriter::ImplWriteLineColor( NMode nMode )
2136 {
2137  if ( aColor != aLineColor )
2138  {
2139  aColor = aLineColor;
2140  ImplWriteColor( nMode );
2141  }
2142 }
2143 
2144 inline void PSWriter::ImplWriteFillColor( NMode nMode )
2145 {
2146  if ( aColor != aFillColor )
2147  {
2148  aColor = aFillColor;
2149  ImplWriteColor( nMode );
2150  }
2151 }
2152 
2153 inline void PSWriter::ImplWriteTextColor( NMode nMode )
2154 {
2155  if ( aColor != aTextColor )
2156  {
2157  aColor = aTextColor;
2158  ImplWriteColor( nMode );
2159  }
2160 }
2161 
2162 void PSWriter::ImplWriteColor( NMode nMode )
2163 {
2164  if ( mbGrayScale )
2165  {
2166  // writes the Color (grayscale) as a Number from 0.000 up to 1.000
2167 
2168  ImplWriteF( 1000 * ( aColor.GetRed() * 77 + aColor.GetGreen() * 151 +
2169  aColor.GetBlue() * 28 + 1 ) / 65536, 3, nMode );
2170  }
2171  else
2172  {
2173  ImplWriteB1 ( aColor.GetRed() );
2174  ImplWriteB1 ( aColor.GetGreen() );
2175  ImplWriteB1 ( aColor.GetBlue() );
2176  }
2177  mpPS->WriteCharPtr( "c" ); // ( c is defined as setrgbcolor or setgray )
2178  ImplExecMode( nMode );
2179 }
2180 
2181 void PSWriter::ImplGetMapMode( const MapMode& rMapMode )
2182 {
2183  ImplWriteLine( "tm setmatrix" );
2184  double fMul = ImplGetScaling(rMapMode);
2185  double fScaleX = static_cast<double>(rMapMode.GetScaleX()) * fMul;
2186  double fScaleY = static_cast<double>(rMapMode.GetScaleY()) * fMul;
2187  ImplTranslate( rMapMode.GetOrigin().X() * fScaleX, rMapMode.GetOrigin().Y() * fScaleY );
2188  ImplScale( fScaleX, fScaleY );
2189 }
2190 
2191 inline void PSWriter::ImplExecMode( NMode nMode )
2192 {
2193  if ( nMode & PS_WRAP )
2194  {
2195  if ( mnCursorPos >= PS_LINESIZE )
2196  {
2197  mnCursorPos = 0;
2198  mpPS->WriteUChar( 0xa );
2199  return;
2200  }
2201  }
2202  if ( nMode & PS_SPACE )
2203  {
2204  mpPS->WriteUChar( 32 );
2205  mnCursorPos++;
2206  }
2207  if ( nMode & PS_RET )
2208  {
2209  mpPS->WriteUChar( 0xa );
2210  mnCursorPos = 0;
2211  }
2212 }
2213 
2214 inline void PSWriter::ImplWriteLine( const char* pString, NMode nMode )
2215 {
2216  sal_uInt32 i = 0;
2217  while ( pString[ i ] )
2218  {
2219  mpPS->WriteUChar( pString[ i++ ] );
2220  }
2221  mnCursorPos += i;
2222  ImplExecMode( nMode );
2223 }
2224 
2225 double PSWriter::ImplGetScaling( const MapMode& rMapMode )
2226 {
2227  double nMul;
2228  switch (rMapMode.GetMapUnit())
2229  {
2230  case MapUnit::MapPixel :
2231  case MapUnit::MapSysFont :
2232  case MapUnit::MapAppFont :
2233 
2234  case MapUnit::Map100thMM :
2235  nMul = 1;
2236  break;
2237  case MapUnit::Map10thMM :
2238  nMul = 10;
2239  break;
2240  case MapUnit::MapMM :
2241  nMul = 100;
2242  break;
2243  case MapUnit::MapCM :
2244  nMul = 1000;
2245  break;
2246  case MapUnit::Map1000thInch :
2247  nMul = 2.54;
2248  break;
2249  case MapUnit::Map100thInch :
2250  nMul = 25.4;
2251  break;
2252  case MapUnit::Map10thInch :
2253  nMul = 254;
2254  break;
2255  case MapUnit::MapInch :
2256  nMul = 2540;
2257  break;
2258  case MapUnit::MapTwip :
2259  nMul = 1.76388889;
2260  break;
2261  case MapUnit::MapPoint :
2262  nMul = 35.27777778;
2263  break;
2264  default:
2265  nMul = 1.0;
2266  break;
2267  }
2268  return nMul;
2269 }
2270 
2271 
2272 void PSWriter::ImplWriteLineInfo( double fLWidth, double fMLimit,
2275  SvtGraphicStroke::DashArray const & rLDash )
2276 {
2277  if ( fLineWidth != fLWidth )
2278  {
2279  fLineWidth = fLWidth;
2280  ImplWriteDouble( fLineWidth );
2281  ImplWriteLine( "lw", PS_SPACE );
2282  }
2283  if ( eLineCap != eLCap )
2284  {
2285  eLineCap = eLCap;
2286  ImplWriteLong( static_cast<sal_Int32>(eLineCap) );
2287  ImplWriteLine( "lc", PS_SPACE );
2288  }
2289  if ( eJoinType != eJoin )
2290  {
2291  eJoinType = eJoin;
2292  ImplWriteLong( static_cast<sal_Int32>(eJoinType) );
2293  ImplWriteLine( "lj", PS_SPACE );
2294  }
2295  if ( eJoinType == SvtGraphicStroke::joinMiter )
2296  {
2297  if ( fMiterLimit != fMLimit )
2298  {
2299  fMiterLimit = fMLimit;
2300  ImplWriteDouble( fMiterLimit );
2301  ImplWriteLine( "ml", PS_SPACE );
2302  }
2303  }
2304  if ( aDashArray != rLDash )
2305  {
2306  aDashArray = rLDash;
2307  sal_uInt32 j, i = aDashArray.size();
2308  ImplWriteLine( "[", PS_SPACE );
2309  for ( j = 0; j < i; j++ )
2310  ImplWriteDouble( aDashArray[ j ] );
2311  ImplWriteLine( "] 0 ld" );
2312  }
2313 }
2314 
2315 void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo )
2316 {
2317  SvtGraphicStroke::DashArray l_aDashArray;
2318  if ( rLineInfo.GetStyle() == LineStyle::Dash )
2319  l_aDashArray.push_back( 2 );
2320  const double fLWidth(( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5);
2323 
2324  switch(rLineInfo.GetLineJoin())
2325  {
2327  // do NOT use SvtGraphicStroke::joinNone here
2328  // since it will be written as numerical value directly
2329  // and is NOT a valid EPS value
2330  break;
2332  aJoinType = SvtGraphicStroke::joinMiter;
2333  break;
2335  aJoinType = SvtGraphicStroke::joinBevel;
2336  break;
2338  aJoinType = SvtGraphicStroke::joinRound;
2339  break;
2340  }
2341  switch(rLineInfo.GetLineCap())
2342  {
2343  default: /* css::drawing::LineCap_BUTT */
2344  {
2345  aCapType = SvtGraphicStroke::capButt;
2346  break;
2347  }
2348  case css::drawing::LineCap_ROUND:
2349  {
2350  aCapType = SvtGraphicStroke::capRound;
2351  break;
2352  }
2353  case css::drawing::LineCap_SQUARE:
2354  {
2355  aCapType = SvtGraphicStroke::capSquare;
2356  break;
2357  }
2358  }
2359 
2360  ImplWriteLineInfo( fLWidth, fMiterLimit, aCapType, aJoinType, l_aDashArray );
2361 }
2362 
2363 void PSWriter::ImplWriteLong(sal_Int32 nNumber, NMode nMode)
2364 {
2365  const OString aNumber(OString::number(nNumber));
2366  mnCursorPos += aNumber.getLength();
2367  mpPS->WriteOString( aNumber );
2368  ImplExecMode(nMode);
2369 }
2370 
2371 void PSWriter::ImplWriteDouble( double fNumber )
2372 {
2373  sal_Int32 nPTemp = static_cast<sal_Int32>(fNumber);
2374  sal_Int32 nATemp = std::abs( static_cast<sal_Int32>( ( fNumber - nPTemp ) * 100000 ) );
2375 
2376  if ( !nPTemp && nATemp && ( fNumber < 0.0 ) )
2377  mpPS->WriteChar( '-' );
2378 
2379  const OString aNumber1(OString::number(nPTemp));
2380  mpPS->WriteOString( aNumber1 );
2381  mnCursorPos += aNumber1.getLength();
2382 
2383  if ( nATemp )
2384  {
2385  int zCount = 0;
2386  mpPS->WriteUChar( '.' );
2387  mnCursorPos++;
2388  const OString aNumber2(OString::number(nATemp));
2389 
2390  sal_Int16 n, nLen = aNumber2.getLength();
2391  if ( nLen < 8 )
2392  {
2393  mnCursorPos += 6 - nLen;
2394  for ( n = 0; n < ( 5 - nLen ); n++ )
2395  {
2396  mpPS->WriteUChar( '0' );
2397  }
2398  }
2399  mnCursorPos += nLen;
2400  for ( n = 0; n < nLen; n++ )
2401  {
2402  mpPS->WriteChar( aNumber2[n] );
2403  zCount--;
2404  if ( aNumber2[n] != '0' )
2405  zCount = 0;
2406  }
2407  if ( zCount )
2408  mpPS->SeekRel( zCount );
2409  }
2410  ImplExecMode( PS_SPACE );
2411 }
2412 
2414 void PSWriter::ImplWriteF( sal_Int32 nNumber, sal_uInt8 nCount, NMode nMode )
2415 {
2416  if ( nNumber < 0 )
2417  {
2418  mpPS->WriteUChar( '-' );
2419  nNumber = -nNumber;
2420  mnCursorPos++;
2421  }
2422  const OString aScaleFactor(OString::number(nNumber));
2423  sal_uInt32 nLen = aScaleFactor.getLength();
2424  sal_Int32 const nStSize = (nCount + 1) - nLen;
2425  static_assert(sizeof(nStSize) == sizeof((nCount + 1) - nLen)); // tdf#134667
2426  if ( nStSize >= 1 )
2427  {
2428  mpPS->WriteUChar( '0' );
2429  mnCursorPos++;
2430  }
2431  if ( nStSize >= 2 )
2432  {
2433  mpPS->WriteUChar( '.' );
2434  for (sal_Int32 i = 1; i < nStSize; ++i)
2435  {
2436  mpPS->WriteUChar( '0' );
2437  mnCursorPos++;
2438  }
2439  }
2440  mnCursorPos += nLen;
2441  for( sal_uInt32 n = 0; n < nLen; n++ )
2442  {
2443  if ( n == nLen - nCount )
2444  {
2445  mpPS->WriteUChar( '.' );
2446  mnCursorPos++;
2447  }
2448  mpPS->WriteChar( aScaleFactor[n] );
2449  }
2450  ImplExecMode( nMode );
2451 }
2452 
2453 void PSWriter::ImplWriteByte( sal_uInt8 nNumb, NMode nMode )
2454 {
2455  mpPS->WriteUChar( nNumb );
2456  mnCursorPos++;
2457  ImplExecMode( nMode );
2458 }
2459 
2460 void PSWriter::ImplWriteHexByte( sal_uInt8 nNumb, NMode nMode )
2461 {
2462  if ( ( nNumb >> 4 ) > 9 )
2463  mpPS->WriteUChar( ( nNumb >> 4 ) + 'A' - 10 );
2464  else
2465  mpPS->WriteUChar( ( nNumb >> 4 ) + '0' );
2466 
2467  if ( ( nNumb & 0xf ) > 9 )
2468  mpPS->WriteUChar( ( nNumb & 0xf ) + 'A' - 10 );
2469  else
2470  mpPS->WriteUChar( ( nNumb & 0xf ) + '0' );
2471  mnCursorPos += 2;
2472  ImplExecMode( nMode );
2473 }
2474 
2475 // writes the sal_uInt8 nNumb as a Number from 0.000 up to 1.000
2476 
2477 void PSWriter::ImplWriteB1( sal_uInt8 nNumb )
2478 {
2479  ImplWriteF( 1000 * ( nNumb + 1 ) / 256 );
2480 }
2481 
2482 inline void PSWriter::WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen )
2483 {
2484  dwShift |= ( nCode << ( nOffset - nCodeLen ) );
2485  nOffset -= nCodeLen;
2486  while ( nOffset < 24 )
2487  {
2488  ImplWriteHexByte( static_cast<sal_uInt8>( dwShift >> 24 ) );
2489  dwShift <<= 8;
2490  nOffset += 8;
2491  }
2492  if ( nCode == 257 && nOffset != 32 )
2493  ImplWriteHexByte( static_cast<sal_uInt8>( dwShift >> 24 ) );
2494 }
2495 
2496 void PSWriter::StartCompression()
2497 {
2498  sal_uInt16 i;
2499  nDataSize = 8;
2500 
2501  nClearCode = 1 << nDataSize;
2502  nEOICode = nClearCode + 1;
2503  nTableSize = nEOICode + 1;
2504  nCodeSize = nDataSize + 1;
2505 
2506  nOffset = 32; // number of free unused in dwShift
2507  dwShift = 0;
2508 
2509  pTable.reset(new PSLZWCTreeNode[ 4096 ]);
2510 
2511  for ( i = 0; i < 4096; i++ )
2512  {
2513  pTable[ i ].pBrother = pTable[ i ].pFirstChild = nullptr;
2514  pTable[ i ].nCode = i;
2515  pTable[ i ].nValue = static_cast<sal_uInt8>( i );
2516  }
2517  pPrefix = nullptr;
2518  WriteBits( nClearCode, nCodeSize );
2519 }
2520 
2521 void PSWriter::Compress( sal_uInt8 nCompThis )
2522 {
2523  PSLZWCTreeNode* p;
2524  sal_uInt16 i;
2525  sal_uInt8 nV;
2526 
2527  if( !pPrefix )
2528  {
2529  pPrefix = pTable.get() + nCompThis;
2530  }
2531  else
2532  {
2533  nV = nCompThis;
2534  for( p = pPrefix->pFirstChild; p != nullptr; p = p->pBrother )
2535  {
2536  if ( p->nValue == nV )
2537  break;
2538  }
2539 
2540  if( p )
2541  pPrefix = p;
2542  else
2543  {
2544  WriteBits( pPrefix->nCode, nCodeSize );
2545 
2546  if ( nTableSize == 409 )
2547  {
2548  WriteBits( nClearCode, nCodeSize );
2549 
2550  for ( i = 0; i < nClearCode; i++ )
2551  pTable[ i ].pFirstChild = nullptr;
2552 
2553  nCodeSize = nDataSize + 1;
2554  nTableSize = nEOICode + 1;
2555  }
2556  else
2557  {
2558  if( nTableSize == static_cast<sal_uInt16>( ( 1 << nCodeSize ) - 1 ) )
2559  nCodeSize++;
2560 
2561  p = pTable.get() + ( nTableSize++ );
2562  p->pBrother = pPrefix->pFirstChild;
2563  pPrefix->pFirstChild = p;
2564  p->nValue = nV;
2565  p->pFirstChild = nullptr;
2566  }
2567 
2568  pPrefix = pTable.get() + nV;
2569  }
2570  }
2571 }
2572 
2573 void PSWriter::EndCompression()
2574 {
2575  if( pPrefix )
2576  WriteBits( pPrefix->nCode, nCodeSize );
2577 
2578  WriteBits( nEOICode, nCodeSize );
2579  pTable.reset();
2580 }
2581 
2582 sal_uInt8* PSWriter::ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uInt32 nComp, sal_uInt32 nSize )
2583 {
2584  while ( nComp-- >= nSize )
2585  {
2586  sal_uInt64 i;
2587  for ( i = 0; i < nSize; i++ )
2588  {
2589  if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
2590  break;
2591  }
2592  if ( i == nSize )
2593  return pSource;
2594  pSource++;
2595  }
2596  return nullptr;
2597 }
2598 
2599 bool PSWriter::ImplGetBoundingBox( double* nNumb, sal_uInt8* pSource, sal_uInt32 nSize )
2600 {
2601  bool bRetValue = false;
2602  sal_uInt32 nBytesRead;
2603 
2604  if ( nSize < 256 ) // we assume that the file is greater than 256 bytes
2605  return false;
2606 
2607  if ( nSize < POSTSCRIPT_BOUNDINGSEARCH )
2608  nBytesRead = nSize;
2609  else
2610  nBytesRead = POSTSCRIPT_BOUNDINGSEARCH;
2611 
2612  sal_uInt8* pDest = ImplSearchEntry( pSource, reinterpret_cast<sal_uInt8 const *>("%%BoundingBox:"), nBytesRead, 14 );
2613  if ( pDest )
2614  {
2615  int nSecurityCount = 100; // only 100 bytes following the bounding box will be checked
2616  nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
2617  pDest += 14;
2618  for ( int i = 0; ( i < 4 ) && nSecurityCount; i++ )
2619  {
2620  int nDivision = 1;
2621  bool bDivision = false;
2622  bool bNegative = false;
2623  bool bValid = true;
2624 
2625  while ( ( --nSecurityCount ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) )
2626  pDest++;
2627  sal_uInt8 nByte = *pDest;
2628  while ( nSecurityCount && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
2629  {
2630  switch ( nByte )
2631  {
2632  case '.' :
2633  if ( bDivision )
2634  bValid = false;
2635  else
2636  bDivision = true;
2637  break;
2638  case '-' :
2639  bNegative = true;
2640  break;
2641  default :
2642  if ( ( nByte < '0' ) || ( nByte > '9' ) )
2643  nSecurityCount = 1; // error parsing the bounding box values
2644  else if ( bValid )
2645  {
2646  if ( bDivision )
2647  nDivision*=10;
2648  nNumb[i] *= 10;
2649  nNumb[i] += nByte - '0';
2650  }
2651  break;
2652  }
2653  nSecurityCount--;
2654  nByte = *(++pDest);
2655  }
2656  if ( bNegative )
2657  nNumb[i] = -nNumb[i];
2658  if ( bDivision && ( nDivision != 1 ) )
2659  nNumb[i] /= nDivision;
2660  }
2661  if ( nSecurityCount)
2662  bRetValue = true;
2663  }
2664  return bRetValue;
2665 }
2666 
2667 //================== GraphicExport - the exported function ===================
2668 
2669 bool ExportEpsGraphic(SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pFilterConfigItem)
2670 {
2671  PSWriter aPSWriter;
2672  return aPSWriter.WritePS(rGraphic, rStream, pFilterConfigItem);
2673 }
2674 
2675 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
Point TopLeft() const
const Fraction & GetScaleX() const
Definition: mapmod.cxx:140
const Color & getFillColor() const
Get color used for solid fills.
virtual void Execute(OutputDevice *pOut)
Definition: metaact.cxx:168
sal_uInt8 GetIndexFromData(const sal_uInt8 *pData, tools::Long nX) const
CapType
Style for open stroke ends.
Bitmap GetMask() const
Definition: BitmapEx.cxx:246
const tools::Polygon & GetObject(sal_uInt16 nPos) const
sal_Int32 GetLen() const
Definition: metaact.hxx:500
sal_uInt8 GetRed() const
SvStream & WriteUInt16(sal_uInt16 nUInt16)
const GDIMetaFile & GetGDIMetaFile() const
Definition: metaact.hxx:1577
std::unique_ptr< ContentProperties > pData
Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1466
sal_Int16 mnLevel
const MapMode & GetPrefMapMode() const
Definition: gdimtf.hxx:178
virtual sal_uInt64 TellEnd()
long Long
constexpr::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
sal_Int64 n
Connect segments by a filled round arc.
Encapsulates geometry and associated attributes of a graphical 'pen stroke'.
moOpDF operator|(moOpDF a, moOpDF b)
const Point & GetPoint() const
Definition: metaact.hxx:1578
WEIGHT_BLACK
sal_uInt64 Seek(sal_uInt64 nPos)
const MapMode & GetMapMode() const
Definition: outdev.hxx:1690
WEIGHT_SEMIBOLD
tools::Long GetWidth() const
const OUString & GetText() const
Definition: metaact.hxx:572
Size GetSizePixel() const
SvStream & ReadSvtGraphicStroke(SvStream &rIStm, SvtGraphicStroke &rClass)
float x
void SetMapMode()
Definition: map.cxx:516
bool Convert(BmpConversion eConversion)
Convert bitmap format.
Definition: BitmapEx.cxx:432
SvStream & ReadSvtGraphicFill(SvStream &rIStm, SvtGraphicFill &rClass)
CapType getCapType() const
Get the style in which open stroke ends are drawn.
std::vector< tools::Rectangle > RectangleVector
Definition: region.hxx:37
const sal_uInt8 * GetData() const
Definition: metaact.hxx:1677
WEIGHT_BOLD
sal_Int32 ReadInt32(const OUString &rKey, sal_Int32 nDefault)
constexpr tools::Long Width() const
bool Crop(const tools::Rectangle &rRectPixel)
Crop the bitmap.
std::locale Create(const char *pPrefixName, const LanguageTag &rLocale)
tools::Long Left() const
Fill with the specified gradient.
const OUString & GetText() const
Definition: metaact.hxx:498
const Fraction & GetScaleY() const
Definition: mapmod.cxx:142
sal_uInt8 * ImplSearchEntry(sal_uInt8 *pSource, sal_uInt8 const *pDest, sal_uLong nComp, sal_uLong nSize)
Scanline GetScanline(tools::Long nY) const
PolyFlags GetFlags(sal_uInt16 nPos) const
Fill with a specified solid color.
int nCount
double getMiterLimit() const
Get the maximum length of mitered joins.
const GDIMetaFile & GetGDIMetaFile() const
Definition: graph.cxx:340
SvStream & WriteUInt32(sal_uInt32 nUInt32)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
sal_uInt8 GetBlue() const
sal_uInt16 nCode
static OUString getProductVersion()
float y
#define EPS_PREVIEW_EPSI
Definition: eps.cxx:52
bool IsEmpty() const
Definition: region.cxx:228
sal_uInt8 * Scanline
Definition: Scanline.hxx:26
UNDERLYING_TYPE get() const
No additional cap.
ALIGN_BASELINE
const Size & GetPrefSize() const
Definition: gdimtf.hxx:175
Half-square cap at the line end, the center lying at the end point.
int i
static OUString getProductName()
bool HasPalette() const
uno_Any a
Fill with the specified hatch.
GraphicType GetType() const
Definition: graph.cxx:294
const Point & GetPoint() const
Definition: metaact.hxx:497
PITCH_FIXED
tools::Long FRound(double fVal)
virtual rtl::Reference< MetaAction > Clone()
Definition: metaact.cxx:172
const Color & GetColor() const
Definition: wall.cxx:199
const Size & GetSize() const
Definition: metaact.hxx:1579
sal_uInt32 GetWidth() const
Definition: metaact.hxx:573
tools::Long Width() const
vcl::Region CreateRegion(const Color &rColor, const tools::Rectangle &rRect) const
Create region of similar colors in a given rectangle.
void getPath(tools::Polygon &) const
Query path to stroke.
sal_uInt16 GetSize() const
static void ReleaseAccess(BitmapInfoAccess *pAccess)
sal_Int32 GetLen() const
Definition: metaact.hxx:575
void Move(tools::Long nX, tools::Long nY)
Definition: gdimtf.cxx:632
MapUnit GetMapUnit() const
Definition: mapmod.cxx:136
WEIGHT_ULTRABOLD
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:330
ITALIC_NONE
NMode
Definition: eps.cxx:91
Fill with the specified texture (a Graphic object)
bool IsTransparent() const
Definition: BitmapEx.cxx:214
bool ExportEpsGraphic(SvStream &rStream, Graphic &rGraphic, FilterConfigItem *pFilterConfigItem)
Definition: eps.cxx:2669
tools::Long Top() const
FillType getFillType() const
Get fill type used.
void getStartArrow(tools::PolyPolygon &) const
Get the polygon that is put at the start of the line.
TextAlign
sal_uInt16 GetPaletteEntryCount() const
#define PS_LINESIZE
Definition: eps.cxx:54
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:229
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1021
const Point & GetPoint() const
Definition: metaact.hxx:571
sal_uInt8 GetGreen() const
const Point & GetPoint(sal_uInt16 nPos) const
static ErrCode Export(SvStream &rOStm, const Graphic &rGraphic, ConvertDataFormat nFormat)
Definition: cvtgrf.cxx:55
BitmapEx GetBitmap() const
Definition: wall.cxx:242
sal_uInt32 GetDataSize() const
Definition: metaact.hxx:1676
bool IsGradient() const
Definition: wall.cxx:278
def rectangle(l)
void getDashArray(DashArray &) const
Get an array of "on" and "off" lengths for stroke dashing.
double nx
Connect segments by a direct straight line.
JoinType
Style for joins of individual stroke segments.
::std::vector< double > DashArray
#define ERRCODE_NONE
Definition: errcode.hxx:196
constexpr tools::Long Height() const
unsigned char sal_uInt8
#define EPS_PREVIEW_TIFF
Definition: eps.cxx:51
bool Scale(const Size &rNewSize, BmpScaleFlag nScaleFlag=BmpScaleFlag::Default)
Scale the bitmap.
void SetFont(const vcl::Font &rNewFont)
bool Convert(BmpConversion eConversion)
Convert bitmap format.
void AddAction(const rtl::Reference< MetaAction > &pAction)
Definition: gdimtf.cxx:564
MetaAction * GetAction(size_t nAction) const
Definition: gdimtf.cxx:185
void SetEndian(SvStreamEndian SvStreamEndian)
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
FAMILY_SWISS
void GetRegionRectangles(RectangleVector &rTarget) const
Definition: region.cxx:1659
Half-round cap at the line end, the center lying at the end point.
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
Width of the text.
Definition: text.cxx:880
#define POSTSCRIPT_BOUNDINGSEARCH
Definition: eps.cxx:48
void Scale(double fScaleX, double fScaleY)
Definition: gdimtf.cxx:709
sal_uInt64 Tell() const
void * p
size_t GetActionSize() const
Definition: gdimtf.cxx:180
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
BitmapColor GetPixelFromData(const sal_uInt8 *pData, tools::Long nX) const
const Point & GetOrigin() const
Definition: mapmod.cxx:138
MetaActionType GetType() const
Definition: metaact.hxx:90
double getStrokeWidth() const
Get width of the stroke.
css::uno::Reference< css::task::XStatusIndicator > GetStatusIndicator() const
bool IsBitmap() const
Definition: wall.cxx:250
tools::Long GetHeight() const
JoinType getJoinType() const
Get the style in which the stroke segments are joined.
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
tools::Rectangle GetBoundRect() const
const BitmapColor & GetPaletteColor(sal_uInt16 nColor) const
const OString & GetComment() const
Definition: metaact.hxx:1674
Encapsulates geometry and associated attributes of a filled area.
OUString get(const char *pContextAndId, const std::locale &loc)
void getEndArrow(tools::PolyPolygon &) const
Get the polygon that is put at the end of the line.
void getPath(tools::PolyPolygon &) const
Query path to fill.
void Push(PushFlags nFlags=PushFlags::ALL)
Definition: outdevstate.cxx:59
Extend segment edges, until they cross.
BitmapColor GetBestMatchingColor(const BitmapColor &rBitmapColor)
aStr
sal_Int32 GetIndex() const
Definition: metaact.hxx:574
sal_Int32 GetIndex() const
Definition: metaact.hxx:499
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, bool bMobile=false)
Definition: builder.cxx:247
Point Center() const
sal_Int16 nValue