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