summaryrefslogtreecommitdiffstats
path: root/vcl/source/filter/eps/eps.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /vcl/source/filter/eps/eps.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/source/filter/eps/eps.cxx')
-rw-r--r--vcl/source/filter/eps/eps.cxx2667
1 files changed, 2667 insertions, 0 deletions
diff --git a/vcl/source/filter/eps/eps.cxx b/vcl/source/filter/eps/eps.cxx
new file mode 100644
index 000000000..bb25bdccb
--- /dev/null
+++ b/vcl/source/filter/eps/eps.cxx
@@ -0,0 +1,2667 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <filter/EpsWriter.hxx>
+#include <tools/stream.hxx>
+#include <tools/poly.hxx>
+#include <tools/fract.hxx>
+#include <tools/helpers.hxx>
+#include <unotools/resmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/metaact.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/BitmapReadAccess.hxx>
+#include <vcl/region.hxx>
+#include <vcl/font.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/cvtgrf.hxx>
+#include <vcl/gradient.hxx>
+#include <unotools/configmgr.hxx>
+#include <vcl/FilterConfigItem.hxx>
+#include <vcl/graphictools.hxx>
+#include <vcl/weld.hxx>
+#include <strings.hrc>
+#include <osl/diagnose.h>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <officecfg/Office/Common.hxx>
+
+#include <cstdlib>
+#include <memory>
+
+using namespace ::com::sun::star::uno;
+
+#define POSTSCRIPT_BOUNDINGSEARCH 0x1000 // we only try to get the BoundingBox
+ // in the first 4096 bytes
+
+#define EPS_PREVIEW_TIFF 1
+#define EPS_PREVIEW_EPSI 2
+
+#define PS_LINESIZE 70 // maximum number of characters a line in the output
+
+// -----------------------------field-types------------------------------
+
+namespace {
+
+struct StackMember
+{
+ struct StackMember * pSucc;
+ Color aGlobalCol;
+ bool bLineCol;
+ Color aLineCol;
+ bool bFillCol;
+ Color aFillCol;
+ Color aTextCol;
+ bool bTextFillCol;
+ Color aTextFillCol;
+ Color aBackgroundCol;
+ vcl::Font aFont;
+ TextAlign eTextAlign;
+
+ double fLineWidth;
+ double fMiterLimit;
+ SvtGraphicStroke::CapType eLineCap;
+ SvtGraphicStroke::JoinType eJoinType;
+ SvtGraphicStroke::DashArray aDashArray;
+};
+
+struct PSLZWCTreeNode
+{
+
+ PSLZWCTreeNode* pBrother; // next node who has the same father
+ PSLZWCTreeNode* pFirstChild; // first son
+ sal_uInt16 nCode; // The code for the string of pixel values, which arises if... <missing comment>
+ sal_uInt16 nValue; // the pixel value
+};
+
+enum NMode {PS_NONE = 0x00, PS_SPACE = 0x01, PS_RET = 0x02, PS_WRAP = 0x04}; // formatting mode: action which is inserted behind the output
+inline NMode operator|(NMode a, NMode b)
+{
+ return static_cast<NMode>(static_cast<sal_uInt8>(a) | static_cast<sal_uInt8>(b));
+}
+
+class PSWriter
+{
+private:
+ bool mbStatus;
+ bool mbLevelWarning; // if there any embedded eps file which was not exported
+ sal_uInt32 mnLatestPush; // offset to streamposition, where last push was done
+
+ tools::Long mnLevel; // dialog options
+ bool mbGrayScale;
+ bool mbCompression;
+ sal_Int32 mnPreview;
+ sal_Int32 mnTextMode;
+
+ SvStream* mpPS;
+ const GDIMetaFile* pMTF;
+ std::unique_ptr<GDIMetaFile>
+ pAMTF; // only created if Graphics is not a Metafile
+ ScopedVclPtrInstance<VirtualDevice>
+ pVDev;
+
+ double nBoundingX2; // this represents the bounding box
+ double nBoundingY2;
+
+ StackMember* pGDIStack;
+ sal_uInt32 mnCursorPos; // current cursor position in output
+ Color aColor; // current color which is used for output
+ bool bLineColor;
+ Color aLineColor; // current GDIMetafile color settings
+ bool bFillColor;
+ Color aFillColor;
+ Color aTextColor;
+ bool bTextFillColor;
+ Color aTextFillColor;
+ Color aBackgroundColor;
+ TextAlign eTextAlign;
+
+ double fLineWidth;
+ double fMiterLimit;
+ SvtGraphicStroke::CapType eLineCap;
+ SvtGraphicStroke::JoinType eJoinType;
+ SvtGraphicStroke::DashArray aDashArray;
+
+ vcl::Font maFont;
+ vcl::Font maLastFont;
+
+ std::unique_ptr<PSLZWCTreeNode[]> pTable; // LZW compression data
+ PSLZWCTreeNode* pPrefix; // the compression is as same as the TIFF compression
+ sal_uInt16 nDataSize;
+ sal_uInt16 nClearCode;
+ sal_uInt16 nEOICode;
+ sal_uInt16 nTableSize;
+ sal_uInt16 nCodeSize;
+ sal_uInt32 nOffset;
+ sal_uInt32 dwShift;
+
+ css::uno::Reference< css::task::XStatusIndicator > xStatusIndicator;
+
+ void ImplWriteProlog( const Graphic* pPreviewEPSI );
+ void ImplWriteEpilog();
+ void ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev );
+
+ // this method makes LF's, space inserting and word wrapping as used in all nMode
+ // parameters
+ inline void ImplExecMode( NMode nMode );
+
+ // writes char[] + LF to stream
+ inline void ImplWriteLine( const char*, NMode nMode = PS_RET );
+
+ // writes ( nNumb / 10^nCount ) in ASCII format to stream
+ void ImplWriteF( sal_Int32 nNumb, sal_uInt8 nCount = 3, NMode nMode = PS_SPACE );
+
+ // writes a double in ASCII format to stream
+ void ImplWriteDouble( double );
+
+ // writes a long in ASCII format to stream
+ void ImplWriteLong( sal_Int32 nNumb, NMode nMode = PS_SPACE );
+
+ // writes a byte in ASCII format to stream
+ void ImplWriteByte( sal_uInt8 nNumb, NMode nMode = PS_SPACE );
+
+ // writes a byte in ASCII (hex) format to stream
+ void ImplWriteHexByte( sal_uInt8 nNumb, NMode nMode = PS_WRAP );
+
+ // writes nNumb as number from 0.000 till 1.000 in ASCII format to stream
+ void ImplWriteB1( sal_uInt8 nNumb );
+
+ inline void ImplWritePoint( const Point& );
+ void ImplMoveTo( const Point& );
+ void ImplLineTo( const Point&, NMode nMode = PS_SPACE );
+ void ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, NMode nMode );
+ void ImplTranslate( const double& fX, const double& fY );
+ void ImplScale( const double& fX, const double& fY );
+
+ void ImplAddPath( const tools::Polygon & rPolygon );
+ void ImplWriteLineInfo( double fLineWidth, double fMiterLimit, SvtGraphicStroke::CapType eLineCap,
+ SvtGraphicStroke::JoinType eJoinType, SvtGraphicStroke::DashArray && rDashArray );
+ void ImplWriteLineInfo( const LineInfo& rLineInfo );
+ void ImplRect( const tools::Rectangle & rRectangle );
+ void ImplRectFill ( const tools::Rectangle & rRectangle );
+ void ImplWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev );
+ void ImplIntersect( const tools::PolyPolygon& rPolyPoly );
+ void ImplPolyPoly( const tools::PolyPolygon & rPolyPolygon, bool bTextOutline = false );
+ void ImplPolyLine( const tools::Polygon & rPolygon );
+
+ void ImplSetClipRegion( vcl::Region const & rRegion );
+ void ImplBmp( Bitmap const *, Bitmap const *, const Point &, double nWidth, double nHeight );
+ void ImplText( const OUString& rUniString, const Point& rPos, o3tl::span<const sal_Int32> pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev );
+ void ImplSetAttrForText( const Point & rPoint );
+ void ImplWriteCharacter( char );
+ void ImplWriteString( const OString&, VirtualDevice const & rVDev, o3tl::span<const sal_Int32> pDXArry, bool bStretch );
+ void ImplDefineFont( const char*, const char* );
+
+ void ImplClosePathDraw();
+ void ImplPathDraw();
+
+ inline void ImplWriteLineColor( NMode nMode );
+ inline void ImplWriteFillColor( NMode nMode );
+ inline void ImplWriteTextColor( NMode nMode );
+ void ImplWriteColor( NMode nMode );
+
+ static double ImplGetScaling( const MapMode& );
+ void ImplGetMapMode( const MapMode& );
+ static bool ImplGetBoundingBox( double* nNumb, sal_uInt8* pSource, sal_uInt32 nSize );
+ static sal_uInt8* ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uInt32 nComp, sal_uInt32 nSize );
+ // LZW methods
+ void StartCompression();
+ void Compress( sal_uInt8 nSrc );
+ void EndCompression();
+ inline void WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen );
+
+public:
+ bool WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* );
+ PSWriter();
+};
+
+}
+
+//========================== methods from PSWriter ==========================
+
+
+PSWriter::PSWriter()
+ : mbStatus(false)
+ , mbLevelWarning(false)
+ , mnLatestPush(0)
+ , mnLevel(0)
+ , mbGrayScale(false)
+ , mbCompression(false)
+ , mnPreview(0)
+ , mnTextMode(0)
+ , mpPS(nullptr)
+ , pMTF(nullptr)
+ , nBoundingX2(0)
+ , nBoundingY2(0)
+ , pGDIStack(nullptr)
+ , mnCursorPos(0)
+ , bLineColor(false)
+ , bFillColor(false)
+ , bTextFillColor(false)
+ , eTextAlign()
+ , fLineWidth(0)
+ , fMiterLimit(0)
+ , eLineCap()
+ , eJoinType()
+ , pPrefix(nullptr)
+ , nDataSize(0)
+ , nClearCode(0)
+ , nEOICode(0)
+ , nTableSize(0)
+ , nCodeSize(0)
+ , nOffset(0)
+ , dwShift(0)
+{
+}
+
+bool PSWriter::WritePS( const Graphic& rGraphic, SvStream& rTargetStream, FilterConfigItem* pFilterConfigItem )
+{
+ sal_uInt32 nStreamPosition = 0, nPSPosition = 0; // -Wall warning, unset, check
+
+ mbStatus = true;
+ mnPreview = 0;
+ mbLevelWarning = false;
+ mnLatestPush = 0xEFFFFFFE;
+
+ if ( pFilterConfigItem )
+ {
+ xStatusIndicator = pFilterConfigItem->GetStatusIndicator();
+ if ( xStatusIndicator.is() )
+ {
+ xStatusIndicator->start( OUString(), 100 );
+ }
+ }
+
+ mpPS = &rTargetStream;
+ mpPS->SetEndian( SvStreamEndian::LITTLE );
+
+ // default values for the dialog options
+ mnLevel = 2;
+ mbGrayScale = false;
+#ifdef UNX // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
+ mbCompression = false;
+#else
+ mbCompression = true;
+#endif
+ mnTextMode = 0; // default0 : export glyph outlines
+
+ // try to get the dialog selection
+ if ( pFilterConfigItem )
+ {
+#ifdef UNX // don't put binary tiff preview ahead of postscript code by default on unix as ghostscript is unable to read it
+ mnPreview = pFilterConfigItem->ReadInt32( "Preview", 0 );
+#else
+ mnPreview = pFilterConfigItem->ReadInt32( "Preview", 1 );
+#endif
+ mnLevel = pFilterConfigItem->ReadInt32( "Version", 2 );
+ if ( mnLevel != 1 )
+ mnLevel = 2;
+ mbGrayScale = pFilterConfigItem->ReadInt32( "ColorFormat", 1 ) == 2;
+#ifdef UNX // don't compress by default on unix as ghostscript is unable to read LZW compressed eps
+ mbCompression = pFilterConfigItem->ReadInt32( "CompressionMode", 0 ) != 0;
+#else
+ mbCompression = pFilterConfigItem->ReadInt32( "CompressionMode", 1 ) == 1;
+#endif
+ mnTextMode = pFilterConfigItem->ReadInt32( "TextMode", 0 );
+ if ( mnTextMode > 2 )
+ mnTextMode = 0;
+ }
+
+ // compression is not available for Level 1
+ if ( mnLevel == 1 )
+ {
+ mbGrayScale = true;
+ mbCompression = false;
+ }
+
+ if ( mnPreview & EPS_PREVIEW_TIFF )
+ {
+ rTargetStream.WriteUInt32( 0xC6D3D0C5 );
+ nStreamPosition = rTargetStream.Tell();
+ rTargetStream.WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 ).WriteUInt32( 0 )
+ .WriteUInt32( nStreamPosition + 26 ).WriteUInt32( 0 ).WriteUInt16( 0xffff );
+
+ ErrCode nErrCode;
+ if ( mbGrayScale )
+ {
+ BitmapEx aTempBitmapEx( rGraphic.GetBitmapEx() );
+ aTempBitmapEx.Convert( BmpConversion::N8BitGreys );
+ nErrCode = GraphicConverter::Export( rTargetStream, aTempBitmapEx, ConvertDataFormat::TIF ) ;
+ }
+ else
+ nErrCode = GraphicConverter::Export( rTargetStream, rGraphic, ConvertDataFormat::TIF ) ;
+
+ if ( nErrCode == ERRCODE_NONE )
+ {
+ nPSPosition = rTargetStream.TellEnd();
+ rTargetStream.Seek( nStreamPosition + 20 );
+ rTargetStream.WriteUInt32( nPSPosition - 30 ); // size of tiff gfx
+ rTargetStream.Seek( nPSPosition );
+ }
+ else
+ {
+ mnPreview &=~ EPS_PREVIEW_TIFF;
+ rTargetStream.Seek( nStreamPosition - 4 );
+ }
+ }
+
+ // global default value setting
+ StackMember* pGS;
+
+ if (rGraphic.GetType() == GraphicType::GdiMetafile)
+ pMTF = &rGraphic.GetGDIMetaFile();
+ else if (rGraphic.GetGDIMetaFile().GetActionSize())
+ {
+ pAMTF.reset( new GDIMetaFile( rGraphic.GetGDIMetaFile() ) );
+ pMTF = pAMTF.get();
+ }
+ else
+ {
+ BitmapEx aBmp( rGraphic.GetBitmapEx() );
+ pAMTF.reset( new GDIMetaFile );
+ ScopedVclPtrInstance< VirtualDevice > pTmpVDev;
+ pAMTF->Record( pTmpVDev );
+ pTmpVDev->DrawBitmapEx( Point(), aBmp );
+ pAMTF->Stop();
+ pAMTF->SetPrefSize( aBmp.GetSizePixel() );
+ pMTF = pAMTF.get();
+ }
+ pVDev->SetMapMode( pMTF->GetPrefMapMode() );
+ nBoundingX2 = pMTF->GetPrefSize().Width();
+ nBoundingY2 = pMTF->GetPrefSize().Height();
+
+ pGDIStack = nullptr;
+ aColor = COL_TRANSPARENT;
+ bLineColor = true;
+ aLineColor = COL_BLACK;
+ bFillColor = true;
+ aFillColor = COL_WHITE;
+ bTextFillColor = true;
+ aTextFillColor = COL_BLACK;
+ fLineWidth = 1;
+ fMiterLimit = 15; // use same limit as most graphic systems and basegfx
+ eLineCap = SvtGraphicStroke::capButt;
+ eJoinType = SvtGraphicStroke::joinMiter;
+ aBackgroundColor = COL_WHITE;
+ eTextAlign = ALIGN_BASELINE;
+
+ if( pMTF->GetActionSize() )
+ {
+ ImplWriteProlog( ( mnPreview & EPS_PREVIEW_EPSI ) ? &rGraphic : nullptr );
+ mnCursorPos = 0;
+ ImplWriteActions( *pMTF, *pVDev );
+ ImplWriteEpilog();
+ if ( mnPreview & EPS_PREVIEW_TIFF )
+ {
+ sal_uInt32 nPosition = rTargetStream.Tell();
+ rTargetStream.Seek( nStreamPosition );
+ rTargetStream.WriteUInt32( nPSPosition );
+ rTargetStream.WriteUInt32( nPosition - nPSPosition );
+ rTargetStream.Seek( nPosition );
+ }
+ while( pGDIStack )
+ {
+ pGS=pGDIStack;
+ pGDIStack=pGS->pSucc;
+ delete pGS;
+ }
+ }
+ else
+ mbStatus = false;
+
+ if ( mbStatus && mbLevelWarning && pFilterConfigItem )
+ {
+ std::locale loc = Translate::Create("flt");
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ Translate::get(KEY_VERSION_CHECK, loc)));
+ xInfoBox->run();
+ }
+
+ if ( xStatusIndicator.is() )
+ xStatusIndicator->end();
+
+ return mbStatus;
+}
+
+void PSWriter::ImplWriteProlog( const Graphic* pPreview )
+{
+ ImplWriteLine( "%!PS-Adobe-3.0 EPSF-3.0 " );
+ mpPS->WriteCharPtr( "%%BoundingBox: " ); // BoundingBox
+ ImplWriteLong( 0 );
+ ImplWriteLong( 0 );
+ Size aSizePoint = OutputDevice::LogicToLogic( pMTF->GetPrefSize(),
+ pMTF->GetPrefMapMode(), MapMode(MapUnit::MapPoint));
+ ImplWriteLong( aSizePoint.Width() );
+ ImplWriteLong( aSizePoint.Height() ,PS_RET );
+ ImplWriteLine( "%%Pages: 0" );
+ OUString aCreator;
+ OUString aCreatorOverride = officecfg::Office::Common::Save::Document::GeneratorOverride::get();
+ if( !aCreatorOverride.isEmpty())
+ aCreator = aCreatorOverride;
+ else
+ aCreator = "%%Creator: " + utl::ConfigManager::getProductName() + " " +
+ utl::ConfigManager::getProductVersion();
+ ImplWriteLine( OUStringToOString( aCreator, RTL_TEXTENCODING_UTF8 ).getStr() );
+ ImplWriteLine( "%%Title: none" );
+ ImplWriteLine( "%%CreationDate: none" );
+
+// defaults
+
+ mpPS->WriteCharPtr( "%%LanguageLevel: " ); // Language level
+ ImplWriteLong( mnLevel, PS_RET );
+ if ( !mbGrayScale && mnLevel == 1 )
+ ImplWriteLine( "%%Extensions: CMYK" ); // CMYK extension is to set in color mode in level 1
+ ImplWriteLine( "%%EndComments" );
+ if ( pPreview && aSizePoint.Width() && aSizePoint.Height() )
+ {
+ Size aSizeBitmap( ( aSizePoint.Width() + 7 ) & ~7, aSizePoint.Height() );
+ Bitmap aTmpBitmap( pPreview->GetBitmapEx().GetBitmap() );
+ aTmpBitmap.Scale( aSizeBitmap, BmpScaleFlag::BestQuality );
+ aTmpBitmap.Convert( BmpConversion::N1BitThreshold );
+ BitmapReadAccess* pAcc = aTmpBitmap.AcquireReadAccess();
+ if ( pAcc )
+ {
+ mpPS->WriteCharPtr( "%%BeginPreview: " ); // BoundingBox
+ ImplWriteLong( aSizeBitmap.Width() );
+ ImplWriteLong( aSizeBitmap.Height() );
+ mpPS->WriteCharPtr( "1 " );
+ sal_Int32 nLines = aSizeBitmap.Width() / 312;
+ if ( ( nLines * 312 ) != aSizeBitmap.Width() )
+ nLines++;
+ nLines *= aSizeBitmap.Height();
+ ImplWriteLong( nLines );
+ sal_Int32 nCount2, nCount = 4;
+ const BitmapColor aBlack( pAcc->GetBestMatchingColor( COL_BLACK ) );
+ for ( tools::Long nY = 0; nY < aSizeBitmap.Height(); nY++ )
+ {
+ nCount2 = 0;
+ char nVal = 0;
+ Scanline pScanline = pAcc->GetScanline( nY );
+ for ( tools::Long nX = 0; nX < aSizeBitmap.Width(); nX++ )
+ {
+ if ( !nCount2 )
+ {
+ ImplExecMode( PS_RET );
+ mpPS->WriteCharPtr( "%" );
+ nCount2 = 312;
+ }
+ nVal <<= 1;
+ if ( pAcc->GetPixelFromData( pScanline, nX ) == aBlack )
+ nVal |= 1;
+ if ( ! ( --nCount ) )
+ {
+ if ( nVal > 9 )
+ nVal += 'A' - 10;
+ else
+ nVal += '0';
+ mpPS->WriteChar( nVal );
+ nVal = 0;
+ nCount += 4;
+ }
+ nCount2--;
+ }
+ }
+ Bitmap::ReleaseAccess( pAcc );
+ ImplExecMode( PS_RET );
+ ImplWriteLine( "%%EndPreview" );
+ }
+ }
+ ImplWriteLine( "%%BeginProlog" );
+ ImplWriteLine( "%%BeginResource: procset SDRes-Prolog 1.0 0" );
+
+// BEGIN EPSF
+ ImplWriteLine( "/b4_inc_state save def\n/dict_count countdictstack def\n/op_count count 1 sub def\nuserdict begin" );
+ ImplWriteLine( "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit[] 0 setdash newpath" );
+ ImplWriteLine( "/languagelevel where {pop languagelevel 1 ne {false setstrokeadjust false setoverprint} if} if" );
+
+ ImplWriteLine( "/bdef {bind def} bind def" ); // the new operator bdef is created
+ if ( mbGrayScale )
+ ImplWriteLine( "/c {setgray} bdef" );
+ else
+ ImplWriteLine( "/c {setrgbcolor} bdef" );
+ ImplWriteLine( "/l {neg lineto} bdef" );
+ ImplWriteLine( "/rl {neg rlineto} bdef" );
+ ImplWriteLine( "/lc {setlinecap} bdef" );
+ ImplWriteLine( "/lj {setlinejoin} bdef" );
+ ImplWriteLine( "/lw {setlinewidth} bdef" );
+ ImplWriteLine( "/ml {setmiterlimit} bdef" );
+ ImplWriteLine( "/ld {setdash} bdef" );
+ ImplWriteLine( "/m {neg moveto} bdef" );
+ ImplWriteLine( "/ct {6 2 roll neg 6 2 roll neg 6 2 roll neg curveto} bdef" );
+ ImplWriteLine( "/r {rotate} bdef" );
+ ImplWriteLine( "/t {neg translate} bdef" );
+ ImplWriteLine( "/s {scale} bdef" );
+ ImplWriteLine( "/sw {show} bdef" );
+ ImplWriteLine( "/gs {gsave} bdef" );
+ ImplWriteLine( "/gr {grestore} bdef" );
+
+ ImplWriteLine( "/f {findfont dup length dict begin" ); // Setfont
+ ImplWriteLine( "{1 index /FID ne {def} {pop pop} ifelse} forall /Encoding ISOLatin1Encoding def" );
+ ImplWriteLine( "currentdict end /NFont exch definefont pop /NFont findfont} bdef" );
+
+ ImplWriteLine( "/p {closepath} bdef" );
+ ImplWriteLine( "/sf {scalefont setfont} bdef" );
+
+ ImplWriteLine( "/ef {eofill}bdef" ); // close path and fill
+ ImplWriteLine( "/pc {closepath stroke}bdef" ); // close path and draw
+ ImplWriteLine( "/ps {stroke}bdef" ); // draw current path
+ ImplWriteLine( "/pum {matrix currentmatrix}bdef" ); // pushes the current matrix
+ ImplWriteLine( "/pom {setmatrix}bdef" ); // pops the matrix
+ 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" );
+ ImplWriteLine( "%%EndResource" );
+ ImplWriteLine( "%%EndProlog" );
+ ImplWriteLine( "%%BeginSetup" );
+ ImplWriteLine( "%%EndSetup" );
+ ImplWriteLine( "%%Page: 1 1" );
+ ImplWriteLine( "%%BeginPageSetup" );
+ ImplWriteLine( "%%EndPageSetup" );
+ ImplWriteLine( "pum" );
+ ImplScale( static_cast<double>(aSizePoint.Width()) / static_cast<double>(pMTF->GetPrefSize().Width()), static_cast<double>(aSizePoint.Height()) / static_cast<double>(pMTF->GetPrefSize().Height()) );
+ ImplWriteDouble( 0 );
+ ImplWriteDouble( -pMTF->GetPrefSize().Height() );
+ ImplWriteLine( "t" );
+ ImplWriteLine( "/tm matrix currentmatrix def" );
+}
+
+void PSWriter::ImplWriteEpilog()
+{
+ ImplTranslate( 0, nBoundingY2 );
+ ImplWriteLine( "pom" );
+ ImplWriteLine( "count op_count sub {pop} repeat countdictstack dict_count sub {end} repeat b4_inc_state restore" );
+
+ ImplWriteLine( "%%PageTrailer" );
+ ImplWriteLine( "%%Trailer" );
+
+ ImplWriteLine( "%%EOF" );
+}
+
+void PSWriter::ImplWriteActions( const GDIMetaFile& rMtf, VirtualDevice& rVDev )
+{
+ tools::PolyPolygon aFillPath;
+
+ for( size_t nCurAction = 0, nCount = rMtf.GetActionSize(); nCurAction < nCount; nCurAction++ )
+ {
+ MetaAction* pMA = rMtf.GetAction( nCurAction );
+
+ switch( pMA->GetType() )
+ {
+ case MetaActionType::NONE :
+ break;
+
+ case MetaActionType::PIXEL :
+ {
+ Color aOldLineColor( aLineColor );
+ aLineColor = static_cast<const MetaPixelAction*>(pMA)->GetColor();
+ ImplWriteLineColor( PS_SPACE );
+ ImplMoveTo( static_cast<const MetaPixelAction*>(pMA)->GetPoint() );
+ ImplLineTo( static_cast<const MetaPixelAction*>(pMA)->GetPoint() );
+ ImplPathDraw();
+ aLineColor = aOldLineColor;
+ }
+ break;
+
+ case MetaActionType::POINT :
+ {
+ ImplWriteLineColor( PS_SPACE );
+ ImplMoveTo( static_cast<const MetaPointAction*>(pMA)->GetPoint() );
+ ImplLineTo( static_cast<const MetaPointAction*>(pMA)->GetPoint() );
+ ImplPathDraw();
+ }
+ break;
+
+ case MetaActionType::LINE :
+ {
+ const LineInfo& rLineInfo = static_cast<const MetaLineAction*>(pMA)->GetLineInfo();
+ ImplWriteLineInfo( rLineInfo );
+ if ( bLineColor )
+ {
+ ImplWriteLineColor( PS_SPACE );
+ ImplMoveTo( static_cast<const MetaLineAction*>(pMA)->GetStartPoint() );
+ ImplLineTo( static_cast<const MetaLineAction*>(pMA )->GetEndPoint() );
+ ImplPathDraw();
+ }
+ }
+ break;
+
+ case MetaActionType::RECT :
+ {
+ ImplRect( static_cast<const MetaRectAction*>(pMA)->GetRect() );
+ }
+ break;
+
+ case MetaActionType::ROUNDRECT :
+ ImplRect( static_cast<const MetaRoundRectAction*>(pMA)->GetRect() );
+ break;
+
+ case MetaActionType::ELLIPSE :
+ {
+ tools::Rectangle aRect = static_cast<const MetaEllipseAction*>(pMA)->GetRect();
+ Point aCenter = aRect.Center();
+ tools::Polygon aPoly( aCenter, aRect.GetWidth() / 2, aRect.GetHeight() / 2 );
+ tools::PolyPolygon aPolyPoly( aPoly );
+ ImplPolyPoly( aPolyPoly );
+ }
+ break;
+
+ case MetaActionType::ARC :
+ {
+ tools::Polygon aPoly( static_cast<const MetaArcAction*>(pMA)->GetRect(), static_cast<const MetaArcAction*>(pMA)->GetStartPoint(),
+ static_cast<const MetaArcAction*>(pMA)->GetEndPoint(), PolyStyle::Arc );
+ tools::PolyPolygon aPolyPoly( aPoly );
+ ImplPolyPoly( aPolyPoly );
+ }
+ break;
+
+ case MetaActionType::PIE :
+ {
+ tools::Polygon aPoly( static_cast<const MetaPieAction*>(pMA)->GetRect(), static_cast<const MetaPieAction*>(pMA)->GetStartPoint(),
+ static_cast<const MetaPieAction*>(pMA)->GetEndPoint(), PolyStyle::Pie );
+ tools::PolyPolygon aPolyPoly( aPoly );
+ ImplPolyPoly( aPolyPoly );
+ }
+ break;
+
+ case MetaActionType::CHORD :
+ {
+ tools::Polygon aPoly( static_cast<const MetaChordAction*>(pMA)->GetRect(), static_cast<const MetaChordAction*>(pMA)->GetStartPoint(),
+ static_cast<const MetaChordAction*>(pMA)->GetEndPoint(), PolyStyle::Chord );
+ tools::PolyPolygon aPolyPoly( aPoly );
+ ImplPolyPoly( aPolyPoly );
+ }
+ break;
+
+ case MetaActionType::POLYLINE :
+ {
+ tools::Polygon aPoly( static_cast<const MetaPolyLineAction*>(pMA)->GetPolygon() );
+ const LineInfo& rLineInfo = static_cast<const MetaPolyLineAction*>(pMA)->GetLineInfo();
+ ImplWriteLineInfo( rLineInfo );
+
+ if(basegfx::B2DLineJoin::NONE == rLineInfo.GetLineJoin()
+ && rLineInfo.GetWidth() > 1)
+ {
+ // emulate B2DLineJoin::NONE by creating single edges
+ const sal_uInt16 nPoints(aPoly.GetSize());
+ const bool bCurve(aPoly.HasFlags());
+
+ for(sal_uInt16 a(0); a + 1 < nPoints; a++)
+ {
+ if(bCurve
+ && PolyFlags::Normal != aPoly.GetFlags(a + 1)
+ && a + 2 < nPoints
+ && PolyFlags::Normal != aPoly.GetFlags(a + 2)
+ && a + 3 < nPoints)
+ {
+ const tools::Polygon aSnippet(4,
+ aPoly.GetConstPointAry() + a,
+ aPoly.GetConstFlagAry() + a);
+ ImplPolyLine(aSnippet);
+ a += 2;
+ }
+ else
+ {
+ const tools::Polygon aSnippet(2,
+ aPoly.GetConstPointAry() + a);
+ ImplPolyLine(aSnippet);
+ }
+ }
+ }
+ else
+ {
+ ImplPolyLine( aPoly );
+ }
+ }
+ break;
+
+ case MetaActionType::POLYGON :
+ {
+ tools::PolyPolygon aPolyPoly( static_cast<const MetaPolygonAction*>(pMA)->GetPolygon() );
+ ImplPolyPoly( aPolyPoly );
+ }
+ break;
+
+ case MetaActionType::POLYPOLYGON :
+ {
+ ImplPolyPoly( static_cast<const MetaPolyPolygonAction*>(pMA)->GetPolyPolygon() );
+ }
+ break;
+
+ case MetaActionType::TEXT:
+ {
+ const MetaTextAction * pA = static_cast<const MetaTextAction*>(pMA);
+
+ OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
+ Point aPoint( pA->GetPoint() );
+
+ ImplText( aUniStr, aPoint, {}, 0, rVDev );
+ }
+ break;
+
+ case MetaActionType::TEXTRECT:
+ {
+ OSL_FAIL( "Unsupported action: TextRect...Action!" );
+ }
+ break;
+
+ case MetaActionType::STRETCHTEXT :
+ {
+ const MetaStretchTextAction* pA = static_cast<const MetaStretchTextAction*>(pMA);
+ OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
+ Point aPoint( pA->GetPoint() );
+
+ ImplText( aUniStr, aPoint, {}, pA->GetWidth(), rVDev );
+ }
+ break;
+
+ case MetaActionType::TEXTARRAY:
+ {
+ const MetaTextArrayAction* pA = static_cast<const MetaTextArrayAction*>(pMA);
+ OUString aUniStr = pA->GetText().copy( pA->GetIndex(), pA->GetLen() );
+ Point aPoint( pA->GetPoint() );
+
+ ImplText( aUniStr, aPoint, pA->GetDXArray(), 0, rVDev );
+ }
+ break;
+
+ case MetaActionType::BMP :
+ {
+ Bitmap aBitmap = static_cast<const MetaBmpAction*>(pMA)->GetBitmap();
+ if ( mbGrayScale )
+ aBitmap.Convert( BmpConversion::N8BitGreys );
+ Point aPoint = static_cast<const MetaBmpAction*>(pMA)->GetPoint();
+ Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
+ ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
+ }
+ break;
+
+ case MetaActionType::BMPSCALE :
+ {
+ Bitmap aBitmap = static_cast<const MetaBmpScaleAction*>(pMA)->GetBitmap();
+ if ( mbGrayScale )
+ aBitmap.Convert( BmpConversion::N8BitGreys );
+ Point aPoint = static_cast<const MetaBmpScaleAction*>(pMA)->GetPoint();
+ Size aSize = static_cast<const MetaBmpScaleAction*>(pMA)->GetSize();
+ ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
+ }
+ break;
+
+ case MetaActionType::BMPSCALEPART :
+ {
+ Bitmap aBitmap( static_cast<const MetaBmpScalePartAction*>(pMA)->GetBitmap() );
+ aBitmap.Crop( tools::Rectangle( static_cast<const MetaBmpScalePartAction*>(pMA)->GetSrcPoint(),
+ static_cast<const MetaBmpScalePartAction*>(pMA)->GetSrcSize() ) );
+ if ( mbGrayScale )
+ aBitmap.Convert( BmpConversion::N8BitGreys );
+ Point aPoint = static_cast<const MetaBmpScalePartAction*>(pMA)->GetDestPoint();
+ Size aSize = static_cast<const MetaBmpScalePartAction*>(pMA)->GetDestSize();
+ ImplBmp( &aBitmap, nullptr, aPoint, aSize.Width(), aSize.Height() );
+ }
+ break;
+
+ case MetaActionType::BMPEX :
+ {
+ BitmapEx aBitmapEx( static_cast<MetaBmpExAction*>(pMA)->GetBitmapEx() );
+ Bitmap aBitmap( aBitmapEx.GetBitmap() );
+ if ( mbGrayScale )
+ aBitmap.Convert( BmpConversion::N8BitGreys );
+ Bitmap aMask( aBitmapEx.GetAlpha() );
+ Point aPoint( static_cast<const MetaBmpExAction*>(pMA)->GetPoint() );
+ Size aSize( rVDev.PixelToLogic( aBitmap.GetSizePixel() ) );
+ ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALE :
+ {
+ BitmapEx aBitmapEx( static_cast<MetaBmpExScaleAction*>(pMA)->GetBitmapEx() );
+ Bitmap aBitmap( aBitmapEx.GetBitmap() );
+ if ( mbGrayScale )
+ aBitmap.Convert( BmpConversion::N8BitGreys );
+ Bitmap aMask( aBitmapEx.GetAlpha() );
+ Point aPoint = static_cast<const MetaBmpExScaleAction*>(pMA)->GetPoint();
+ Size aSize( static_cast<const MetaBmpExScaleAction*>(pMA)->GetSize() );
+ ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
+ }
+ break;
+
+ case MetaActionType::BMPEXSCALEPART :
+ {
+ BitmapEx aBitmapEx( static_cast<const MetaBmpExScalePartAction*>(pMA)->GetBitmapEx() );
+ aBitmapEx.Crop( tools::Rectangle( static_cast<const MetaBmpExScalePartAction*>(pMA)->GetSrcPoint(),
+ static_cast<const MetaBmpExScalePartAction*>(pMA)->GetSrcSize() ) );
+ Bitmap aBitmap( aBitmapEx.GetBitmap() );
+ if ( mbGrayScale )
+ aBitmap.Convert( BmpConversion::N8BitGreys );
+ Bitmap aMask( aBitmapEx.GetAlpha() );
+ Point aPoint = static_cast<const MetaBmpExScalePartAction*>(pMA)->GetDestPoint();
+ Size aSize = static_cast<const MetaBmpExScalePartAction*>(pMA)->GetDestSize();
+ ImplBmp( &aBitmap, &aMask, aPoint, aSize.Width(), aSize.Height() );
+ }
+ break;
+
+ // Unsupported Actions
+ case MetaActionType::MASK:
+ case MetaActionType::MASKSCALE:
+ case MetaActionType::MASKSCALEPART:
+ {
+ OSL_FAIL( "Unsupported action: MetaMask...Action!" );
+ }
+ break;
+
+ case MetaActionType::GRADIENT :
+ {
+ tools::PolyPolygon aPolyPoly( static_cast<const MetaGradientAction*>(pMA)->GetRect() );
+ ImplWriteGradient( aPolyPoly, static_cast<const MetaGradientAction*>(pMA)->GetGradient(), rVDev );
+ }
+ break;
+
+ case MetaActionType::GRADIENTEX :
+ {
+ tools::PolyPolygon aPolyPoly( static_cast<const MetaGradientExAction*>(pMA)->GetPolyPolygon() );
+ ImplWriteGradient( aPolyPoly, static_cast<const MetaGradientExAction*>(pMA)->GetGradient(), rVDev );
+ }
+ break;
+
+ case MetaActionType::HATCH :
+ {
+ ScopedVclPtrInstance< VirtualDevice > l_pVirDev;
+ GDIMetaFile aTmpMtf;
+
+ l_pVirDev->SetMapMode( rVDev.GetMapMode() );
+ l_pVirDev->AddHatchActions( static_cast<const MetaHatchAction*>(pMA)->GetPolyPolygon(),
+ static_cast<const MetaHatchAction*>(pMA)->GetHatch(), aTmpMtf );
+ ImplWriteActions( aTmpMtf, rVDev );
+ }
+ break;
+
+ case MetaActionType::WALLPAPER :
+ {
+ const MetaWallpaperAction* pA = static_cast<const MetaWallpaperAction*>(pMA);
+ tools::Rectangle aRect = pA->GetRect();
+ const Wallpaper& aWallpaper = pA->GetWallpaper();
+
+ if ( aWallpaper.IsBitmap() )
+ {
+ BitmapEx aBitmapEx = aWallpaper.GetBitmap();
+ Bitmap aBitmap( aBitmapEx.GetBitmap() );
+ if ( aBitmapEx.IsAlpha() )
+ {
+ if ( aWallpaper.IsGradient() )
+ {
+
+ // gradient action
+
+ }
+ Bitmap aMask( aBitmapEx.GetAlpha() );
+ ImplBmp( &aBitmap, &aMask, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
+ }
+ else
+ ImplBmp( &aBitmap, nullptr, Point( aRect.Left(), aRect.Top() ), aRect.GetWidth(), aRect.GetHeight() );
+
+ // wallpaper Style
+
+ }
+ else if ( aWallpaper.IsGradient() )
+ {
+
+ // gradient action
+
+ }
+ else
+ {
+ aColor = aWallpaper.GetColor();
+ ImplRectFill( aRect );
+ }
+ }
+ break;
+
+ case MetaActionType::ISECTRECTCLIPREGION:
+ {
+ const MetaISectRectClipRegionAction* pA = static_cast<const MetaISectRectClipRegionAction*>(pMA);
+ vcl::Region aRegion( pA->GetRect() );
+ ImplSetClipRegion( aRegion );
+ }
+ break;
+
+ case MetaActionType::CLIPREGION:
+ {
+ const MetaClipRegionAction* pA = static_cast<const MetaClipRegionAction*>(pMA);
+ const vcl::Region& aRegion( pA->GetRegion() );
+ ImplSetClipRegion( aRegion );
+ }
+ break;
+
+ case MetaActionType::ISECTREGIONCLIPREGION:
+ {
+ const MetaISectRegionClipRegionAction* pA = static_cast<const MetaISectRegionClipRegionAction*>(pMA);
+ const vcl::Region& aRegion( pA->GetRegion() );
+ ImplSetClipRegion( aRegion );
+ }
+ break;
+
+ case MetaActionType::MOVECLIPREGION:
+ {
+ // TODO: Implement!
+ }
+ break;
+
+ case MetaActionType::LINECOLOR :
+ {
+ if ( static_cast<const MetaLineColorAction*>(pMA)->IsSetting() )
+ {
+ bLineColor = true;
+ aLineColor = static_cast<const MetaLineColorAction*>(pMA)->GetColor();
+ }
+ else
+ bLineColor = false;
+ }
+ break;
+
+ case MetaActionType::FILLCOLOR :
+ {
+ if ( static_cast<const MetaFillColorAction*>(pMA)->IsSetting() )
+ {
+ bFillColor = true;
+ aFillColor = static_cast<const MetaFillColorAction*>(pMA)->GetColor();
+ }
+ else
+ bFillColor = false;
+ }
+ break;
+
+ case MetaActionType::TEXTCOLOR :
+ {
+ aTextColor = static_cast<const MetaTextColorAction*>(pMA)->GetColor();
+ }
+ break;
+
+ case MetaActionType::TEXTFILLCOLOR :
+ {
+ if ( static_cast<const MetaTextFillColorAction*>(pMA)->IsSetting() )
+ {
+ bTextFillColor = true;
+ aTextFillColor = static_cast<const MetaTextFillColorAction*>(pMA)->GetColor();
+ }
+ else
+ bTextFillColor = false;
+ }
+ break;
+
+ case MetaActionType::TEXTALIGN :
+ {
+ eTextAlign = static_cast<const MetaTextAlignAction*>(pMA)->GetTextAlign();
+ }
+ break;
+
+ case MetaActionType::MAPMODE :
+ {
+ pMA->Execute( &rVDev );
+ ImplGetMapMode( rVDev.GetMapMode() );
+ }
+ break;
+
+ case MetaActionType::FONT :
+ {
+ maFont = static_cast<const MetaFontAction*>(pMA)->GetFont();
+ rVDev.SetFont( maFont );
+ }
+ break;
+
+ case MetaActionType::PUSH :
+ {
+ rVDev.Push(static_cast<const MetaPushAction*>(pMA)->GetFlags() );
+ StackMember* pGS = new StackMember;
+ pGS->pSucc = pGDIStack;
+ pGDIStack = pGS;
+ pGS->aDashArray = aDashArray;
+ pGS->eJoinType = eJoinType;
+ pGS->eLineCap = eLineCap;
+ pGS->fLineWidth = fLineWidth;
+ pGS->fMiterLimit = fMiterLimit;
+ pGS->eTextAlign = eTextAlign;
+ pGS->aGlobalCol = aColor;
+ pGS->bLineCol = bLineColor;
+ pGS->aLineCol = aLineColor;
+ pGS->bFillCol = bFillColor;
+ pGS->aFillCol = aFillColor;
+ pGS->aTextCol = aTextColor;
+ pGS->bTextFillCol = bTextFillColor;
+ pGS->aTextFillCol = aTextFillColor;
+ pGS->aBackgroundCol = aBackgroundColor;
+ pGS->aFont = maFont;
+ mnLatestPush = mpPS->Tell();
+ ImplWriteLine( "gs" );
+ }
+ break;
+
+ case MetaActionType::POP :
+ {
+ rVDev.Pop();
+ if( pGDIStack )
+ {
+ StackMember* pGS = pGDIStack;
+ pGDIStack = pGS->pSucc;
+ aDashArray = pGS->aDashArray;
+ eJoinType = pGS->eJoinType;
+ eLineCap = pGS->eLineCap;
+ fLineWidth = pGS->fLineWidth;
+ fMiterLimit = pGS->fMiterLimit;
+ eTextAlign = pGS->eTextAlign;
+ aColor = pGS->aGlobalCol;
+ bLineColor = pGS->bLineCol;
+ aLineColor = pGS->aLineCol;
+ bFillColor = pGS->bFillCol;
+ aFillColor = pGS->aFillCol;
+ aTextColor = pGS->aTextCol;
+ bTextFillColor = pGS->bTextFillCol;
+ aTextFillColor = pGS->aTextFillCol;
+ aBackgroundColor = pGS->aBackgroundCol;
+ maFont = pGS->aFont;
+ maLastFont = vcl::Font(); // set maLastFont != maFont -> so that
+ delete pGS;
+ sal_uInt32 nCurrentPos = mpPS->Tell();
+ if ( nCurrentPos - 3 == mnLatestPush )
+ {
+ mpPS->Seek( mnLatestPush );
+ ImplWriteLine( " " );
+ mpPS->Seek( mnLatestPush );
+ }
+ else
+ ImplWriteLine( "gr" );
+ }
+ }
+ break;
+
+ case MetaActionType::EPS :
+ {
+ GfxLink aGfxLink = static_cast<const MetaEPSAction*>(pMA)->GetLink();
+ const GDIMetaFile aSubstitute( static_cast<const MetaEPSAction*>(pMA)->GetSubstitute() );
+
+ bool bLevelConflict = false;
+ sal_uInt8* pSource = const_cast<sal_uInt8*>(aGfxLink.GetData());
+ sal_uInt32 nSize = aGfxLink.GetDataSize();
+ sal_uInt32 nParseThis = POSTSCRIPT_BOUNDINGSEARCH;
+ if ( nSize < 64 ) // assuming eps is larger than 64 bytes
+ pSource = nullptr;
+ if ( nParseThis > nSize )
+ nParseThis = nSize;
+
+ if ( pSource && ( mnLevel == 1 ) )
+ {
+ sal_uInt8* pFound = ImplSearchEntry( pSource, reinterpret_cast<sal_uInt8 const *>("%%LanguageLevel:"), nParseThis - 10, 16 );
+ if ( pFound )
+ {
+ sal_uInt8 k, i = 10;
+ pFound += 16;
+ while ( --i )
+ {
+ k = *pFound++;
+ if ( ( k > '0' ) && ( k <= '9' ) )
+ {
+ if ( k != '1' )
+ {
+ bLevelConflict = true;
+ mbLevelWarning = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ( !bLevelConflict )
+ {
+ double nBoundingBox[4];
+ if ( pSource && ImplGetBoundingBox( nBoundingBox, pSource, nParseThis ) )
+ {
+ Point aPoint = static_cast<const MetaEPSAction*>(pMA)->GetPoint();
+ Size aSize = static_cast<const MetaEPSAction*>(pMA)->GetSize();
+
+ MapMode aMapMode( aSubstitute.GetPrefMapMode() );
+ Size aOutSize( OutputDevice::LogicToLogic( aSize, rVDev.GetMapMode(), aMapMode ) );
+ Point aOrigin( OutputDevice::LogicToLogic( aPoint, rVDev.GetMapMode(), aMapMode ) );
+ aOrigin.AdjustY(aOutSize.Height() );
+ aMapMode.SetOrigin( aOrigin );
+ aMapMode.SetScaleX( Fraction(aOutSize.Width() / ( nBoundingBox[ 2 ] - nBoundingBox[ 0 ] )) );
+ aMapMode.SetScaleY( Fraction(aOutSize.Height() / ( nBoundingBox[ 3 ] - nBoundingBox[ 1 ] )) );
+ ImplWriteLine( "gs" );
+ ImplGetMapMode( aMapMode );
+ ImplWriteLine( "%%BeginDocument:" );
+ mpPS->WriteBytes(pSource, aGfxLink.GetDataSize());
+ ImplWriteLine( "%%EndDocument\ngr" );
+ }
+ }
+ }
+ break;
+
+ case MetaActionType::Transparent:
+ {
+ // TODO: implement!
+ }
+ break;
+
+ case MetaActionType::RASTEROP:
+ {
+ pMA->Execute( &rVDev );
+ }
+ break;
+
+ case MetaActionType::FLOATTRANSPARENT:
+ {
+ const MetaFloatTransparentAction* pA = static_cast<const MetaFloatTransparentAction*>(pMA);
+
+ GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() );
+ Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() );
+ const Size aSrcSize( aTmpMtf.GetPrefSize() );
+ const Point aDestPt( pA->GetPoint() );
+ const Size aDestSize( pA->GetSize() );
+ const double fScaleX = aSrcSize.Width() ? static_cast<double>(aDestSize.Width()) / aSrcSize.Width() : 1.0;
+ const double fScaleY = aSrcSize.Height() ? static_cast<double>(aDestSize.Height()) / aSrcSize.Height() : 1.0;
+ tools::Long nMoveX, nMoveY;
+
+ if( fScaleX != 1.0 || fScaleY != 1.0 )
+ {
+ aTmpMtf.Scale( fScaleX, fScaleY );
+ aSrcPt.setX( FRound( aSrcPt.X() * fScaleX ) );
+ aSrcPt.setY( FRound( aSrcPt.Y() * fScaleY ) );
+ }
+
+ nMoveX = aDestPt.X() - aSrcPt.X();
+ nMoveY = aDestPt.Y() - aSrcPt.Y();
+
+ if( nMoveX || nMoveY )
+ aTmpMtf.Move( nMoveX, nMoveY );
+
+ ImplWriteActions( aTmpMtf, rVDev );
+ }
+ break;
+
+ case MetaActionType::COMMENT:
+ {
+ const MetaCommentAction* pA = static_cast<const MetaCommentAction*>(pMA);
+ if ( pA->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_BEGIN") )
+ {
+ const MetaGradientExAction* pGradAction = nullptr;
+ while( ++nCurAction < nCount )
+ {
+ MetaAction* pAction = rMtf.GetAction( nCurAction );
+ if( pAction->GetType() == MetaActionType::GRADIENTEX )
+ pGradAction = static_cast<const MetaGradientExAction*>(pAction);
+ else if( ( pAction->GetType() == MetaActionType::COMMENT ) &&
+ ( static_cast<const MetaCommentAction*>(pAction)->GetComment().equalsIgnoreAsciiCase("XGRAD_SEQ_END") ) )
+ {
+ break;
+ }
+ }
+
+ if( pGradAction )
+ ImplWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), rVDev );
+ }
+ else if ( pA->GetComment() == "XPATHFILL_SEQ_END" )
+ {
+ if ( aFillPath.Count() )
+ {
+ aFillPath = tools::PolyPolygon();
+ ImplWriteLine( "gr" );
+ }
+ }
+ else
+ {
+ const sal_uInt8* pData = pA->GetData();
+ if ( pData )
+ {
+ SvMemoryStream aMemStm( const_cast<sal_uInt8 *>(pData), pA->GetDataSize(), StreamMode::READ );
+ bool bSkipSequence = false;
+ OString sSeqEnd;
+
+ if( pA->GetComment() == "XPATHSTROKE_SEQ_BEGIN" )
+ {
+ sSeqEnd = "XPATHSTROKE_SEQ_END";
+ SvtGraphicStroke aStroke;
+ ReadSvtGraphicStroke( aMemStm, aStroke );
+
+ tools::Polygon aPath;
+ aStroke.getPath( aPath );
+
+ tools::PolyPolygon aStartArrow;
+ tools::PolyPolygon aEndArrow;
+ double fStrokeWidth( aStroke.getStrokeWidth() );
+ SvtGraphicStroke::JoinType eJT( aStroke.getJoinType() );
+ SvtGraphicStroke::DashArray l_aDashArray;
+
+ aStroke.getStartArrow( aStartArrow );
+ aStroke.getEndArrow( aEndArrow );
+ aStroke.getDashArray( l_aDashArray );
+
+ bSkipSequence = true;
+ if ( l_aDashArray.size() > 11 ) // ps dasharray limit is 11
+ bSkipSequence = false;
+ if ( aStartArrow.Count() || aEndArrow.Count() )
+ bSkipSequence = false;
+ if ( static_cast<sal_uInt32>(eJT) > 2 )
+ bSkipSequence = false;
+ if ( !l_aDashArray.empty() && ( fStrokeWidth != 0.0 ) )
+ bSkipSequence = false;
+ if ( bSkipSequence )
+ {
+ ImplWriteLineInfo( fStrokeWidth, aStroke.getMiterLimit(),
+ aStroke.getCapType(), eJT, std::move(l_aDashArray) );
+ ImplPolyLine( aPath );
+ }
+ }
+ else if (pA->GetComment() == "XPATHFILL_SEQ_BEGIN")
+ {
+ sSeqEnd = "XPATHFILL_SEQ_END";
+ SvtGraphicFill aFill;
+ ReadSvtGraphicFill( aMemStm, aFill );
+ switch( aFill.getFillType() )
+ {
+ case SvtGraphicFill::fillSolid :
+ {
+ bSkipSequence = true;
+ tools::PolyPolygon aPolyPoly;
+ aFill.getPath( aPolyPoly );
+ sal_uInt16 i, nPolyCount = aPolyPoly.Count();
+ if ( nPolyCount )
+ {
+ aFillColor = aFill.getFillColor();
+ ImplWriteFillColor( PS_SPACE );
+ for ( i = 0; i < nPolyCount; )
+ {
+ ImplAddPath( aPolyPoly.GetObject( i ) );
+ if ( ++i < nPolyCount )
+ {
+ mpPS->WriteCharPtr( "p" );
+ mnCursorPos += 2;
+ ImplExecMode( PS_RET );
+ }
+ }
+ mpPS->WriteCharPtr( "p ef" );
+ mnCursorPos += 4;
+ ImplExecMode( PS_RET );
+ }
+ }
+ break;
+
+ case SvtGraphicFill::fillTexture :
+ {
+ aFill.getPath( aFillPath );
+
+ /* normally an object filling is consisting of three MetaActions:
+ MetaBitmapAction using RasterOp xor,
+ MetaPolyPolygonAction using RasterOp rop_0
+ MetaBitmapAction using RasterOp xor
+
+ Because RasterOps cannot been used in Postscript, we have to
+ replace these actions. The MetaComment "XPATHFILL_SEQ_BEGIN" is
+ providing the clippath of the object. The following loop is
+ trying to find the bitmap that is matching the clippath, so that
+ only one bitmap is exported, otherwise if the bitmap is not
+ locatable, all metaactions are played normally.
+ */
+ sal_uInt32 nCommentStartAction = nCurAction;
+ sal_uInt32 nBitmapCount = 0;
+ sal_uInt32 nBitmapAction = 0;
+
+ bool bOk = true;
+ while( bOk && ( ++nCurAction < nCount ) )
+ {
+ MetaAction* pAction = rMtf.GetAction( nCurAction );
+ switch( pAction->GetType() )
+ {
+ case MetaActionType::BMPSCALE :
+ case MetaActionType::BMPSCALEPART :
+ case MetaActionType::BMPEXSCALE :
+ case MetaActionType::BMPEXSCALEPART :
+ {
+ nBitmapCount++;
+ nBitmapAction = nCurAction;
+ }
+ break;
+ case MetaActionType::COMMENT :
+ {
+ if (static_cast<const MetaCommentAction*>(pAction)->GetComment() == "XPATHFILL_SEQ_END")
+ bOk = false;
+ }
+ break;
+ default: break;
+ }
+ }
+ if( nBitmapCount == 2 )
+ {
+ ImplWriteLine( "gs" );
+ ImplIntersect( aFillPath );
+ GDIMetaFile aTempMtf;
+ aTempMtf.AddAction( rMtf.GetAction( nBitmapAction )->Clone() );
+ ImplWriteActions( aTempMtf, rVDev );
+ ImplWriteLine( "gr" );
+ aFillPath = tools::PolyPolygon();
+ }
+ else
+ nCurAction = nCommentStartAction + 1;
+ }
+ break;
+
+ case SvtGraphicFill::fillGradient :
+ aFill.getPath( aFillPath );
+ break;
+
+ case SvtGraphicFill::fillHatch :
+ break;
+ }
+ if ( aFillPath.Count() )
+ {
+ ImplWriteLine( "gs" );
+ ImplIntersect( aFillPath );
+ }
+ }
+ if ( bSkipSequence )
+ {
+ while( ++nCurAction < nCount )
+ {
+ pMA = rMtf.GetAction( nCurAction );
+ if ( pMA->GetType() == MetaActionType::COMMENT )
+ {
+ OString sComment( static_cast<MetaCommentAction*>(pMA)->GetComment() );
+ if ( sComment == sSeqEnd )
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ default: break;
+ }
+ }
+}
+
+inline void PSWriter::ImplWritePoint( const Point& rPoint )
+{
+ ImplWriteDouble( rPoint.X() );
+ ImplWriteDouble( rPoint.Y() );
+}
+
+void PSWriter::ImplMoveTo( const Point& rPoint )
+{
+ ImplWritePoint( rPoint );
+ ImplWriteByte( 'm' );
+ ImplExecMode( PS_SPACE );
+}
+
+void PSWriter::ImplLineTo( const Point& rPoint, NMode nMode )
+{
+ ImplWritePoint( rPoint );
+ ImplWriteByte( 'l' );
+ ImplExecMode( nMode );
+}
+
+void PSWriter::ImplCurveTo( const Point& rP1, const Point& rP2, const Point& rP3, NMode nMode )
+{
+ ImplWritePoint( rP1 );
+ ImplWritePoint( rP2 );
+ ImplWritePoint( rP3 );
+ mpPS->WriteCharPtr( "ct " );
+ ImplExecMode( nMode );
+}
+
+void PSWriter::ImplTranslate( const double& fX, const double& fY )
+{
+ ImplWriteDouble( fX );
+ ImplWriteDouble( fY );
+ ImplWriteByte( 't' );
+ ImplExecMode( PS_RET );
+}
+
+void PSWriter::ImplScale( const double& fX, const double& fY )
+{
+ ImplWriteDouble( fX );
+ ImplWriteDouble( fY );
+ ImplWriteByte( 's' );
+ ImplExecMode( PS_RET );
+}
+
+void PSWriter::ImplRect( const tools::Rectangle & rRect )
+{
+ if ( bFillColor )
+ ImplRectFill( rRect );
+ if ( bLineColor )
+ {
+ double nWidth = rRect.GetWidth();
+ double nHeight = rRect.GetHeight();
+
+ ImplWriteLineColor( PS_SPACE );
+ ImplMoveTo( rRect.TopLeft() );
+ ImplWriteDouble( nWidth );
+ mpPS->WriteCharPtr( "0 rl 0 " );
+ ImplWriteDouble( nHeight );
+ mpPS->WriteCharPtr( "rl " );
+ ImplWriteDouble( nWidth );
+ mpPS->WriteCharPtr( "neg 0 rl " );
+ ImplClosePathDraw();
+ }
+ mpPS->WriteUChar( 10 );
+ mnCursorPos = 0;
+}
+
+void PSWriter::ImplRectFill( const tools::Rectangle & rRect )
+{
+ double nWidth = rRect.GetWidth();
+ double nHeight = rRect.GetHeight();
+
+ ImplWriteFillColor( PS_SPACE );
+ ImplMoveTo( rRect.TopLeft() );
+ ImplWriteDouble( nWidth );
+ mpPS->WriteCharPtr( "0 rl 0 " );
+ ImplWriteDouble( nHeight );
+ mpPS->WriteCharPtr( "rl " );
+ ImplWriteDouble( nWidth );
+ mpPS->WriteCharPtr( "neg 0 rl ef " );
+ mpPS->WriteCharPtr( "p ef" );
+ mnCursorPos += 2;
+ ImplExecMode( PS_RET );
+}
+
+void PSWriter::ImplAddPath( const tools::Polygon & rPolygon )
+{
+ sal_uInt16 nPointCount = rPolygon.GetSize();
+ if ( nPointCount <= 1 )
+ return;
+
+ sal_uInt16 i = 1;
+ ImplMoveTo( rPolygon.GetPoint( 0 ) );
+ while ( i < nPointCount )
+ {
+ if ( ( rPolygon.GetFlags( i ) == PolyFlags::Control )
+ && ( ( i + 2 ) < nPointCount )
+ && ( rPolygon.GetFlags( i + 1 ) == PolyFlags::Control )
+ && ( rPolygon.GetFlags( i + 2 ) != PolyFlags::Control ) )
+ {
+ ImplCurveTo( rPolygon[ i ], rPolygon[ i + 1 ], rPolygon[ i + 2 ], PS_WRAP );
+ i += 3;
+ }
+ else
+ ImplLineTo( rPolygon.GetPoint( i++ ), PS_SPACE | PS_WRAP );
+ }
+}
+
+void PSWriter::ImplIntersect( const tools::PolyPolygon& rPolyPoly )
+{
+ sal_uInt16 i, nPolyCount = rPolyPoly.Count();
+ for ( i = 0; i < nPolyCount; )
+ {
+ ImplAddPath( rPolyPoly.GetObject( i ) );
+ if ( ++i < nPolyCount )
+ {
+ mpPS->WriteCharPtr( "p" );
+ mnCursorPos += 2;
+ ImplExecMode( PS_RET );
+ }
+ }
+ ImplWriteLine( "eoclip newpath" );
+}
+
+void PSWriter::ImplWriteGradient( const tools::PolyPolygon& rPolyPoly, const Gradient& rGradient, VirtualDevice& rVDev )
+{
+ ScopedVclPtrInstance< VirtualDevice > l_pVDev;
+ GDIMetaFile aTmpMtf;
+ l_pVDev->SetMapMode( rVDev.GetMapMode() );
+ Gradient aGradient(rGradient);
+ aGradient.AddGradientActions( rPolyPoly.GetBoundRect(), aTmpMtf );
+ ImplWriteActions( aTmpMtf, rVDev );
+}
+
+void PSWriter::ImplPolyPoly( const tools::PolyPolygon & rPolyPoly, bool bTextOutline )
+{
+ sal_uInt16 i, nPolyCount = rPolyPoly.Count();
+ if ( !nPolyCount )
+ return;
+
+ if ( bFillColor || bTextOutline )
+ {
+ if ( bTextOutline )
+ ImplWriteTextColor( PS_SPACE );
+ else
+ ImplWriteFillColor( PS_SPACE );
+ for ( i = 0; i < nPolyCount; )
+ {
+ ImplAddPath( rPolyPoly.GetObject( i ) );
+ if ( ++i < nPolyCount )
+ {
+ mpPS->WriteCharPtr( "p" );
+ mnCursorPos += 2;
+ ImplExecMode( PS_RET );
+ }
+ }
+ mpPS->WriteCharPtr( "p ef" );
+ mnCursorPos += 4;
+ ImplExecMode( PS_RET );
+ }
+ if ( bLineColor )
+ {
+ ImplWriteLineColor( PS_SPACE );
+ for ( i = 0; i < nPolyCount; i++ )
+ ImplAddPath( rPolyPoly.GetObject( i ) );
+ ImplClosePathDraw();
+ }
+}
+
+void PSWriter::ImplPolyLine( const tools::Polygon & rPoly )
+{
+ if ( !bLineColor )
+ return;
+
+ ImplWriteLineColor( PS_SPACE );
+ sal_uInt16 i, nPointCount = rPoly.GetSize();
+ if ( !nPointCount )
+ return;
+
+ if ( nPointCount > 1 )
+ {
+ ImplMoveTo( rPoly.GetPoint( 0 ) );
+ i = 1;
+ while ( i < nPointCount )
+ {
+ if ( ( rPoly.GetFlags( i ) == PolyFlags::Control )
+ && ( ( i + 2 ) < nPointCount )
+ && ( rPoly.GetFlags( i + 1 ) == PolyFlags::Control )
+ && ( rPoly.GetFlags( i + 2 ) != PolyFlags::Control ) )
+ {
+ ImplCurveTo( rPoly[ i ], rPoly[ i + 1 ], rPoly[ i + 2 ], PS_WRAP );
+ i += 3;
+ }
+ else
+ ImplLineTo( rPoly.GetPoint( i++ ), PS_SPACE | PS_WRAP );
+ }
+ }
+
+ // #104645# explicitly close path if polygon is closed
+ if( rPoly[ 0 ] == rPoly[ nPointCount-1 ] )
+ ImplClosePathDraw();
+ else
+ ImplPathDraw();
+}
+
+void PSWriter::ImplSetClipRegion( vcl::Region const & rClipRegion )
+{
+ if ( rClipRegion.IsEmpty() )
+ return;
+
+ RectangleVector aRectangles;
+ rClipRegion.GetRegionRectangles(aRectangles);
+
+ for (auto const& rectangle : aRectangles)
+ {
+ double nX1(rectangle.Left());
+ double nY1(rectangle.Top());
+ double nX2(rectangle.Right());
+ double nY2(rectangle.Bottom());
+
+ ImplWriteDouble( nX1 );
+ ImplWriteDouble( nY1 );
+ ImplWriteByte( 'm' );
+ ImplWriteDouble( nX2 );
+ ImplWriteDouble( nY1 );
+ ImplWriteByte( 'l' );
+ ImplWriteDouble( nX2 );
+ ImplWriteDouble( nY2 );
+ ImplWriteByte( 'l' );
+ ImplWriteDouble( nX1 );
+ ImplWriteDouble( nY2 );
+ ImplWriteByte( 'l' );
+ ImplWriteDouble( nX1 );
+ ImplWriteDouble( nY1 );
+ ImplWriteByte( 'l', PS_SPACE | PS_WRAP );
+ }
+
+ ImplWriteLine( "eoclip newpath" );
+}
+
+// possible gfx formats:
+//
+// level 1: grayscale 8 bit
+// color 24 bit
+//
+// level 2: grayscale 8 bit
+// color 1(pal), 4(pal), 8(pal), 24 Bit
+//
+
+void PSWriter::ImplBmp( Bitmap const * pBitmap, Bitmap const * pMaskBitmap, const Point & rPoint, double nXWidth, double nYHeightOrg )
+{
+ if ( !pBitmap )
+ return;
+
+ sal_Int32 nHeightOrg = pBitmap->GetSizePixel().Height();
+ sal_Int32 nHeightLeft = nHeightOrg;
+ tools::Long nWidth = pBitmap->GetSizePixel().Width();
+ Point aSourcePos( rPoint );
+
+ while ( nHeightLeft )
+ {
+ Bitmap aTileBitmap( *pBitmap );
+ tools::Long nHeight = nHeightLeft;
+ double nYHeight = nYHeightOrg;
+
+ bool bDoTrans = false;
+
+ tools::Rectangle aRect;
+ vcl::Region aRegion;
+
+ if ( pMaskBitmap )
+ {
+ bDoTrans = true;
+ while (true)
+ {
+ if ( mnLevel == 1 && nHeight > 10 )
+ nHeight = 8;
+ aRect = tools::Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) );
+ aRegion = pMaskBitmap->CreateRegion( COL_BLACK, aRect );
+
+ if( mnLevel == 1 )
+ {
+ RectangleVector aRectangleVector;
+ aRegion.GetRegionRectangles(aRectangleVector);
+
+ if ( aRectangleVector.size() * 5 > 1000 )
+ {
+ nHeight >>= 1;
+ if ( nHeight < 2 )
+ return;
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ if ( nHeight != nHeightOrg )
+ {
+ nYHeight = nYHeightOrg * nHeight / nHeightOrg;
+ aTileBitmap.Crop( tools::Rectangle( Point( 0, nHeightOrg - nHeightLeft ), Size( nWidth, nHeight ) ) );
+ }
+ if ( bDoTrans )
+ {
+ ImplWriteLine( "gs\npum" );
+ ImplTranslate( aSourcePos.X(), aSourcePos.Y() );
+ ImplScale( nXWidth / nWidth, nYHeight / nHeight );
+
+ RectangleVector aRectangles;
+ aRegion.GetRegionRectangles(aRectangles);
+ const tools::Long nMoveVertical(nHeightLeft - nHeightOrg);
+
+ for (auto & rectangle : aRectangles)
+ {
+ rectangle.Move(0, nMoveVertical);
+
+ ImplWriteLong( rectangle.Left() );
+ ImplWriteLong( rectangle.Top() );
+ ImplWriteByte( 'm' );
+ ImplWriteLong( rectangle.Right() + 1 );
+ ImplWriteLong( rectangle.Top() );
+ ImplWriteByte( 'l' );
+ ImplWriteLong( rectangle.Right() + 1 );
+ ImplWriteLong( rectangle.Bottom() + 1 );
+ ImplWriteByte( 'l' );
+ ImplWriteLong( rectangle.Left() );
+ ImplWriteLong( rectangle.Bottom() + 1 );
+ ImplWriteByte( 'l' );
+ ImplWriteByte( 'p', PS_SPACE | PS_WRAP );
+ }
+
+ ImplWriteLine( "eoclip newpath" );
+ ImplWriteLine( "pom" );
+ }
+ BitmapReadAccess* pAcc = aTileBitmap.AcquireReadAccess();
+
+ if (!bDoTrans )
+ ImplWriteLine( "pum" );
+
+ ImplTranslate( aSourcePos.X(), aSourcePos.Y() + nYHeight );
+ ImplScale( nXWidth, nYHeight );
+ if ( mnLevel == 1 ) // level 1 is always grayscale !!!
+ {
+ ImplWriteLong( nWidth );
+ ImplWriteLong( nHeight );
+ mpPS->WriteCharPtr( "8 [" );
+ ImplWriteLong( nWidth );
+ mpPS->WriteCharPtr( "0 0 " );
+ ImplWriteLong( -nHeight );
+ ImplWriteLong( 0 );
+ ImplWriteLong( nHeight );
+ ImplWriteLine( "]" );
+ mpPS->WriteCharPtr( "{currentfile " );
+ ImplWriteLong( nWidth );
+ ImplWriteLine( "string readhexstring pop}" );
+ ImplWriteLine( "image" );
+ for ( tools::Long y = 0; y < nHeight; y++ )
+ {
+ Scanline pScanlineRead = pAcc->GetScanline( y );
+ for ( tools::Long x = 0; x < nWidth; x++ )
+ {
+ ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
+ }
+ }
+ mpPS->WriteUChar( 10 );
+ }
+ else // Level 2
+ {
+ if ( mbGrayScale )
+ {
+ ImplWriteLine( "/DeviceGray setcolorspace" );
+ ImplWriteLine( "<<" );
+ ImplWriteLine( "/ImageType 1" );
+ mpPS->WriteCharPtr( "/Width " );
+ ImplWriteLong( nWidth, PS_RET );
+ mpPS->WriteCharPtr( "/Height " );
+ ImplWriteLong( nHeight, PS_RET );
+ ImplWriteLine( "/BitsPerComponent 8" );
+ ImplWriteLine( "/Decode[0 1]" );
+ mpPS->WriteCharPtr( "/ImageMatrix[" );
+ ImplWriteLong( nWidth );
+ mpPS->WriteCharPtr( "0 0 " );
+ ImplWriteLong( -nHeight );
+ ImplWriteLong( 0 );
+ ImplWriteLong( nHeight, PS_NONE );
+ ImplWriteByte( ']', PS_RET );
+ ImplWriteLine( "/DataSource currentfile" );
+ ImplWriteLine( "/ASCIIHexDecode filter" );
+ if ( mbCompression )
+ ImplWriteLine( "/LZWDecode filter" );
+ ImplWriteLine( ">>" );
+ ImplWriteLine( "image" );
+ if ( mbCompression )
+ {
+ StartCompression();
+ for ( tools::Long y = 0; y < nHeight; y++ )
+ {
+ Scanline pScanlineRead = pAcc->GetScanline( y );
+ for ( tools::Long x = 0; x < nWidth; x++ )
+ {
+ Compress( pAcc->GetIndexFromData( pScanlineRead, x ) );
+ }
+ }
+ EndCompression();
+ }
+ else
+ {
+ for ( tools::Long y = 0; y < nHeight; y++ )
+ {
+ Scanline pScanlineRead = pAcc->GetScanline( y );
+ for ( tools::Long x = 0; x < nWidth; x++ )
+ {
+ ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
+ }
+ }
+ }
+ }
+ else
+ {
+ // have we to write a palette ?
+
+ if ( pAcc->HasPalette() )
+ {
+ ImplWriteLine( "[/Indexed /DeviceRGB " );
+ ImplWriteLong( pAcc->GetPaletteEntryCount() - 1, PS_RET );
+ ImplWriteByte( '<', PS_NONE );
+ for ( sal_uInt16 i = 0; i < pAcc->GetPaletteEntryCount(); i++ )
+ {
+ BitmapColor aBitmapColor = pAcc->GetPaletteColor( i );
+ ImplWriteHexByte( aBitmapColor.GetRed(), PS_NONE );
+ ImplWriteHexByte( aBitmapColor.GetGreen(), PS_NONE );
+ ImplWriteHexByte( aBitmapColor.GetBlue(), PS_SPACE | PS_WRAP );
+ }
+ ImplWriteByte( '>', PS_RET );
+
+ ImplWriteLine( "] setcolorspace" );
+ ImplWriteLine( "<<" );
+ ImplWriteLine( "/ImageType 1" );
+ mpPS->WriteCharPtr( "/Width " );
+ ImplWriteLong( nWidth, PS_RET );
+ mpPS->WriteCharPtr( "/Height " );
+ ImplWriteLong( nHeight, PS_RET );
+ ImplWriteLine( "/BitsPerComponent 8" );
+ ImplWriteLine( "/Decode[0 255]" );
+ mpPS->WriteCharPtr( "/ImageMatrix[" );
+ ImplWriteLong( nWidth );
+ mpPS->WriteCharPtr( "0 0 " );
+ ImplWriteLong( -nHeight );
+ ImplWriteLong( 0);
+ ImplWriteLong( nHeight, PS_NONE );
+ ImplWriteByte( ']', PS_RET );
+ ImplWriteLine( "/DataSource currentfile" );
+ ImplWriteLine( "/ASCIIHexDecode filter" );
+ if ( mbCompression )
+ ImplWriteLine( "/LZWDecode filter" );
+ ImplWriteLine( ">>" );
+ ImplWriteLine( "image" );
+ if ( mbCompression )
+ {
+ StartCompression();
+ for ( tools::Long y = 0; y < nHeight; y++ )
+ {
+ Scanline pScanlineRead = pAcc->GetScanline( y );
+ for ( tools::Long x = 0; x < nWidth; x++ )
+ {
+ Compress( pAcc->GetIndexFromData( pScanlineRead, x ) );
+ }
+ }
+ EndCompression();
+ }
+ else
+ {
+ for ( tools::Long y = 0; y < nHeight; y++ )
+ {
+ Scanline pScanlineRead = pAcc->GetScanline( y );
+ for ( tools::Long x = 0; x < nWidth; x++ )
+ {
+ ImplWriteHexByte( pAcc->GetIndexFromData( pScanlineRead, x ) );
+ }
+ }
+ }
+ }
+ else // 24 bit color
+ {
+ ImplWriteLine( "/DeviceRGB setcolorspace" );
+ ImplWriteLine( "<<" );
+ ImplWriteLine( "/ImageType 1" );
+ mpPS->WriteCharPtr( "/Width " );
+ ImplWriteLong( nWidth, PS_RET );
+ mpPS->WriteCharPtr( "/Height " );
+ ImplWriteLong( nHeight, PS_RET );
+ ImplWriteLine( "/BitsPerComponent 8" );
+ ImplWriteLine( "/Decode[0 1 0 1 0 1]" );
+ mpPS->WriteCharPtr( "/ImageMatrix[" );
+ ImplWriteLong( nWidth );
+ mpPS->WriteCharPtr( "0 0 " );
+ ImplWriteLong( -nHeight );
+ ImplWriteLong( 0 );
+ ImplWriteLong( nHeight, PS_NONE );
+ ImplWriteByte( ']', PS_RET );
+ ImplWriteLine( "/DataSource currentfile" );
+ ImplWriteLine( "/ASCIIHexDecode filter" );
+ if ( mbCompression )
+ ImplWriteLine( "/LZWDecode filter" );
+ ImplWriteLine( ">>" );
+ ImplWriteLine( "image" );
+ if ( mbCompression )
+ {
+ StartCompression();
+ for ( tools::Long y = 0; y < nHeight; y++ )
+ {
+ Scanline pScanlineRead = pAcc->GetScanline( y );
+ for ( tools::Long x = 0; x < nWidth; x++ )
+ {
+ const BitmapColor aBitmapColor( pAcc->GetPixelFromData( pScanlineRead, x ) );
+ Compress( aBitmapColor.GetRed() );
+ Compress( aBitmapColor.GetGreen() );
+ Compress( aBitmapColor.GetBlue() );
+ }
+ }
+ EndCompression();
+ }
+ else
+ {
+ for ( tools::Long y = 0; y < nHeight; y++ )
+ {
+ Scanline pScanline = pAcc->GetScanline( y );
+ for ( tools::Long x = 0; x < nWidth; x++ )
+ {
+ const BitmapColor aBitmapColor( pAcc->GetPixelFromData( pScanline, x ) );
+ ImplWriteHexByte( aBitmapColor.GetRed() );
+ ImplWriteHexByte( aBitmapColor.GetGreen() );
+ ImplWriteHexByte( aBitmapColor.GetBlue() );
+ }
+ }
+ }
+ }
+ }
+ ImplWriteLine( ">" ); // in Level 2 the dictionary needs to be closed (eod)
+ }
+ if ( bDoTrans )
+ ImplWriteLine( "gr" );
+ else
+ ImplWriteLine( "pom" );
+
+ Bitmap::ReleaseAccess( pAcc );
+ nHeightLeft -= nHeight;
+ if ( nHeightLeft )
+ {
+ nHeightLeft++;
+ aSourcePos.setY( static_cast<tools::Long>( rPoint.Y() + ( nYHeightOrg * ( nHeightOrg - nHeightLeft ) ) / nHeightOrg ) );
+ }
+ }
+}
+
+void PSWriter::ImplWriteCharacter( char nChar )
+{
+ switch( nChar )
+ {
+ case '(' :
+ case ')' :
+ case '\\' :
+ ImplWriteByte( sal_uInt8('\\'), PS_NONE );
+ }
+ ImplWriteByte( static_cast<sal_uInt8>(nChar), PS_NONE );
+}
+
+void PSWriter::ImplWriteString( const OString& rString, VirtualDevice const & rVDev, o3tl::span<const sal_Int32> pDXArry, bool bStretch )
+{
+ sal_Int32 nLen = rString.getLength();
+ if ( !nLen )
+ return;
+
+ if ( !pDXArry.empty() )
+ {
+ double nx = 0;
+
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ {
+ if ( i > 0 )
+ nx = pDXArry[ i - 1 ];
+ ImplWriteDouble( bStretch ? nx : rVDev.GetTextWidth( OUString(rString[i]) ) );
+ ImplWriteDouble( nx );
+ ImplWriteLine( "(", PS_NONE );
+ ImplWriteCharacter( rString[i] );
+ ImplWriteLine( ") bs" );
+ }
+ }
+ else
+ {
+ ImplWriteByte( '(', PS_NONE );
+ for (sal_Int32 i = 0; i < nLen; ++i)
+ ImplWriteCharacter( rString[i] );
+ ImplWriteLine( ") sw" );
+ }
+}
+
+void PSWriter::ImplText( const OUString& rUniString, const Point& rPos, o3tl::span<const sal_Int32> pDXArry, sal_Int32 nWidth, VirtualDevice const & rVDev )
+{
+ if ( rUniString.isEmpty() )
+ return;
+ if ( mnTextMode == 0 ) // using glyph outlines
+ {
+ vcl::Font aNotRotatedFont( maFont );
+ aNotRotatedFont.SetOrientation( 0_deg10 );
+
+ ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::DEFAULT);
+ pVirDev->SetMapMode( rVDev.GetMapMode() );
+ pVirDev->SetFont( aNotRotatedFont );
+ pVirDev->SetTextAlign( eTextAlign );
+
+ Degree10 nRotation = maFont.GetOrientation();
+ tools::Polygon aPolyDummy( 1 );
+
+ Point aPos( rPos );
+ if ( nRotation )
+ {
+ aPolyDummy.SetPoint( aPos, 0 );
+ aPolyDummy.Rotate( rPos, nRotation );
+ aPos = aPolyDummy.GetPoint( 0 );
+ }
+ bool bOldLineColor = bLineColor;
+ bLineColor = false;
+ std::vector<tools::PolyPolygon> aPolyPolyVec;
+ if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniString, 0, 0, -1, nWidth, pDXArry ) )
+ {
+ // always adjust text position to match baseline alignment
+ ImplWriteLine( "pum" );
+ ImplWriteDouble( aPos.X() );
+ ImplWriteDouble( aPos.Y() );
+ ImplWriteLine( "t" );
+ if ( nRotation )
+ {
+ ImplWriteF( nRotation.get(), 1 );
+ mpPS->WriteCharPtr( "r " );
+ }
+ for (auto const& elem : aPolyPolyVec)
+ ImplPolyPoly( elem, true );
+ ImplWriteLine( "pom" );
+ }
+ bLineColor = bOldLineColor;
+ }
+ else if ( ( mnTextMode == 1 ) || ( mnTextMode == 2 ) ) // normal text output
+ {
+ if ( mnTextMode == 2 ) // forcing output one complete text packet, by
+ pDXArry = {}; // ignoring the kerning array
+ ImplSetAttrForText( rPos );
+ OString aStr(OUStringToOString(rUniString,
+ maFont.GetCharSet()));
+ ImplWriteString( aStr, rVDev, pDXArry, nWidth != 0 );
+ if ( maFont.GetOrientation() )
+ ImplWriteLine( "gr" );
+ }
+}
+
+void PSWriter::ImplSetAttrForText( const Point& rPoint )
+{
+ Point aPoint( rPoint );
+
+ Degree10 nRotation = maFont.GetOrientation();
+ ImplWriteTextColor(PS_RET);
+
+ Size aSize = maFont.GetFontSize();
+
+ if ( maLastFont != maFont )
+ {
+ if ( maFont.GetPitch() == PITCH_FIXED ) // a little bit font selection
+ ImplDefineFont( "Courier", "Oblique" );
+ else if ( maFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL )
+ ImplWriteLine( "/Symbol findfont" );
+ else if ( maFont.GetFamilyType() == FAMILY_SWISS )
+ ImplDefineFont( "Helvetica", "Oblique" );
+ else
+ ImplDefineFont( "Times", "Italic" );
+
+ maLastFont = maFont;
+ aSize = maFont.GetFontSize();
+ ImplWriteDouble( aSize.Height() );
+ mpPS->WriteCharPtr( "sf " );
+ }
+ if ( eTextAlign != ALIGN_BASELINE )
+ { // PostScript does not know about FontAlignment
+ if ( eTextAlign == ALIGN_TOP ) // -> so I assume that
+ aPoint.AdjustY( aSize.Height() * 4 / 5 ); // the area under the baseline
+ else if ( eTextAlign == ALIGN_BOTTOM ) // is about 20% of the font size
+ aPoint.AdjustY( -( aSize.Height() / 5 ) );
+ }
+ ImplMoveTo( aPoint );
+ if ( nRotation )
+ {
+ mpPS->WriteCharPtr( "gs " );
+ ImplWriteF( nRotation.get(), 1 );
+ mpPS->WriteCharPtr( "r " );
+ }
+}
+
+void PSWriter::ImplDefineFont( const char* pOriginalName, const char* pItalic )
+{
+ mpPS->WriteUChar( '/' ); //convert the font pOriginalName using ISOLatin1Encoding
+ mpPS->WriteCharPtr( pOriginalName );
+ switch ( maFont.GetWeight() )
+ {
+ case WEIGHT_SEMIBOLD :
+ case WEIGHT_BOLD :
+ case WEIGHT_ULTRABOLD :
+ case WEIGHT_BLACK :
+ mpPS->WriteCharPtr( "-Bold" );
+ if ( maFont.GetItalic() != ITALIC_NONE )
+ mpPS->WriteCharPtr( pItalic );
+ break;
+ default:
+ if ( maFont.GetItalic() != ITALIC_NONE )
+ mpPS->WriteCharPtr( pItalic );
+ break;
+ }
+ ImplWriteLine( " f" );
+}
+
+void PSWriter::ImplClosePathDraw()
+{
+ mpPS->WriteCharPtr( "pc" );
+ mnCursorPos += 2;
+ ImplExecMode( PS_RET );
+}
+
+void PSWriter::ImplPathDraw()
+{
+ mpPS->WriteCharPtr( "ps" );
+ mnCursorPos += 2;
+ ImplExecMode( PS_RET );
+}
+
+
+inline void PSWriter::ImplWriteLineColor( NMode nMode )
+{
+ if ( aColor != aLineColor )
+ {
+ aColor = aLineColor;
+ ImplWriteColor( nMode );
+ }
+}
+
+inline void PSWriter::ImplWriteFillColor( NMode nMode )
+{
+ if ( aColor != aFillColor )
+ {
+ aColor = aFillColor;
+ ImplWriteColor( nMode );
+ }
+}
+
+inline void PSWriter::ImplWriteTextColor( NMode nMode )
+{
+ if ( aColor != aTextColor )
+ {
+ aColor = aTextColor;
+ ImplWriteColor( nMode );
+ }
+}
+
+void PSWriter::ImplWriteColor( NMode nMode )
+{
+ if ( mbGrayScale )
+ {
+ // writes the Color (grayscale) as a Number from 0.000 up to 1.000
+
+ ImplWriteF( 1000 * ( aColor.GetRed() * 77 + aColor.GetGreen() * 151 +
+ aColor.GetBlue() * 28 + 1 ) / 65536, 3, nMode );
+ }
+ else
+ {
+ ImplWriteB1 ( aColor.GetRed() );
+ ImplWriteB1 ( aColor.GetGreen() );
+ ImplWriteB1 ( aColor.GetBlue() );
+ }
+ mpPS->WriteCharPtr( "c" ); // ( c is defined as setrgbcolor or setgray )
+ ImplExecMode( nMode );
+}
+
+void PSWriter::ImplGetMapMode( const MapMode& rMapMode )
+{
+ ImplWriteLine( "tm setmatrix" );
+ double fMul = ImplGetScaling(rMapMode);
+ double fScaleX = static_cast<double>(rMapMode.GetScaleX()) * fMul;
+ double fScaleY = static_cast<double>(rMapMode.GetScaleY()) * fMul;
+ ImplTranslate( rMapMode.GetOrigin().X() * fScaleX, rMapMode.GetOrigin().Y() * fScaleY );
+ ImplScale( fScaleX, fScaleY );
+}
+
+inline void PSWriter::ImplExecMode( NMode nMode )
+{
+ if ( nMode & PS_WRAP )
+ {
+ if ( mnCursorPos >= PS_LINESIZE )
+ {
+ mnCursorPos = 0;
+ mpPS->WriteUChar( 0xa );
+ return;
+ }
+ }
+ if ( nMode & PS_SPACE )
+ {
+ mpPS->WriteUChar( 32 );
+ mnCursorPos++;
+ }
+ if ( nMode & PS_RET )
+ {
+ mpPS->WriteUChar( 0xa );
+ mnCursorPos = 0;
+ }
+}
+
+inline void PSWriter::ImplWriteLine( const char* pString, NMode nMode )
+{
+ sal_uInt32 i = 0;
+ while ( pString[ i ] )
+ {
+ mpPS->WriteUChar( pString[ i++ ] );
+ }
+ mnCursorPos += i;
+ ImplExecMode( nMode );
+}
+
+double PSWriter::ImplGetScaling( const MapMode& rMapMode )
+{
+ double nMul;
+ switch (rMapMode.GetMapUnit())
+ {
+ case MapUnit::MapPixel :
+ case MapUnit::MapSysFont :
+ case MapUnit::MapAppFont :
+
+ case MapUnit::Map100thMM :
+ nMul = 1;
+ break;
+ case MapUnit::Map10thMM :
+ nMul = 10;
+ break;
+ case MapUnit::MapMM :
+ nMul = 100;
+ break;
+ case MapUnit::MapCM :
+ nMul = 1000;
+ break;
+ case MapUnit::Map1000thInch :
+ nMul = 2.54;
+ break;
+ case MapUnit::Map100thInch :
+ nMul = 25.4;
+ break;
+ case MapUnit::Map10thInch :
+ nMul = 254;
+ break;
+ case MapUnit::MapInch :
+ nMul = 2540;
+ break;
+ case MapUnit::MapTwip :
+ nMul = 1.76388889;
+ break;
+ case MapUnit::MapPoint :
+ nMul = 35.27777778;
+ break;
+ default:
+ nMul = 1.0;
+ break;
+ }
+ return nMul;
+}
+
+
+void PSWriter::ImplWriteLineInfo( double fLWidth, double fMLimit,
+ SvtGraphicStroke::CapType eLCap,
+ SvtGraphicStroke::JoinType eJoin,
+ SvtGraphicStroke::DashArray && rLDash )
+{
+ if ( fLineWidth != fLWidth )
+ {
+ fLineWidth = fLWidth;
+ ImplWriteDouble( fLineWidth );
+ ImplWriteLine( "lw", PS_SPACE );
+ }
+ if ( eLineCap != eLCap )
+ {
+ eLineCap = eLCap;
+ ImplWriteLong( static_cast<sal_Int32>(eLineCap) );
+ ImplWriteLine( "lc", PS_SPACE );
+ }
+ if ( eJoinType != eJoin )
+ {
+ eJoinType = eJoin;
+ ImplWriteLong( static_cast<sal_Int32>(eJoinType) );
+ ImplWriteLine( "lj", PS_SPACE );
+ }
+ if ( eJoinType == SvtGraphicStroke::joinMiter )
+ {
+ if ( fMiterLimit != fMLimit )
+ {
+ fMiterLimit = fMLimit;
+ ImplWriteDouble( fMiterLimit );
+ ImplWriteLine( "ml", PS_SPACE );
+ }
+ }
+ if ( aDashArray != rLDash )
+ {
+ aDashArray = std::move(rLDash);
+ sal_uInt32 j, i = aDashArray.size();
+ ImplWriteLine( "[", PS_SPACE );
+ for ( j = 0; j < i; j++ )
+ ImplWriteDouble( aDashArray[ j ] );
+ ImplWriteLine( "] 0 ld" );
+ }
+}
+
+void PSWriter::ImplWriteLineInfo( const LineInfo& rLineInfo )
+{
+ std::vector< double > l_aDashArray;
+ if ( rLineInfo.GetStyle() == LineStyle::Dash )
+ l_aDashArray = rLineInfo.GetDotDashArray();
+ const double fLWidth(( ( rLineInfo.GetWidth() + 1 ) + ( rLineInfo.GetWidth() + 1 ) ) * 0.5);
+ SvtGraphicStroke::JoinType aJoinType(SvtGraphicStroke::joinMiter);
+ SvtGraphicStroke::CapType aCapType(SvtGraphicStroke::capButt);
+
+ switch(rLineInfo.GetLineJoin())
+ {
+ case basegfx::B2DLineJoin::NONE:
+ // do NOT use SvtGraphicStroke::joinNone here
+ // since it will be written as numerical value directly
+ // and is NOT a valid EPS value
+ break;
+ case basegfx::B2DLineJoin::Miter:
+ aJoinType = SvtGraphicStroke::joinMiter;
+ break;
+ case basegfx::B2DLineJoin::Bevel:
+ aJoinType = SvtGraphicStroke::joinBevel;
+ break;
+ case basegfx::B2DLineJoin::Round:
+ aJoinType = SvtGraphicStroke::joinRound;
+ break;
+ }
+ switch(rLineInfo.GetLineCap())
+ {
+ default: /* css::drawing::LineCap_BUTT */
+ {
+ aCapType = SvtGraphicStroke::capButt;
+ break;
+ }
+ case css::drawing::LineCap_ROUND:
+ {
+ aCapType = SvtGraphicStroke::capRound;
+ break;
+ }
+ case css::drawing::LineCap_SQUARE:
+ {
+ aCapType = SvtGraphicStroke::capSquare;
+ break;
+ }
+ }
+
+ ImplWriteLineInfo( fLWidth, fMiterLimit, aCapType, aJoinType, std::move(l_aDashArray) );
+}
+
+void PSWriter::ImplWriteLong(sal_Int32 nNumber, NMode nMode)
+{
+ const OString aNumber(OString::number(nNumber));
+ mnCursorPos += aNumber.getLength();
+ mpPS->WriteOString( aNumber );
+ ImplExecMode(nMode);
+}
+
+void PSWriter::ImplWriteDouble( double fNumber )
+{
+ sal_Int32 nPTemp = static_cast<sal_Int32>(fNumber);
+ sal_Int32 nATemp = std::abs( static_cast<sal_Int32>( ( fNumber - nPTemp ) * 100000 ) );
+
+ if ( !nPTemp && nATemp && ( fNumber < 0.0 ) )
+ mpPS->WriteChar( '-' );
+
+ const OString aNumber1(OString::number(nPTemp));
+ mpPS->WriteOString( aNumber1 );
+ mnCursorPos += aNumber1.getLength();
+
+ if ( nATemp )
+ {
+ int zCount = 0;
+ mpPS->WriteUChar( '.' );
+ mnCursorPos++;
+ const OString aNumber2(OString::number(nATemp));
+
+ sal_Int16 n, nLen = aNumber2.getLength();
+ if ( nLen < 8 )
+ {
+ mnCursorPos += 6 - nLen;
+ for ( n = 0; n < ( 5 - nLen ); n++ )
+ {
+ mpPS->WriteUChar( '0' );
+ }
+ }
+ mnCursorPos += nLen;
+ for ( n = 0; n < nLen; n++ )
+ {
+ mpPS->WriteChar( aNumber2[n] );
+ zCount--;
+ if ( aNumber2[n] != '0' )
+ zCount = 0;
+ }
+ if ( zCount )
+ mpPS->SeekRel( zCount );
+ }
+ ImplExecMode( PS_SPACE );
+}
+
+/// Writes the number to stream: nNumber / ( 10^nCount )
+void PSWriter::ImplWriteF( sal_Int32 nNumber, sal_uInt8 nCount, NMode nMode )
+{
+ if ( nNumber < 0 )
+ {
+ mpPS->WriteUChar( '-' );
+ nNumber = -nNumber;
+ mnCursorPos++;
+ }
+ const OString aScaleFactor(OString::number(nNumber));
+ sal_uInt32 nLen = aScaleFactor.getLength();
+ sal_Int32 const nStSize = (nCount + 1) - nLen;
+ static_assert(sizeof(nStSize) == sizeof((nCount + 1) - nLen)); // tdf#134667
+ if ( nStSize >= 1 )
+ {
+ mpPS->WriteUChar( '0' );
+ mnCursorPos++;
+ }
+ if ( nStSize >= 2 )
+ {
+ mpPS->WriteUChar( '.' );
+ for (sal_Int32 i = 1; i < nStSize; ++i)
+ {
+ mpPS->WriteUChar( '0' );
+ mnCursorPos++;
+ }
+ }
+ mnCursorPos += nLen;
+ for( sal_uInt32 n = 0; n < nLen; n++ )
+ {
+ if ( n == nLen - nCount )
+ {
+ mpPS->WriteUChar( '.' );
+ mnCursorPos++;
+ }
+ mpPS->WriteChar( aScaleFactor[n] );
+ }
+ ImplExecMode( nMode );
+}
+
+void PSWriter::ImplWriteByte( sal_uInt8 nNumb, NMode nMode )
+{
+ mpPS->WriteUChar( nNumb );
+ mnCursorPos++;
+ ImplExecMode( nMode );
+}
+
+void PSWriter::ImplWriteHexByte( sal_uInt8 nNumb, NMode nMode )
+{
+ if ( ( nNumb >> 4 ) > 9 )
+ mpPS->WriteUChar( ( nNumb >> 4 ) + 'A' - 10 );
+ else
+ mpPS->WriteUChar( ( nNumb >> 4 ) + '0' );
+
+ if ( ( nNumb & 0xf ) > 9 )
+ mpPS->WriteUChar( ( nNumb & 0xf ) + 'A' - 10 );
+ else
+ mpPS->WriteUChar( ( nNumb & 0xf ) + '0' );
+ mnCursorPos += 2;
+ ImplExecMode( nMode );
+}
+
+// writes the sal_uInt8 nNumb as a Number from 0.000 up to 1.000
+
+void PSWriter::ImplWriteB1( sal_uInt8 nNumb )
+{
+ ImplWriteF( 1000 * ( nNumb + 1 ) / 256 );
+}
+
+inline void PSWriter::WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen )
+{
+ dwShift |= ( nCode << ( nOffset - nCodeLen ) );
+ nOffset -= nCodeLen;
+ while ( nOffset < 24 )
+ {
+ ImplWriteHexByte( static_cast<sal_uInt8>( dwShift >> 24 ) );
+ dwShift <<= 8;
+ nOffset += 8;
+ }
+ if ( nCode == 257 && nOffset != 32 )
+ ImplWriteHexByte( static_cast<sal_uInt8>( dwShift >> 24 ) );
+}
+
+void PSWriter::StartCompression()
+{
+ sal_uInt16 i;
+ nDataSize = 8;
+
+ nClearCode = 1 << nDataSize;
+ nEOICode = nClearCode + 1;
+ nTableSize = nEOICode + 1;
+ nCodeSize = nDataSize + 1;
+
+ nOffset = 32; // number of free unused in dwShift
+ dwShift = 0;
+
+ pTable.reset(new PSLZWCTreeNode[ 4096 ]);
+
+ for ( i = 0; i < 4096; i++ )
+ {
+ pTable[ i ].pBrother = pTable[ i ].pFirstChild = nullptr;
+ pTable[ i ].nCode = i;
+ pTable[ i ].nValue = static_cast<sal_uInt8>( i );
+ }
+ pPrefix = nullptr;
+ WriteBits( nClearCode, nCodeSize );
+}
+
+void PSWriter::Compress( sal_uInt8 nCompThis )
+{
+ PSLZWCTreeNode* p;
+ sal_uInt16 i;
+ sal_uInt8 nV;
+
+ if( !pPrefix )
+ {
+ pPrefix = pTable.get() + nCompThis;
+ }
+ else
+ {
+ nV = nCompThis;
+ for( p = pPrefix->pFirstChild; p != nullptr; p = p->pBrother )
+ {
+ if ( p->nValue == nV )
+ break;
+ }
+
+ if( p )
+ pPrefix = p;
+ else
+ {
+ WriteBits( pPrefix->nCode, nCodeSize );
+
+ if ( nTableSize == 409 )
+ {
+ WriteBits( nClearCode, nCodeSize );
+
+ for ( i = 0; i < nClearCode; i++ )
+ pTable[ i ].pFirstChild = nullptr;
+
+ nCodeSize = nDataSize + 1;
+ nTableSize = nEOICode + 1;
+ }
+ else
+ {
+ if( nTableSize == static_cast<sal_uInt16>( ( 1 << nCodeSize ) - 1 ) )
+ nCodeSize++;
+
+ p = pTable.get() + ( nTableSize++ );
+ p->pBrother = pPrefix->pFirstChild;
+ pPrefix->pFirstChild = p;
+ p->nValue = nV;
+ p->pFirstChild = nullptr;
+ }
+
+ pPrefix = pTable.get() + nV;
+ }
+ }
+}
+
+void PSWriter::EndCompression()
+{
+ if( pPrefix )
+ WriteBits( pPrefix->nCode, nCodeSize );
+
+ WriteBits( nEOICode, nCodeSize );
+ pTable.reset();
+}
+
+sal_uInt8* PSWriter::ImplSearchEntry( sal_uInt8* pSource, sal_uInt8 const * pDest, sal_uInt32 nComp, sal_uInt32 nSize )
+{
+ while ( nComp-- >= nSize )
+ {
+ sal_uInt64 i;
+ for ( i = 0; i < nSize; i++ )
+ {
+ if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) )
+ break;
+ }
+ if ( i == nSize )
+ return pSource;
+ pSource++;
+ }
+ return nullptr;
+}
+
+bool PSWriter::ImplGetBoundingBox( double* nNumb, sal_uInt8* pSource, sal_uInt32 nSize )
+{
+ bool bRetValue = false;
+ sal_uInt32 nBytesRead;
+
+ if ( nSize < 256 ) // we assume that the file is greater than 256 bytes
+ return false;
+
+ if ( nSize < POSTSCRIPT_BOUNDINGSEARCH )
+ nBytesRead = nSize;
+ else
+ nBytesRead = POSTSCRIPT_BOUNDINGSEARCH;
+
+ sal_uInt8* pDest = ImplSearchEntry( pSource, reinterpret_cast<sal_uInt8 const *>("%%BoundingBox:"), nBytesRead, 14 );
+ if ( pDest )
+ {
+ int nSecurityCount = 100; // only 100 bytes following the bounding box will be checked
+ nNumb[0] = nNumb[1] = nNumb[2] = nNumb[3] = 0;
+ pDest += 14;
+ for ( int i = 0; ( i < 4 ) && nSecurityCount; i++ )
+ {
+ int nDivision = 1;
+ bool bDivision = false;
+ bool bNegative = false;
+ bool bValid = true;
+
+ while ( ( --nSecurityCount ) && ( ( *pDest == ' ' ) || ( *pDest == 0x9 ) ) )
+ pDest++;
+ sal_uInt8 nByte = *pDest;
+ while ( nSecurityCount && ( nByte != ' ' ) && ( nByte != 0x9 ) && ( nByte != 0xd ) && ( nByte != 0xa ) )
+ {
+ switch ( nByte )
+ {
+ case '.' :
+ if ( bDivision )
+ bValid = false;
+ else
+ bDivision = true;
+ break;
+ case '-' :
+ bNegative = true;
+ break;
+ default :
+ if ( ( nByte < '0' ) || ( nByte > '9' ) )
+ nSecurityCount = 1; // error parsing the bounding box values
+ else if ( bValid )
+ {
+ if ( bDivision )
+ nDivision*=10;
+ nNumb[i] *= 10;
+ nNumb[i] += nByte - '0';
+ }
+ break;
+ }
+ nSecurityCount--;
+ nByte = *(++pDest);
+ }
+ if ( bNegative )
+ nNumb[i] = -nNumb[i];
+ if ( bDivision && ( nDivision != 1 ) )
+ nNumb[i] /= nDivision;
+ }
+ if ( nSecurityCount)
+ bRetValue = true;
+ }
+ return bRetValue;
+}
+
+//================== GraphicExport - the exported function ===================
+
+bool ExportEpsGraphic(SvStream & rStream, const Graphic & rGraphic, FilterConfigItem* pFilterConfigItem)
+{
+ PSWriter aPSWriter;
+ return aPSWriter.WritePS(rGraphic, rStream, pFilterConfigItem);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */