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