summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorPhilipp Lohmann <pl@openoffice.org>2002-07-08 13:18:58 +0000
committerPhilipp Lohmann <pl@openoffice.org>2002-07-08 13:18:58 +0000
commitdf0f52d3aadea5c4d5f600d1533901af1087b464 (patch)
tree5061887e595a26a9c7a90877b098a41a9eee609f /vcl
parent7244fd72ca8251018fa9775ad366c6220ad4cdff (diff)
#100608# preparations for PDF export
Diffstat (limited to 'vcl')
-rw-r--r--vcl/prj/d.lst2
-rw-r--r--vcl/source/gdi/makefile.mk8
-rw-r--r--vcl/source/gdi/pdfwriter.cxx393
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx2317
-rw-r--r--vcl/source/gdi/pdfwriter_impl.hxx435
5 files changed, 3151 insertions, 4 deletions
diff --git a/vcl/prj/d.lst b/vcl/prj/d.lst
index 153a237d770f..23b6198181d5 100644
--- a/vcl/prj/d.lst
+++ b/vcl/prj/d.lst
@@ -185,7 +185,7 @@ hedabu: ..\inc\unohelp.hxx %_DEST%\inc%_EXT%\vcl\unohelp.hxx
hedabu: ..\inc\unohelp2.hxx %_DEST%\inc%_EXT%\vcl\unohelp2.hxx
hedabu: ..\inc\i18nhelp.hxx %_DEST%\inc%_EXT%\vcl\i18nhelp.hxx
hedabu: ..\inc\dndhelp.hxx %_DEST%\inc%_EXT%\vcl\dndhelp.hxx
-hedabu: ..\unx\inc\salconfig.hxx %_DEST%\inc%_EXT%\vcl\unx\salconfig.hxx
+hedabu: ..\inc\pdfwriter.hxx %_DEST%\inc%_EXT%\vcl\pdfwriter.hxx
..\%__SRC%\lib\lib*static*.dylib %_DEST%\lib%_EXT%\lib*static*.dylib
..\%__SRC%\misc\*staticdatamembers.cxx %_DEST%\inc%_EXT%\*staticdatamembers.cxx
diff --git a/vcl/source/gdi/makefile.mk b/vcl/source/gdi/makefile.mk
index 6d3886d3d1c6..832377a949b8 100644
--- a/vcl/source/gdi/makefile.mk
+++ b/vcl/source/gdi/makefile.mk
@@ -2,9 +2,9 @@
#
# $RCSfile: makefile.mk,v $
#
-# $Revision: 1.6 $
+# $Revision: 1.7 $
#
-# last change: $Author: hdu $ $Date: 2002-02-18 17:54:10 $
+# last change: $Author: pl $ $Date: 2002-07-08 14:18:58 $
#
# The Contents of this file are made available subject to the terms of
# either of the following licenses
@@ -132,7 +132,9 @@ SLOFILES= $(SLO)$/salmisc.obj \
$(SLO)$/virdev.obj \
$(SLO)$/wall.obj \
$(SLO)$/opengl.obj \
- $(SLO)$/fontcfg.obj
+ $(SLO)$/fontcfg.obj \
+ $(SLO)$/pdfwriter.obj \
+ $(SLO)$/pdfwriter_impl.obj
.IF "$(ENABLE_CTL)"!=""
diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx
new file mode 100644
index 000000000000..ea5d0c050b84
--- /dev/null
+++ b/vcl/source/gdi/pdfwriter.cxx
@@ -0,0 +1,393 @@
+/*************************************************************************
+ *
+ * $RCSfile: pdfwriter.cxx,v $
+ *
+ * $Revision: 1.1 $
+ *
+ * last change: $Author: pl $ $Date: 2002-07-08 14:18:53 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (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.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <pdfwriter_impl.hxx>
+#include <bitmapex.hxx>
+#include <image.hxx>
+
+using namespace vcl;
+
+PDFWriter::PDFWriter( const rtl::OUString& rFilename, PDFVersion eVersion )
+ :
+ pImplementation( new PDFWriterImpl( rFilename, eVersion ) )
+{
+}
+
+PDFWriter::~PDFWriter()
+{
+ delete (PDFWriterImpl*)pImplementation;
+}
+
+OutputDevice* PDFWriter::GetReferenceDevice()
+{
+ return ((PDFWriterImpl*)pImplementation)->getReferenceDevice();
+}
+
+sal_Int32 PDFWriter::NewPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, Orientation eOrientation )
+{
+ return ((PDFWriterImpl*)pImplementation)->newPage( nPageWidth, nPageHeight, eOrientation );
+}
+
+bool PDFWriter::Emit()
+{
+ return ((PDFWriterImpl*)pImplementation)->emit();
+}
+
+PDFWriter::PDFVersion PDFWriter::GetVersion() const
+{
+ return ((PDFWriterImpl*)pImplementation)->getVersion();
+}
+
+void PDFWriter::SetFont( const Font& rFont )
+{
+ ((PDFWriterImpl*)pImplementation)->setFont( rFont );
+}
+
+void PDFWriter::DrawText( const Point& rPos, const String& rText )
+{
+ ((PDFWriterImpl*)pImplementation)->drawText( rPos, rText );
+}
+
+void PDFWriter::DrawTextLine(
+ const Point& rPos,
+ long nWidth,
+ FontStrikeout eStrikeout,
+ FontUnderline eUnderline,
+ BOOL bUnderlineAbove )
+{
+ // TODO
+}
+
+void PDFWriter::DrawTextArray(
+ const Point& rStartPt,
+ const XubString& rStr,
+ const long* pDXAry,
+ xub_StrLen nIndex,
+ xub_StrLen nLen )
+{
+ // TODO
+ DrawText( rStartPt, rStr );
+}
+
+void PDFWriter::DrawStretchText(
+ const Point& rStartPt,
+ ULONG nWidth,
+ const XubString& rStr,
+ xub_StrLen nIndex,
+ xub_StrLen nLen )
+{
+ // TODO
+ DrawText( rStartPt, rStr );
+}
+
+void PDFWriter::DrawText(
+ const Rectangle& rRect,
+ const XubString& rStr,
+ USHORT nStyle )
+{
+ // TODO
+ DrawText( rRect.TopLeft(), rStr );
+}
+
+void PDFWriter::DrawLine( const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawLine( rStart, rStop );
+}
+
+void PDFWriter::DrawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
+{
+ ((PDFWriterImpl*)pImplementation)->drawLine( rStart, rStop, rInfo );
+}
+
+void PDFWriter::DrawPolygon( const Polygon& rPoly )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolygon( rPoly );
+}
+
+void PDFWriter::DrawPolyLine( const Polygon& rPoly )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyLine( rPoly );
+}
+
+void PDFWriter::DrawRect( const Rectangle& rRect )
+{
+ ((PDFWriterImpl*)pImplementation)->drawRectangle( rRect );
+}
+
+void PDFWriter::DrawRect( const Rectangle& rRect, ULONG nHorzRound, ULONG nVertRound )
+{
+ ((PDFWriterImpl*)pImplementation)->drawRectangle( rRect, nHorzRound, nVertRound );
+}
+
+void PDFWriter::DrawEllipse( const Rectangle& rRect )
+{
+ ((PDFWriterImpl*)pImplementation)->drawEllipse( rRect );
+}
+
+void PDFWriter::DrawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawArc( rRect, rStart, rStop, false, false );
+}
+
+void PDFWriter::DrawPie( const Rectangle& rRect, const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawArc( rRect, rStart, rStop, true, false );
+}
+
+void PDFWriter::DrawChord( const Rectangle& rRect, const Point& rStart, const Point& rStop )
+{
+ ((PDFWriterImpl*)pImplementation)->drawArc( rRect, rStart, rStop, false, true );
+}
+
+void PDFWriter::DrawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyLine( rPoly, rInfo );
+}
+
+void PDFWriter::DrawPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPolyPolygon( rPolyPoly );
+}
+
+void PDFWriter::DrawPixel( const Point& rPos, const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPixel( rPos, rColor );
+}
+
+void PDFWriter::DrawPixel( const Polygon& rPts, const Color* pColors )
+{
+ ((PDFWriterImpl*)pImplementation)->drawPixel( rPts, pColors );
+}
+
+void PDFWriter::DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap )
+{
+ Size aSize = OutputDevice::LogicToLogic( rBitmap.GetPrefSize(),
+ rBitmap.GetPrefMapMode(),
+ ((PDFWriterImpl*)pImplementation)->getMapMode() );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, aSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap )
+{
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, const Bitmap& rBitmap )
+{
+ Bitmap aBitmap( rBitmap );
+ aBitmap.Crop( Rectangle( rSrcPtPixel, rSrcSizePixel ) );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, aBitmap );
+}
+
+void PDFWriter::DrawBitmapEx( const Point& rDestPt, const BitmapEx& rBitmap )
+{
+ Size aSize = OutputDevice::LogicToLogic( rBitmap.GetPrefSize(),
+ rBitmap.GetPrefMapMode(),
+ ((PDFWriterImpl*)pImplementation)->getMapMode() );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, aSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, const BitmapEx& rBitmap )
+{
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, rBitmap );
+}
+
+void PDFWriter::DrawBitmapEx( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, const BitmapEx& rBitmap )
+{
+ BitmapEx aBitmap( rBitmap );
+ aBitmap.Crop( Rectangle( rSrcPtPixel, rSrcSizePixel ) );
+ ((PDFWriterImpl*)pImplementation)->drawBitmap( rDestPt, rDestSize, aBitmap );
+}
+
+void PDFWriter::DrawMask( const Point& rDestPt, const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ Size aSize = OutputDevice::LogicToLogic( rBitmap.GetPrefSize(),
+ rBitmap.GetPrefMapMode(),
+ ((PDFWriterImpl*)pImplementation)->getMapMode() );
+ ((PDFWriterImpl*)pImplementation)->drawMask( rDestPt, aSize, rBitmap, rMaskColor );
+}
+
+void PDFWriter::DrawMask( const Point& rDestPt, const Size& rDestSize, const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ ((PDFWriterImpl*)pImplementation)->drawMask( rDestPt, rDestSize, rBitmap, rMaskColor );
+}
+
+void PDFWriter::DrawMask( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, const Bitmap& rBitmap, const Color& rMaskColor )
+{
+ Bitmap aBitmap( rBitmap );
+ aBitmap.Crop( Rectangle( rSrcPtPixel, rSrcSizePixel ) );
+ ((PDFWriterImpl*)pImplementation)->drawMask( rDestPt, rDestSize, aBitmap, rMaskColor );
+}
+
+void PDFWriter::DrawGradient( const Rectangle& rRect, const Gradient& rGradient )
+{
+ ((PDFWriterImpl*)pImplementation)->drawGradient( rRect, rGradient );
+}
+
+void PDFWriter::DrawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
+{
+ ((PDFWriterImpl*)pImplementation)->drawGradient( rPolyPoly, rGradient );
+}
+
+void PDFWriter::DrawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
+{
+ ((PDFWriterImpl*)pImplementation)->drawHatch( rPolyPoly, rHatch );
+}
+
+void PDFWriter::DrawWallpaper( const Rectangle& rRect, const Wallpaper& rWallpaper )
+{
+ ((PDFWriterImpl*)pImplementation)->drawWallpaper( rRect, rWallpaper );
+}
+
+void PDFWriter::DrawTransparent( const PolyPolygon& rPolyPoly, USHORT nTransparencePercent )
+{
+ ((PDFWriterImpl*)pImplementation)->drawTransparent( rPolyPoly, nTransparencePercent );
+}
+
+void PDFWriter::Push()
+{
+ ((PDFWriterImpl*)pImplementation)->push();
+}
+
+void PDFWriter::Pop()
+{
+ ((PDFWriterImpl*)pImplementation)->pop();
+}
+
+void PDFWriter::SetMapMode( const MapMode& rMapMode )
+{
+ ((PDFWriterImpl*)pImplementation)->setMapMode( rMapMode );
+}
+
+void PDFWriter::SetMapMode()
+{
+ ((PDFWriterImpl*)pImplementation)->setMapMode();
+}
+
+void PDFWriter::SetLineColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setLineColor( rColor );
+}
+
+void PDFWriter::SetFillColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setFillColor( rColor );
+}
+
+void PDFWriter::SetClipRegion()
+{
+ ((PDFWriterImpl*)pImplementation)->clearClipRegion();
+}
+
+void PDFWriter::SetClipRegion( const Region& rRegion )
+{
+ ((PDFWriterImpl*)pImplementation)->setClipRegion( rRegion );
+}
+
+void PDFWriter::MoveClipRegion( long nHorzMove, long nVertMove )
+{
+ ((PDFWriterImpl*)pImplementation)->moveClipRegion( nHorzMove, nVertMove );
+}
+
+void PDFWriter::IntersectClipRegion( const Region& rRegion )
+{
+ ((PDFWriterImpl*)pImplementation)->intersectClipRegion( rRegion );
+}
+
+void PDFWriter::IntersectClipRegion( const Rectangle& rRect )
+{
+ ((PDFWriterImpl*)pImplementation)->intersectClipRegion( rRect );
+}
+
+void PDFWriter::SetAntialiasing( USHORT nMode )
+{
+ ((PDFWriterImpl*)pImplementation)->setAntiAlias( (sal_Int32)nMode );
+}
+
+void PDFWriter::SetLayoutMode( ULONG nMode )
+{
+ ((PDFWriterImpl*)pImplementation)->setLayoutMode( (sal_Int32)nMode );
+}
+
+void PDFWriter::SetTextColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setTextColor( rColor );
+}
+
+void PDFWriter::SetTextFillColor()
+{
+ ((PDFWriterImpl*)pImplementation)->setTextFillColor();
+}
+
+void PDFWriter::SetTextFillColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setTextFillColor( rColor );
+}
+
+void PDFWriter::SetTextLineColor()
+{
+ ((PDFWriterImpl*)pImplementation)->setTextLineColor();
+}
+
+void PDFWriter::SetTextLineColor( const Color& rColor )
+{
+ ((PDFWriterImpl*)pImplementation)->setTextLineColor( rColor );
+}
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
new file mode 100644
index 000000000000..8f41de0bf3a3
--- /dev/null
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -0,0 +1,2317 @@
+/*************************************************************************
+ *
+ * $RCSfile: pdfwriter_impl.cxx,v $
+ *
+ * $Revision: 1.1 $
+ *
+ * last change: $Author: pl $ $Date: 2002-07-08 14:18:55 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (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.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <pdfwriter_impl.hxx>
+#include <rtl/strbuf.hxx>
+#include <tools/debug.hxx>
+#include <virdev.hxx>
+#include <bmpacc.hxx>
+#include <bitmapex.hxx>
+#include <image.hxx>
+
+#include "implncvt.hxx"
+
+#include <math.h>
+
+using namespace vcl;
+using namespace rtl;
+
+#if defined DEBUG || defined DBG_UTIL
+#define MARK( x ) emitComment( x )
+#else
+#define MARK( x )
+#endif
+
+static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer )
+{
+ static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+ rBuffer.append( pHexDigits[ (nInt >> 4) & 15 ] );
+ rBuffer.append( pHexDigits[ nInt & 15 ] );
+}
+
+// appends a double. PDF does not accept exponential format, only fixed point
+static void appendDouble( double fValue, OStringBuffer& rBuffer, int nPrecision = 5 )
+{
+ if( fValue < 0 )
+ {
+ rBuffer.append( '-' );
+ fValue=-fValue;
+ }
+
+ sal_Int64 nInt = (sal_Int64)fValue;
+ fValue -= (double)nInt;
+ // optimizing hardware may lead to a value of 1.0 after the subtraction
+ if( fValue == 1.0 || log10( 1.0-fValue ) <= -nPrecision )
+ {
+ nInt++;
+ fValue = 0.0;
+ }
+ rBuffer.append( nInt );
+ if( fValue )
+ {
+ fValue *= pow( 10.0, (double)nPrecision );
+ nInt = (sal_Int64)fValue;
+ while( nInt && ! (nInt % 10 ) )
+ nInt /= 10;
+ if( nInt )
+ {
+ rBuffer.append( '.' );
+ rBuffer.append( nInt );
+ }
+ }
+}
+
+
+static void appendColor( const Color& rColor, OStringBuffer& rBuffer )
+{
+
+ if( rColor != Color( COL_TRANSPARENT ) )
+ {
+ appendDouble( (double)rColor.GetRed() / 255.0, rBuffer );
+ rBuffer.append( ' ' );
+ appendDouble( (double)rColor.GetGreen() / 255.0, rBuffer );
+ rBuffer.append( ' ' );
+ appendDouble( (double)rColor.GetBlue() / 255.0, rBuffer );
+ }
+}
+
+static void appendStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
+{
+ if( rColor != Color( COL_TRANSPARENT ) )
+ {
+ appendColor( rColor, rBuffer );
+ rBuffer.append( " RG" );
+ }
+}
+
+static void appendNonStrokingColor( const Color& rColor, OStringBuffer& rBuffer )
+{
+ if( rColor != Color( COL_TRANSPARENT ) )
+ {
+ appendColor( rColor, rBuffer );
+ rBuffer.append( " rg" );
+ }
+}
+
+
+PDFWriterImpl::PDFPage::PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
+ :
+ m_pWriter( pWriter ),
+ m_nPageWidth( nPageWidth ),
+ m_nPageHeight( nPageHeight ),
+ m_eOrientation( eOrientation ),
+ m_nPageObject( 0 ), // invalid object number
+ m_nStreamObject( 0 ),
+ m_nStreamLengthObject( 0 ),
+ m_nBeginStreamPos( 0 )
+{
+}
+
+PDFWriterImpl::PDFPage::~PDFPage()
+{
+}
+
+void PDFWriterImpl::PDFPage::beginStream()
+{
+ m_nStreamObject = m_pWriter->createObject();
+ if( ! m_pWriter->updateObject( m_nStreamObject ) )
+ return;
+
+ m_nStreamLengthObject = m_pWriter->createObject();
+ // write content stream header
+ OStringBuffer aLine;
+ aLine.append( m_nStreamObject );
+ aLine.append( " 0 obj\r\n << /Length " );
+ aLine.append( m_nStreamLengthObject );
+ aLine.append( " 0 R >>\r\nstream\r\n" );
+ if( ! m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() ) )
+ return;
+ if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &m_nBeginStreamPos ) )
+ {
+ osl_closeFile( m_pWriter->m_aFile );
+ m_pWriter->m_bOpen = false;
+ }
+}
+
+void PDFWriterImpl::PDFPage::endStream()
+{
+ sal_uInt64 nEndStreamPos;
+ if( osl_File_E_None != osl_getFilePos( m_pWriter->m_aFile, &nEndStreamPos ) )
+ {
+ osl_closeFile( m_pWriter->m_aFile );
+ m_pWriter->m_bOpen = false;
+ return;
+ }
+ if( ! m_pWriter->writeBuffer( "endstream\r\nendobj\r\n\r\n", 21 ) )
+ return;
+ // emit stream length object
+ if( ! m_pWriter->updateObject( m_nStreamLengthObject ) )
+ return;
+ OStringBuffer aLine;
+ aLine.append( m_nStreamLengthObject );
+ aLine.append( " 0 obj\r\n " );
+ aLine.append( (sal_Int64)(nEndStreamPos-m_nBeginStreamPos) );
+ aLine.append( "\r\nendobj\r\n\r\n" );
+ m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+bool PDFWriterImpl::PDFPage::PDFPage::emit(sal_Int32 nParentObject )
+{
+ // emit page object
+ m_nPageObject = m_pWriter->createObject();
+ if( ! m_pWriter->updateObject( m_nPageObject ) )
+ return false;
+ OStringBuffer aLine;
+
+ aLine.append( m_nPageObject );
+ aLine.append( " 0 obj\r\n << /Type /Page\r\n /Parent " );
+ aLine.append( nParentObject );
+ aLine.append( " 0 R\r\n" );
+ if( m_nPageWidth && m_nPageHeight )
+ {
+ aLine.append( " /MediaBox " );
+ aLine.append( "[ 0 0 " );
+ aLine.append( m_nPageWidth );
+ aLine.append( ' ' );
+ aLine.append( m_nPageHeight );
+ aLine.append( " ]\r\n" );
+ }
+ switch( m_eOrientation )
+ {
+ case PDFWriter::Landscape: aLine.append( " /Rotate 90\r\n" );break;
+ case PDFWriter::Seascape: aLine.append( " /Rotate -90\r\n" );break;
+ case PDFWriter::Portrait: aLine.append( " /Rotate 0\r\n" );break;
+
+ case PDFWriter::Inherit:
+ default:
+ break;
+ }
+ aLine.append( " /Contents " );
+ aLine.append( m_nStreamObject );
+ aLine.append( " 0 R\r\n >>\r\nendobj\r\n\r\n" );
+ return m_pWriter->writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::PDFPage::appendPoint( const Point& rPoint, OStringBuffer& rBuffer, bool bNeg )
+{
+ Point aPoint = OutputDevice::LogicToLogic( Point( rPoint.X(), rPoint.Y() ),
+ m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode );
+ sal_Int32 nValue = aPoint.X();
+ if( bNeg )
+ nValue = -nValue;
+
+ if( nValue < 0 )
+ {
+ rBuffer.append( '-' );
+ nValue = -nValue;
+ }
+ sal_Int32 nInt = nValue / 10;
+ sal_Int32 nDecimal = nValue % 10;
+ rBuffer.append( nInt );
+ if( nDecimal )
+ {
+ rBuffer.append( '.' );
+ rBuffer.append( nDecimal );
+ }
+
+ rBuffer.append( ' ' );
+
+ nValue = 10*(m_nPageHeight ? m_nPageHeight : m_pWriter->m_nInheritedPageHeight) - aPoint.Y();
+ if( bNeg )
+ nValue = -nValue;
+
+ if( nValue < 0 )
+ {
+ rBuffer.append( '-' );
+ nValue = -nValue;
+ }
+ nInt = nValue / 10;
+ nDecimal = nValue % 10;
+ rBuffer.append( nInt );
+ if( nDecimal )
+ {
+ rBuffer.append( '.' );
+ rBuffer.append( nDecimal );
+ }
+}
+
+void PDFWriterImpl::PDFPage::appendRect( const Rectangle& rRect, OStringBuffer& rBuffer )
+{
+ appendPoint( rRect.BottomLeft() + Point( 0, 1 ), rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( rRect.GetWidth(), rBuffer, false );
+ rBuffer.append( ' ' );
+ appendMappedLength( rRect.GetHeight(), rBuffer, true );
+ rBuffer.append( " re" );
+}
+
+void PDFWriterImpl::PDFPage::appendPolygon( const Polygon& rPoly, OStringBuffer& rBuffer, bool bClose )
+{
+ int nPoints = rPoly.GetSize();
+ appendPoint( rPoly[0], rBuffer );
+ rBuffer.append( " m\r\n" );
+ for( int i = 1; i < nPoints; i++ )
+ {
+ appendPoint( rPoly[i], rBuffer );
+ rBuffer.append( " l" );
+ rBuffer.append( (i & 3) ? " " : "\r\n" );
+ }
+ if( bClose )
+ rBuffer.append( "h\r\n" );
+}
+
+void PDFWriterImpl::PDFPage::appendPolyPolygon( const PolyPolygon& rPolyPoly, OStringBuffer& rBuffer, bool bClose )
+{
+ int nPolygons = rPolyPoly.Count();
+ for( int n = 0; n < nPolygons; n++ )
+ appendPolygon( rPolyPoly[n], rBuffer, bClose );
+}
+
+void PDFWriterImpl::PDFPage::appendMappedLength( sal_Int32 nLength, OStringBuffer& rBuffer, bool bVertical )
+{
+ Size aSize = OutputDevice::LogicToLogic( Size( nLength, nLength ),
+ m_pWriter->m_aGraphicsStack.front().m_aMapMode,
+ m_pWriter->m_aMapMode );
+ sal_Int32 nInt = ( bVertical ? aSize.Height() : aSize.Width() ) / 10;
+ sal_Int32 nDecimal = ( bVertical ? aSize.Height() : aSize.Width() ) % 10;
+ rBuffer.append( nInt );
+ if( nDecimal )
+ {
+ rBuffer.append( '.' );
+ rBuffer.append( nDecimal );
+ }
+}
+
+void PDFWriterImpl::PDFPage::appendLineInfo( const LineInfo& rInfo, OStringBuffer& rBuffer )
+{
+ if( rInfo.GetStyle() == LINE_DASH )
+ {
+ rBuffer.append( "[ " );
+ for( int n = 0; n < rInfo.GetDashCount(); n++ )
+ {
+ appendMappedLength( rInfo.GetDashLen(), rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( rInfo.GetDistance(), rBuffer );
+ rBuffer.append( ' ' );
+ }
+ for( int m = 0; m < rInfo.GetDotCount(); m++ )
+ {
+ appendMappedLength( rInfo.GetDotLen(), rBuffer );
+ rBuffer.append( ' ' );
+ appendMappedLength( rInfo.GetDistance(), rBuffer );
+ rBuffer.append( ' ' );
+ }
+ rBuffer.append( "] 0 d\r\n" );
+ }
+ if( rInfo.GetWidth() > 1 )
+ {
+ appendMappedLength( rInfo.GetWidth(), rBuffer );
+ rBuffer.append( " w\r\n" );
+ }
+}
+
+/*
+ * class PDFWriterImpl
+ */
+
+PDFWriterImpl::PDFWriterImpl( const OUString& rFilename, PDFWriter::PDFVersion eVersion )
+ :
+ m_aFileName( rFilename ),
+ m_pReferenceDevice( NULL ),
+ m_nInheritedPageWidth( 595 ), // default A4
+ m_nInheritedPageHeight( 842 ), // default A4
+ m_eInheritedOrientation( PDFWriter::Portrait ),
+ m_nCurrentPage( -1 ),
+ m_eVersion( eVersion ),
+ m_nNextFID( 1 ),
+ m_aMapMode( MAP_POINT, Point(), Fraction( 1L, 10L ), Fraction( 1L, 10L ) )
+{
+ Font aFont;
+ aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
+ aFont.SetSize( Size( 0, 12 ) );
+
+ GraphicsState aState;
+ aState.m_aMapMode = m_aMapMode;
+ aState.m_aFont = aFont;
+ m_aGraphicsStack.push_front( aState );
+
+ oslFileError aError = osl_openFile( m_aFileName.pData, &m_aFile, osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
+ if( aError != osl_File_E_None )
+ {
+ if( aError == osl_File_E_EXIST )
+ {
+ aError = osl_openFile( m_aFileName.pData, &m_aFile, osl_File_OpenFlag_Write );
+ if( aError == osl_File_E_None )
+ aError = osl_setFileSize( m_aFile, 0 );
+ }
+ }
+ if( aError != osl_File_E_None )
+ return;
+
+ // write header
+ OStringBuffer aBuffer( 20 );
+ aBuffer.append( "%PDF-" );
+ switch( m_eVersion )
+ {
+ case PDFWriter::PDF_1_2: aBuffer.append( "1.2" );break;
+ case PDFWriter::PDF_1_3: aBuffer.append( "1.3" );break;
+ default:
+ case PDFWriter::PDF_1_4: aBuffer.append( "1.4" );break;
+ }
+ // append something binary as comment (suggested in PDF Reference)
+ aBuffer.append( "\r\n%\r\n" );
+ if( !writeBuffer( aBuffer.getStr(), aBuffer.getLength() ) )
+ {
+ osl_closeFile( m_aFile );
+ return;
+ }
+ m_bOpen = true;
+}
+
+PDFWriterImpl::~PDFWriterImpl()
+{
+ delete static_cast<VirtualDevice*>(m_pReferenceDevice);
+}
+
+void PDFWriterImpl::emitComment( const OString& rComment )
+{
+ OStringBuffer aLine( rComment.getLength()+5 );
+ aLine.append( "% " );
+ aLine.append( rComment );
+ aLine.append( "\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+bool PDFWriterImpl::writeBuffer( const void* pBuffer, sal_uInt64 nBytes )
+{
+ if( ! m_bOpen ) // we are already down the drain
+ return false;
+
+ if( ! nBytes ) // huh ?
+ return true;
+
+ sal_uInt64 nWritten;
+ if( osl_writeFile( m_aFile, pBuffer, nBytes, &nWritten ) != osl_File_E_None )
+ nWritten = 0;
+
+ if( nWritten != nBytes )
+ {
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+ }
+
+ return nWritten == nBytes;
+}
+
+OutputDevice* PDFWriterImpl::getReferenceDevice()
+{
+ if( ! m_pReferenceDevice )
+ {
+ VirtualDevice* pVDev = new VirtualDevice( 0 );
+ m_pReferenceDevice = pVDev;
+ pVDev->SetOutputSizePixel( Size( 640, 480 ) );
+ }
+ return m_pReferenceDevice;
+}
+
+sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation )
+{
+ endPage();
+ m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) );
+ m_aPages.back().beginStream();
+ return ++m_nCurrentPage;
+}
+
+void PDFWriterImpl::endPage()
+{
+ if( m_aPages.begin() != m_aPages.end() )
+ {
+ m_aGraphicsStack.clear();
+ m_aGraphicsStack.push_back( GraphicsState() );
+
+ // this should pop the PDF graphics stack if necessary
+ updateGraphicsState();
+
+ m_aPages.back().endStream();
+
+ // reset the default font
+ Font aFont;
+ aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Times" ) ) );
+ aFont.SetSize( Size( 0, 12 ) );
+
+ m_aCurrentPDFState = m_aGraphicsStack.front();
+ m_aGraphicsStack.front().m_aFont = aFont;
+
+ for( std::list<BitmapEmit>::iterator it = m_aBitmaps.begin();
+ it != m_aBitmaps.end(); ++it )
+ {
+ if( ! it->m_aBitmap.IsEmpty() )
+ {
+ writeBitmapObject( *it );
+ it->m_aBitmap = BitmapEx();
+ }
+ }
+ }
+}
+
+sal_Int32 PDFWriterImpl::createObject()
+{
+ m_aObjects.push_back( ~0 );
+ return m_aObjects.size();
+}
+
+bool PDFWriterImpl::updateObject( sal_Int32 n )
+{
+ if( ! m_bOpen )
+ return false;
+
+ sal_uInt64 nOffset = ~0;
+ oslFileError aError = osl_getFilePos( m_aFile, &nOffset );
+ DBG_ASSERT( aError == osl_File_E_None, "could not register object" );
+ if( aError != osl_File_E_None )
+ {
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+ }
+ m_aObjects[ n-1 ] = nOffset;
+ return aError == osl_File_E_None;
+}
+
+#define CHECK_RETURN( x ) if( !x ) return 0
+
+bool PDFWriterImpl::emitGradients()
+{
+ for( std::list<GradientEmit>::iterator it = m_aGradients.begin();
+ it != m_aGradients.end(); ++it )
+ {
+ CHECK_RETURN( writeGradientFunction( *it ) );
+ }
+ return true;
+}
+
+bool PDFWriterImpl::emitTilings()
+{
+ OStringBuffer aTilingStream( 1024 );
+ OStringBuffer aTilingObj( 1024 );
+
+ for( std::list<BitmapPatternEmit>::const_iterator it = m_aTilings.begin(); it != m_aTilings.end(); ++it )
+ {
+ aTilingStream.setLength( 0 );
+ aTilingObj.setLength( 0 );
+
+ sal_Int32 nX = (sal_Int32)it->m_aRectangle.BottomLeft().X();
+ sal_Int32 nY = (sal_Int32)it->m_aRectangle.BottomLeft().Y()+1;
+ sal_Int32 nW = (sal_Int32)it->m_aRectangle.GetWidth();
+ sal_Int32 nH = (sal_Int32)it->m_aRectangle.GetHeight();
+
+ appendDouble( (double)nW/10.0, aTilingStream, 1 );
+ aTilingStream.append( " 0 0 " );
+ appendDouble( (double)nH/10.0, aTilingStream, 1 );
+ aTilingStream.append( ' ' );
+ appendDouble( (double)nX/10.0, aTilingStream, 1 );
+ aTilingStream.append( ' ' );
+ appendDouble( (double)nY/10.0, aTilingStream, 1 );
+ aTilingStream.append( " cm\r\n /Im" );
+ aTilingStream.append( it->m_nBitmapObject );
+ aTilingStream.append( " Do\r\n" );
+
+ // write pattern object
+ aTilingObj.append( it->m_nObject );
+ aTilingObj.append( " 0 obj\r\n" );
+ aTilingObj.append( " << /Type /Pattern\r\n /PatternType 1\r\n /PaintType 1\r\n /TilingType 1\r\n /BBox [ " );
+ appendDouble( (double)nX/10.0, aTilingObj, 1 );
+ aTilingObj.append( ' ' );
+ appendDouble( (double)nY/10.0, aTilingObj, 1 );
+ aTilingObj.append( ' ' );
+ appendDouble( (double)(nX+nW)/10.0, aTilingObj, 1 );
+ aTilingObj.append( ' ' );
+ appendDouble( (double)(nY+nH)/10.0, aTilingObj, 1 );
+ aTilingObj.append( " ]\r\n /XStep " );
+ appendDouble( (double)nW/10.0, aTilingObj, 1 );
+ aTilingObj.append( "\r\n /YStep " );
+ appendDouble( (double)nH/10.0, aTilingObj, 1 );
+ aTilingObj.append( "\r\n /Resources <<\r\n" );
+ aTilingObj.append( " /XObject << /Im" );
+ aTilingObj.append( it->m_nBitmapObject );
+ aTilingObj.append( ' ' );
+ aTilingObj.append( it->m_nBitmapObject );
+ aTilingObj.append( " 0 R >> >>\r\n /Length " );
+ aTilingObj.append( (sal_Int32)aTilingStream.getLength() );
+ aTilingObj.append( "\r\n >>\r\nstream\r\n" );
+ CHECK_RETURN( updateObject( it->m_nObject ) );
+ CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
+ CHECK_RETURN( writeBuffer( aTilingStream.getStr(), aTilingStream.getLength() ) );
+ aTilingObj.setLength( 0 );
+ aTilingObj.append( "\r\nendstream\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aTilingObj.getStr(), aTilingObj.getLength() ) );
+ }
+ return true;
+}
+
+bool PDFWriterImpl::emitHatches()
+{
+ OStringBuffer aHatchStream( 1024 );
+ OStringBuffer aHatchObj( 1024 );
+
+ // get maximum page rectangle
+ sal_Int32 nWidth, nHeight, nMax = 0;
+ for( std::list<PDFPage>::const_iterator pg = m_aPages.begin(); pg != m_aPages.end(); ++pg )
+ {
+ if( pg->m_nPageWidth && pg->m_nPageHeight )
+ {
+ nWidth = pg->m_nPageWidth;
+ nHeight = pg->m_nPageHeight;
+ }
+ else
+ {
+ nWidth = m_nInheritedPageWidth;
+ nHeight = m_nInheritedPageHeight;
+ }
+ nMax = (nMax > nWidth ? nMax : nWidth);
+ nMax = (nMax > nHeight ? nMax : nHeight);
+ }
+
+ nMax /= 2;
+
+ sal_Int32 nSingleHatch = 0, nDoubleHatch = 0, nTripleHatch = 0;
+
+ for( std::list<HatchEmit>::iterator it = m_aHatches.begin(); it != m_aHatches.end(); ++it )
+ {
+ aHatchStream.setLength( 0 );
+ aHatchObj.setLength( 0 );
+
+ const Hatch& rHatch = it->m_aHatch;
+
+ // draw hatch
+ sal_Int32 nBaseHatch = 0;
+ switch( rHatch.GetStyle() )
+ {
+ case HATCH_SINGLE:
+ if( ! nSingleHatch )
+ nSingleHatch = createObject();
+ nBaseHatch = nSingleHatch;
+ break;
+ case HATCH_DOUBLE:
+ if( ! nDoubleHatch )
+ nDoubleHatch = createObject();
+ nBaseHatch = nDoubleHatch;
+ break;
+ case HATCH_TRIPLE:
+ if( ! nTripleHatch )
+ nTripleHatch = createObject();
+ nBaseHatch = nTripleHatch;
+ break;
+ }
+ aHatchStream.append( "/HCS cs " );
+ aHatchStream.append( (double)rHatch.GetColor().GetRed()/255.0 );
+ aHatchStream.append( ' ' );
+ aHatchStream.append( (double)rHatch.GetColor().GetGreen()/255.0 );
+ aHatchStream.append( ' ' );
+ aHatchStream.append( (double)rHatch.GetColor().GetBlue()/255.0 );
+ aHatchStream.append( " /P" );
+ aHatchStream.append( nBaseHatch );
+ aHatchStream.append( " scn\r\n" );
+ aHatchStream.append( -nMax );
+ aHatchStream.append( ' ' );
+ aHatchStream.append( -nMax );
+ aHatchStream.append( ' ' );
+ aHatchStream.append( 2*nMax );
+ aHatchStream.append( ' ' );
+ aHatchStream.append( 2*nMax );
+ aHatchStream.append( " re f\r\n" );
+
+ // write pattern object
+ aHatchObj.append( it->m_nObject );
+ aHatchObj.append( " 0 obj\r\n" );
+ aHatchObj.append( " << /Type /Pattern\r\n /PatternType 1\r\n /PaintType 1\r\n /TilingType 1\r\n /BBox [ " );
+ aHatchObj.append( -nMax );
+ aHatchObj.append( ' ' );
+ aHatchObj.append( -nMax );
+ aHatchObj.append( ' ' );
+ aHatchObj.append( nMax );
+ aHatchObj.append( ' ' );
+ aHatchObj.append( nMax );
+ aHatchObj.append( " ]\r\n /XStep " );
+ aHatchObj.append( 2*nMax );
+ aHatchObj.append( "\r\n /YStep " );
+ aHatchObj.append( 2*nMax );
+ aHatchObj.append( "\r\n /Matrix [ " );
+ // prepare matrix
+ const double theta = (double)rHatch.GetAngle() * M_PI / 1800.0;
+ /* the constant factor in scale is arbitrary */
+ const double scale = 2.0*(double)rHatch.GetDistance();
+ appendDouble( scale*cos( theta ), aHatchObj );
+ aHatchObj.append( ' ' );
+ appendDouble( scale*sin( theta ), aHatchObj );
+ aHatchObj.append( ' ' );
+ appendDouble( scale*(-sin( theta )), aHatchObj );
+ aHatchObj.append( ' ' );
+ appendDouble( scale*cos( theta ), aHatchObj );
+ aHatchObj.append( " 0 0 ]\r\n" );
+
+ aHatchObj.append( " /Resources <<\r\n" );
+ aHatchObj.append( " /ColorSpace << /HCS [ /Pattern /DeviceRGB ] >>\r\n" );
+ aHatchObj.append( " /Pattern << /P" );
+ aHatchObj.append( nBaseHatch );
+ aHatchObj.append( ' ' );
+ aHatchObj.append( nBaseHatch );
+ aHatchObj.append( " 0 R >>\r\n" );
+ aHatchObj.append( " >>\r\n /Length " );
+ aHatchObj.append( (sal_Int32)aHatchStream.getLength() );
+ aHatchObj.append( "\r\n >>\r\nstream\r\n" );
+ CHECK_RETURN( updateObject( it->m_nObject ) );
+ CHECK_RETURN( writeBuffer( aHatchObj.getStr(), aHatchObj.getLength() ) );
+ CHECK_RETURN( writeBuffer( aHatchStream.getStr(), aHatchStream.getLength() ) );
+ aHatchObj.setLength( 0 );
+ aHatchObj.append( "\r\nendstream\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aHatchObj.getStr(), aHatchObj.getLength() ) );
+ }
+
+ // emit needed base hatches
+ for( int i = 0; i < 3; i++ )
+ {
+ if( ( i == 0 && nSingleHatch ) ||
+ ( i == 1 && nDoubleHatch ) ||
+ ( i == 2 && nTripleHatch ) )
+ {
+ sal_Int32 nObject = 0;
+ aHatchStream.setLength( 0 );
+ switch( i )
+ {
+ case 0:
+ nObject = nSingleHatch;
+ aHatchStream.append( "0 0 m 1 0 l S\r\n" );
+ break;
+ case 1:
+ nObject = nDoubleHatch;
+ aHatchStream.append( "0 0 m 1 0 l S\r\n" );
+ aHatchStream.append( "0 0 m 0 1 l S\r\n" );
+ break;
+ case 2:
+ nObject = nTripleHatch;
+ aHatchStream.append( "0 0 m 1 0 l S\r\n" );
+ aHatchStream.append( "0 0 m 0 1 l S\r\n" );
+ aHatchStream.append( "0 1 m 1 0 l S\r\n" );
+ break;
+ }
+ CHECK_RETURN( updateObject( nObject ) );
+ aHatchObj.setLength( 0 );
+
+ aHatchObj.append( nObject );
+ aHatchObj.append( " 0 obj\r\n" );
+ aHatchObj.append( " << /Type /Pattern\r\n /PatternType 1\r\n /PaintType 2\r\n /TilingType 1\r\n /BBox [ 0 0 1 1 ]\r\n" );
+ aHatchObj.append( " /XStep 1\r\n" );
+ aHatchObj.append( " /YStep 1\r\n" );
+ aHatchObj.append( " /Resources << >>\r\n /Length " );
+ aHatchObj.append( (sal_Int32)aHatchStream.getLength() );
+ aHatchObj.append( "\r\n >>\r\nstream\r\n" );
+ CHECK_RETURN( writeBuffer( aHatchObj.getStr(), aHatchObj.getLength() ) );
+ CHECK_RETURN( writeBuffer( aHatchStream.getStr(), aHatchStream.getLength() ) );
+ aHatchObj.setLength( 0 );
+ aHatchObj.append( "\r\nendstream\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aHatchObj.getStr(), aHatchObj.getLength() ) );
+ }
+ }
+ return true;
+}
+
+sal_Int32 PDFWriterImpl::emitFont( const Font& rFont )
+{
+ sal_Int32 nFont = 0;
+ // catch the 14 special fonts
+ if( rFont.GetName().EqualsIgnoreCaseAscii( "Times" )
+ || rFont.GetName().EqualsIgnoreCaseAscii( "Helvetica" )
+ || rFont.GetName().EqualsIgnoreCaseAscii( "Courier" )
+ || rFont.GetName().EqualsIgnoreCaseAscii( "Symbol" )
+ || rFont.GetName().EqualsIgnoreCaseAscii( "ZapfDingbats" )
+ )
+ {
+ // emit a simple font
+ nFont = createObject();
+ if( updateObject( nFont ) )
+ {
+ OStringBuffer aLine( 256 );
+ aLine.append( nFont );
+ aLine.append( " 0 obj\r\n << /Type /Font\r\n /Subtype /Type1\r\n /BaseFont " );
+ if( rFont.GetName().EqualsIgnoreCaseAscii( "Times" ) )
+ {
+ if( rFont.GetItalic() == ITALIC_NONE || rFont.GetItalic() == ITALIC_DONTKNOW )
+ {
+ if( rFont.GetWeight() == WEIGHT_DONTKNOW || rFont.GetWeight() < WEIGHT_SEMIBOLD )
+ aLine.append( "/Times-Roman" );
+ else
+ aLine.append( "/Times-Bold" );
+ }
+ else
+ {
+ if( rFont.GetWeight() == WEIGHT_DONTKNOW || rFont.GetWeight() < WEIGHT_SEMIBOLD )
+ aLine.append( "/Times-Italic" );
+ else
+ aLine.append( "/Times-BoldItalic" );
+ }
+ }
+ else if( rFont.GetName().EqualsIgnoreCaseAscii( "Helvetica" ) )
+ {
+ if( rFont.GetItalic() == ITALIC_NONE || rFont.GetItalic() == ITALIC_DONTKNOW )
+ {
+ if( rFont.GetWeight() == WEIGHT_DONTKNOW || rFont.GetWeight() < WEIGHT_SEMIBOLD )
+ aLine.append( "/Helvetica" );
+ else
+ aLine.append( "/Helvetica-Bold" );
+ }
+ else
+ {
+ if( rFont.GetWeight() == WEIGHT_DONTKNOW || rFont.GetWeight() < WEIGHT_SEMIBOLD )
+ aLine.append( "/Helvetica-Oblique" );
+ else
+ aLine.append( "/Helvetica-BoldOblique" );
+ }
+ }
+ else if( rFont.GetName().EqualsIgnoreCaseAscii( "Courier" ) )
+ {
+ if( rFont.GetItalic() == ITALIC_NONE || rFont.GetItalic() == ITALIC_DONTKNOW )
+ {
+ if( rFont.GetWeight() == WEIGHT_DONTKNOW || rFont.GetWeight() < WEIGHT_SEMIBOLD )
+ aLine.append( "/Courier" );
+ else
+ aLine.append( "/Courier" );
+ }
+ else
+ {
+ if( rFont.GetWeight() == WEIGHT_DONTKNOW || rFont.GetWeight() < WEIGHT_SEMIBOLD )
+ aLine.append( "/Courier-Oblique" );
+ else
+ aLine.append( "/Courier-BoldOblique" );
+ }
+ }
+ else if( rFont.GetName().EqualsIgnoreCaseAscii( "ZapfDingbats" ) )
+ aLine.append( "/ZapfDingbats" );
+ else
+ aLine.append( "/Symbol" );
+ aLine.append( "\r\n >>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+ }
+ // much TODO here
+ // preliminary: map everything else to Helvetica
+ else
+ {
+ Font aFont( rFont );
+ aFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Helvetica" ) ) );
+ nFont = emitFont( aFont );
+ }
+
+ return nFont;
+}
+
+sal_Int32 PDFWriterImpl::emitResources()
+{
+ OStringBuffer aLine( 512 );
+
+ // emit shadings
+ sal_Int32 nShadingDict = 0;
+ if( m_aGradients.begin() != m_aGradients.end() )
+ {
+ CHECK_RETURN( emitGradients() );
+ aLine.setLength( 0 );
+ aLine.append( nShadingDict = createObject() );
+ aLine.append( " 0 obj\r\n << " );
+ for( std::list<GradientEmit>::iterator it = m_aGradients.begin();
+ it != m_aGradients.end(); ++it )
+ {
+ aLine.append( "/P" );
+ aLine.append( it->m_nObject );
+ aLine.append( ' ' );
+ aLine.append( it->m_nObject );
+ aLine.append( " 0 R\r\n " );
+ }
+ aLine.append( ">>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( updateObject( nShadingDict ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
+ // emit patterns
+ sal_Int32 nPatternDict = 0;
+ if( m_aHatches.begin() != m_aHatches.end() || m_aTilings.begin() != m_aTilings.end() )
+ {
+ if( m_aHatches.begin() != m_aHatches.end() )
+ CHECK_RETURN( emitHatches() );
+ if( m_aTilings.begin() != m_aTilings.end() )
+ CHECK_RETURN( emitTilings() );
+ aLine.setLength( 0 );
+ aLine.append( nPatternDict = createObject() );
+ aLine.append( " 0 obj\r\n << " );
+ for( std::list<HatchEmit>::const_iterator hatch = m_aHatches.begin();
+ hatch != m_aHatches.end(); ++hatch )
+ {
+ aLine.append( "/P" );
+ aLine.append( hatch->m_nObject );
+ aLine.append( ' ' );
+ aLine.append( hatch->m_nObject );
+ aLine.append( " 0 R\r\n " );
+ }
+ for( std::list<BitmapPatternEmit>::const_iterator tile = m_aTilings.begin();
+ tile != m_aTilings.end(); ++tile )
+ {
+ aLine.append( "/P" );
+ aLine.append( tile->m_nObject );
+ aLine.append( ' ' );
+ aLine.append( tile->m_nObject );
+ aLine.append( " 0 R\r\n " );
+ }
+ aLine.append( ">>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( updateObject( nPatternDict ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
+ // emit font dict
+ sal_Int32 nFontDict = createObject();
+ aLine.setLength( 0 );
+ aLine.append( nFontDict );
+ aLine.append( " 0 obj\r\n << " );
+ for( std::map< Font, sal_Int32 >::const_iterator it = m_aFonts.begin();
+ it != m_aFonts.end(); ++it )
+ {
+ sal_Int32 nFont = emitFont( it->first );
+ DBG_ASSERT( nFont, "could not emit font" );
+ if( nFont )
+ {
+ aLine.append( "/F" );
+ aLine.append( it->second );
+ aLine.append( ' ' );
+ aLine.append( nFont );
+ aLine.append( " 0 R\r\n " );
+ }
+ }
+ aLine.append( ">>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( updateObject( nFontDict ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ // emit xobject dict
+ sal_Int32 nXObjectDict = 0;
+ if( m_aBitmaps.begin() != m_aBitmaps.end() )
+ {
+ aLine.setLength( 0 );
+ nXObjectDict = createObject();
+ aLine.append( nXObjectDict );
+ aLine.append( " 0 obj\r\n << " );
+ for( std::list<BitmapEmit>::const_iterator it = m_aBitmaps.begin();
+ it != m_aBitmaps.end(); ++it )
+ {
+ aLine.append( "/Im" );
+ aLine.append( it->m_nObject );
+ aLine.append( ' ' );
+ aLine.append( it->m_nObject );
+ aLine.append( " 0 R\r\n " );
+ }
+ aLine.append( ">>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( updateObject( nXObjectDict ) );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
+ // emit Resource dict
+ sal_Int32 nResourceDict = createObject();
+ CHECK_RETURN( updateObject( nResourceDict ) );
+ aLine.setLength( 0 );
+ aLine.append( nResourceDict );
+ aLine.append( " 0 obj\r\n << /Font " );
+ aLine.append( nFontDict );
+ aLine.append( " 0 R\r\n" );
+ if( nXObjectDict )
+ {
+ aLine.append( " /XObject " );
+ aLine.append( nXObjectDict );
+ aLine.append( " 0 R\r\n" );
+ }
+ if( nShadingDict )
+ {
+ aLine.append( " /Shading " );
+ aLine.append( nShadingDict );
+ aLine.append( " 0 R\r\n" );
+ }
+ if( nPatternDict )
+ {
+ aLine.append( " /Pattern " );
+ aLine.append( nPatternDict );
+ aLine.append( " 0 R\r\n" );
+ }
+ aLine.append( " /ProcSet [ /PDF " );
+ if( nXObjectDict )
+ aLine.append( "/ImageC /ImageI " );
+ aLine.append( "]\r\n" );
+ aLine.append( " >>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ return nResourceDict;
+}
+
+#undef CHECK_RETURN
+#define CHECK_RETURN( x ) if( !x ) return false
+
+bool PDFWriterImpl::emitCatalog()
+{
+ // build page tree
+ // currently there is only one node that contains all leaves
+
+ // first create a page tree node id
+ sal_Int32 nTreeNode = createObject();
+
+ // emit all pages
+ for( std::list<PDFPage>::iterator it = m_aPages.begin(); it != m_aPages.end(); ++it )
+ if( ! it->emit( nTreeNode ) )
+ return false;
+
+ sal_Int32 nResourceDict = emitResources();
+
+ // adjust tree node file offset
+ if( ! updateObject( nTreeNode ) )
+ return false;
+
+ // emit tree node
+ OStringBuffer aLine( 1024 );
+ aLine.append( nTreeNode );
+ aLine.append( " 0 obj\r\n" );
+ aLine.append( " << /Type /Pages\r\n" );
+ aLine.append( " /Resources " );
+ aLine.append( nResourceDict );
+ aLine.append( " 0 R\r\n" );
+ switch( m_eInheritedOrientation )
+ {
+ case PDFWriter::Landscape: aLine.append( " /Rotate 90\r\n" );break;
+ case PDFWriter::Seascape: aLine.append( " /Rotate -90\r\n" );break;
+
+ case PDFWriter::Inherit: // actually Inherit would be a bug, but insignificant
+ case PDFWriter::Portrait:
+ default:
+ break;
+ }
+ aLine.append( " /MediaBox [ 0 0 " );
+ aLine.append( m_nInheritedPageWidth );
+ aLine.append( ' ' );
+ aLine.append( m_nInheritedPageHeight );
+ aLine.append( " ]\r\n /Kids [ " );
+ for( std::list<PDFPage>::const_iterator iter = m_aPages.begin(); iter != m_aPages.end(); ++iter )
+ {
+ aLine.append( iter->m_nPageObject );
+ aLine.append( " 0 R\r\n " );
+ }
+ aLine.append( "]\r\n /Count " );
+ aLine.append( (sal_Int32)m_aPages.size() );
+ aLine.append( "\r\n >>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ // emit Catalog
+ m_nCatalogObject = createObject();
+ if( ! updateObject( m_nCatalogObject ) )
+ return false;
+ aLine.setLength( 0 );
+ aLine.append( m_nCatalogObject );
+ aLine.append( " 0 obj\r\n << /Type /Catalog\r\n /Pages " );
+ aLine.append( nTreeNode );
+ aLine.append( " 0 R\r\n >>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ return true;
+}
+
+bool PDFWriterImpl::emitTrailer()
+{
+ // emit xref table
+
+ // remember start
+ sal_uInt64 nXRefOffset = 0;
+ CHECK_RETURN( osl_File_E_None == osl_getFilePos( m_aFile, &nXRefOffset ) );
+ nXRefOffset;
+ CHECK_RETURN( writeBuffer( "xref\r\n", 6 ) );
+
+ sal_Int32 nObjects = m_aObjects.size();
+ OStringBuffer aLine;
+ aLine.append( "0 " );
+ aLine.append( nObjects+1 );
+ aLine.append( "\r\n" );
+ aLine.append( "0000000000 65535 f\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ for( sal_Int32 i = 0; i < nObjects; i++ )
+ {
+ aLine.setLength( 0 );
+ OString aOffset = OString::valueOf( (sal_Int64)m_aObjects[i] );
+ for( sal_Int32 j = 0; j < (10-aOffset.getLength()); j++ )
+ aLine.append( '0' );
+ aLine.append( aOffset );
+ aLine.append( " 00000 n\r\n" );
+ DBG_ASSERT( aLine.getLength() == 20, "invalid xref entry" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
+ // emit trailer
+ aLine.setLength( 0 );
+ aLine.append( "trailer\r\n<< /Size " );
+ aLine.append( nObjects+1 );
+ aLine.append( "\r\n /Root " );
+ aLine.append( m_nCatalogObject );
+ aLine.append( " 0 R\r\n>>\r\nstartxref\r\n" );
+ aLine.append( (sal_Int64)nXRefOffset );
+ aLine.append( "\r\n%%EOF\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ return true;
+}
+
+bool PDFWriterImpl::emit()
+{
+ endPage();
+
+ // emit catalog
+ CHECK_RETURN( emitCatalog() );
+
+ // emit trailer
+ CHECK_RETURN( emitTrailer() );
+
+ osl_closeFile( m_aFile );
+ m_bOpen = false;
+
+ return true;
+}
+
+void PDFWriterImpl::drawText( const Point& rPos, const String& rText )
+{
+ MARK( "drawText" );
+
+ // just for testing purposes
+ ByteString aText( rText, RTL_TEXTENCODING_MS_1252 );
+
+ updateGraphicsState();
+
+ DBG_ASSERT( m_aCurrentPDFState.m_aFont.GetName().Len(), "invalid font set" );
+
+ OStringBuffer aLine;
+ aLine.append( "BT\r\n /F" );
+ aLine.append( m_aFonts[ m_aCurrentPDFState.m_aFont ] );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( m_aCurrentPDFState.m_aFont.GetHeight(), aLine, true );
+ aLine.append( " Tf\r\n " );
+ m_aPages.back().appendPoint( rPos, aLine );
+ aLine.append( " Td\r\n <" );
+ for( int i = 0; i < aText.Len(); i++ )
+ {
+ sal_Int8 aChar = rText.GetChar( i );
+ appendHex( aChar, aLine );
+ }
+ aLine.append( "> Tj\r\nET\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop )
+{
+ MARK( "drawLine" );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine;
+ m_aPages.back().appendPoint( rStart, aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( rStop, aLine );
+ aLine.append( " l S\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo )
+{
+ MARK( "drawLine with LineInfo" );
+
+ updateGraphicsState();
+
+#if 1
+ if( rInfo.GetStyle() == LINE_SOLID && rInfo.GetWidth() < 2 )
+ {
+ drawLine( rStart, rStop );
+ return;
+ }
+
+ OStringBuffer aLine;
+
+ aLine.append( "q " );
+ m_aPages.back().appendLineInfo( rInfo, aLine );
+ m_aPages.back().appendPoint( rStart, aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( rStop, aLine );
+ aLine.append( " l S Q\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+#else
+ Polygon aPoly( 2 ); aPoly[ 0 ] = rStart; aPoly[ 1 ] = rStop;
+ ImplLineConverter aLineCvt( aPoly, rInfo, NULL );
+
+ if( rInfo.GetWidth() > 1 )
+ {
+ Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor;
+ Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
+ setFillColor( m_aGraphicsStack.front().m_aLineColor );
+ setLineColor( Color( COL_TRANSPARENT ) );
+ for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() )
+ drawPolygon( *pPoly );
+ setLineColor( aOldLineColor );
+ setFillColor( aOldFillColor );
+ }
+ else
+ {
+ for( const Polygon* pPoly = aLineCvt.ImplGetFirst(); pPoly; pPoly = aLineCvt.ImplGetNext() )
+ drawLine( (*pPoly)[0], (*pPoly)[1] );
+ }
+#endif
+}
+
+void PDFWriterImpl::drawPolygon( const Polygon& rPoly )
+{
+ MARK( "drawPolygon" );
+
+ updateGraphicsState();
+
+ int nPoints = rPoly.GetSize();
+ OStringBuffer aLine( 20 * nPoints );
+ m_aPages.back().appendPolygon( rPoly, aLine );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "B*\r\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "S\r\n" );
+ else
+ aLine.append( "f*\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawPolyPolygon( const PolyPolygon& rPolyPoly )
+{
+ MARK( "drawPolyPolygon" );
+
+ updateGraphicsState();
+
+ int nPolygons = rPolyPoly.Count();
+
+ OStringBuffer aLine( 40 * nPolygons );
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "B*\r\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "S\r\n" );
+ else
+ aLine.append( "f*\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent )
+{
+ MARK( "drawTransparent" );
+
+ updateGraphicsState();
+
+ if( m_eVersion < PDFWriter::PDF_1_4 )
+ {
+ drawPolyPolygon( rPolyPoly );
+ return;
+ }
+ // TODO: build in transparency
+ drawPolyPolygon( rPolyPoly );
+}
+
+void PDFWriterImpl::drawRectangle( const Rectangle& rRect )
+{
+ MARK( "drawRectangle" );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine( 40 );
+ m_aPages.back().appendRect( rRect, aLine );
+
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( " B*\r\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( " S\r\n" );
+ else
+ aLine.append( " f*\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound )
+{
+ MARK( "drawRectangle with rounded edges" );
+
+ if( !nHorzRound && !nVertRound )
+ drawRectangle( rRect );
+
+ updateGraphicsState();
+
+ if( nHorzRound > rRect.GetWidth()/2 )
+ nHorzRound = rRect.GetWidth()/2;
+ if( nVertRound > rRect.GetWidth()/2 )
+ nVertRound = rRect.GetWidth()/2;
+
+ Point aPoints[16];
+ const double kappa = 0.5522847498;
+ const sal_uInt32 kx = (sal_uInt32)((kappa*(double)nHorzRound)+0.5);
+ const sal_uInt32 ky = (sal_uInt32)((kappa*(double)nVertRound)+0.5);
+
+ aPoints[1] = Point( rRect.TopLeft().X() + nHorzRound, rRect.TopLeft().Y() );
+ aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() );
+ aPoints[2] = Point( rRect.TopRight().X()+1 - nHorzRound, aPoints[1].Y() );
+ aPoints[3] = Point( aPoints[2].X()+kx, aPoints[2].Y() );
+
+ aPoints[5] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y()+nVertRound );
+ aPoints[4] = Point( aPoints[5].X(), aPoints[5].Y()-ky );
+ aPoints[6] = Point( aPoints[5].X(), rRect.BottomRight().Y()+1 - nVertRound );
+ aPoints[7] = Point( aPoints[6].X(), aPoints[6].Y()+ky );
+
+ aPoints[9] = Point( rRect.BottomRight().X()+1-nHorzRound, rRect.BottomRight().Y()+1 );
+ aPoints[8] = Point( aPoints[9].X()+kx, aPoints[9].Y() );
+ aPoints[10] = Point( rRect.BottomLeft().X() + nHorzRound, aPoints[9].Y() );
+ aPoints[11] = Point( aPoints[10].X()-kx, aPoints[10].Y() );
+
+ aPoints[13] = Point( rRect.BottomLeft().X(), rRect.BottomLeft().Y()+1-nVertRound );
+ aPoints[12] = Point( aPoints[13].X(), aPoints[13].Y()+ky );
+ aPoints[14] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y()+nVertRound );
+ aPoints[15] = Point( aPoints[14].X(), aPoints[14].Y()-ky );
+
+
+ OStringBuffer aLine( 80 );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( aPoints[2], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[3], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[4], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[5], aLine );
+ aLine.append( " c\r\n" );
+ m_aPages.back().appendPoint( aPoints[6], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[7], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[8], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[9], aLine );
+ aLine.append( " c\r\n" );
+ m_aPages.back().appendPoint( aPoints[10], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[11], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[12], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[13], aLine );
+ aLine.append( " c\r\n" );
+ m_aPages.back().appendPoint( aPoints[14], aLine );
+ aLine.append( " l " );
+ m_aPages.back().appendPoint( aPoints[15], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[0], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " c " );
+
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "b*\r\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "s\r\n" );
+ else
+ aLine.append( "f*\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawEllipse( const Rectangle& rRect )
+{
+ MARK( "drawEllipse" );
+
+ updateGraphicsState();
+
+ Point aPoints[12];
+ const double kappa = 0.5522847498;
+ const sal_uInt32 kx = (sal_uInt32)((kappa*(double)rRect.GetWidth()/2.0)+0.5);
+ const sal_uInt32 ky = (sal_uInt32)((kappa*(double)rRect.GetHeight()/2.0)+0.5);
+
+ aPoints[1] = Point( rRect.TopLeft().X() + rRect.GetWidth()/2, rRect.TopLeft().Y() );
+ aPoints[0] = Point( aPoints[1].X() - kx, aPoints[1].Y() );
+ aPoints[2] = Point( aPoints[1].X() + kx, aPoints[1].Y() );
+
+ aPoints[4] = Point( rRect.TopRight().X()+1, rRect.TopRight().Y() + rRect.GetHeight()/2 );
+ aPoints[3] = Point( aPoints[4].X(), aPoints[4].Y() - ky );
+ aPoints[5] = Point( aPoints[4].X(), aPoints[4].Y() + ky );
+
+ aPoints[7] = Point( rRect.BottomLeft().X() + rRect.GetWidth()/2, rRect.BottomLeft().Y()+1 );
+ aPoints[6] = Point( aPoints[7].X() + kx, aPoints[7].Y() );
+ aPoints[8] = Point( aPoints[7].X() - kx, aPoints[7].Y() );
+
+ aPoints[10] = Point( rRect.TopLeft().X(), rRect.TopLeft().Y() + rRect.GetHeight()/2 );
+ aPoints[9] = Point( aPoints[10].X(), aPoints[10].Y() + ky );
+ aPoints[11] = Point( aPoints[10].X(), aPoints[10].Y() - ky );
+
+ OStringBuffer aLine( 80 );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( aPoints[2], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[3], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[4], aLine );
+ aLine.append( " c\r\n" );
+ m_aPages.back().appendPoint( aPoints[5], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[6], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[7], aLine );
+ aLine.append( " c\r\n" );
+ m_aPages.back().appendPoint( aPoints[8], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[9], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[10], aLine );
+ aLine.append( " c\r\n" );
+ m_aPages.back().appendPoint( aPoints[11], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[0], aLine );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( aPoints[1], aLine );
+ aLine.append( " c " );
+
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "b*\r\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "s\r\n" );
+ else
+ aLine.append( "f*\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+static double calcAngle( const Rectangle& rRect, const Point& rPoint )
+{
+ Point aOrigin((rRect.TopLeft().X()+rRect.BottomRight().X()+1)/2,
+ (rRect.TopLeft().Y()+rRect.BottomRight().Y()+1)/2);
+ Point aPoint = rPoint - aOrigin;
+ aPoint.Y() = -aPoint.Y();
+ if( rRect.GetWidth() > rRect.GetHeight() )
+ aPoint.Y() = aPoint.Y()*rRect.GetWidth()/rRect.GetHeight();
+ else if( rRect.GetHeight() > rRect.GetWidth() )
+ aPoint.X() = aPoint.X()*rRect.GetHeight()/rRect.GetWidth();
+ return atan2( (double)aPoint.Y(), (double)aPoint.X() );
+}
+
+void PDFWriterImpl::drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWithChord )
+{
+ MARK( "drawArc" );
+
+ updateGraphicsState();
+
+ // calculate start and stop angles
+ double fStartAngle = calcAngle( rRect, rStart );
+ double fStopAngle = calcAngle( rRect, rStop );
+ while( fStopAngle < fStartAngle )
+ fStopAngle += 2.0*M_PI;
+ int nFragments = (int)((fStopAngle-fStartAngle)/(M_PI/2.0))+1;
+ double fFragmentDelta = (fStopAngle-fStartAngle)/(double)nFragments;
+ double kappa = fabs( 4.0 * (1.0-cos(fFragmentDelta/2.0))/sin(fFragmentDelta/2.0) / 3.0);
+ double halfWidth = (double)rRect.GetWidth()/2.0;
+ double halfHeight = (double)rRect.GetHeight()/2.0;
+
+ Point aCenter( (rRect.TopLeft().X()+rRect.BottomRight().X()+1)/2,
+ (rRect.TopLeft().Y()+rRect.BottomRight().Y()+1)/2 );
+
+ OStringBuffer aLine( 30*nFragments );
+ Point aPoint( (int)(halfWidth * cos(fStartAngle) ),
+ -(int)(halfHeight * sin(fStartAngle) ) );
+ aPoint += aCenter;
+ Point aStart = aPoint;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( " m " );
+ for( int i = 0; i < nFragments; i++ )
+ {
+ double fStartFragment = fStartAngle + (double)i*fFragmentDelta;
+ double fStopFragment = fStartFragment + fFragmentDelta;
+ aPoint = Point( (int)(halfWidth * (cos(fStartFragment) - kappa*sin(fStartFragment) ) ),
+ -(int)(halfHeight * (sin(fStartFragment) + kappa*cos(fStartFragment) ) ) );
+ aPoint += aCenter;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( ' ' );
+
+ aPoint = Point( (int)(halfWidth * (cos(fStopFragment) + kappa*sin(fStopFragment) ) ),
+ -(int)(halfHeight * (sin(fStopFragment) - kappa*cos(fStopFragment) ) ) );
+ aPoint += aCenter;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( ' ' );
+
+ aPoint = Point( (int)(halfWidth * cos(fStopFragment) ),
+ -(int)(halfHeight * sin(fStopFragment) ) );
+ aPoint += aCenter;
+ m_aPages.back().appendPoint( aPoint, aLine );
+ aLine.append( " c\r\n" );
+ }
+ if( bWithPie )
+ {
+ m_aPages.back().appendPoint( aCenter, aLine );
+ aLine.append( " l " );
+ }
+ if( ! bWithChord && ! bWithPie )
+ aLine.append( "S\r\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) &&
+ m_aGraphicsStack.front().m_aFillColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "b*\r\n" );
+ else if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "s\r\n" );
+ else
+ aLine.append( "f*\r\n" );
+
+#ifdef DEBUG_ARC
+ aLine.append( "0 1 1 RG " );
+ m_aPages.back().appendPoint( rStart, aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( aCenter, aLine );
+ aLine.append( " l S 1 0 0 RG " );
+ m_aPages.back().appendPoint( aCenter, aLine );
+ aLine.append( " m " );
+ m_aPages.back().appendPoint( rStop, aLine );
+ aLine.append( " l S\r\n" );
+ aLine.append( "0 0 0 RG " );
+ m_aPages.back().appendRect( rRect );
+ aLine.append( " S\r\n" );
+#endif
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawPolyLine( const Polygon& rPoly )
+{
+ MARK( "drawPolyLine" );
+
+ updateGraphicsState();
+
+ int nPoints = rPoly.GetSize();
+ OStringBuffer aLine( 20 * nPoints );
+ m_aPages.back().appendPolygon( rPoly, aLine, false );
+ aLine.append( "S\r\n" );
+
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo )
+{
+ MARK( "drawPolyLine with LineInfo" );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine;
+ aLine.append( "q " );
+ m_aPages.back().appendLineInfo( rInfo,aLine );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ drawPolyLine( rPoly );
+ writeBuffer( "Q\r\n", 3 );
+}
+
+void PDFWriterImpl::drawPixel( const Point& rPoint, const Color& rColor )
+{
+ MARK( "drawPixel" );
+
+ Color aColor = ( rColor == Color( COL_TRANSPARENT ) ? m_aGraphicsStack.front().m_aLineColor : rColor );
+
+ // pixels are drawn in line color, so have to set
+ // the nonstroking color to line color
+ Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
+ setFillColor( aColor );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine( 20 );
+ m_aPages.back().appendPoint( rPoint, aLine );
+ aLine.append( " 1 1 re f\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+
+ setFillColor( aOldFillColor );
+}
+
+void PDFWriterImpl::drawPixel( const Polygon& rPoints, const Color* pColors )
+{
+ MARK( "drawPixel with Polygon" );
+
+ updateGraphicsState();
+
+ int nPoints = rPoints.GetSize();
+ OStringBuffer aLine( nPoints*40 );
+ aLine.append( "q " );
+ if( ! pColors )
+ {
+ appendNonStrokingColor( m_aGraphicsStack.front().m_aLineColor, aLine );
+ aLine.append( ' ' );
+ }
+
+ for( int i = 0; i < nPoints; i++ )
+ {
+ if( pColors )
+ {
+ appendNonStrokingColor( pColors[i], aLine );
+ aLine.append( ' ' );
+ }
+ m_aPages.back().appendPoint( rPoints[i], aLine );
+ aLine.append( " 1 1 re f\r\n" );
+ }
+ aLine.append( "Q\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+class AccessReleaser
+{
+ BitmapReadAccess* m_pAccess;
+public:
+ AccessReleaser( BitmapReadAccess* pAccess ) : m_pAccess( pAccess ){}
+ ~AccessReleaser() { delete m_pAccess; }
+};
+
+bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
+{
+ sal_Int32 nFunctionObject = createObject();
+ CHECK_RETURN( updateObject( nFunctionObject ) );
+
+ OutputDevice* pRefDevice = getReferenceDevice();
+ if( rObject.m_aSize.Width() > pRefDevice->GetOutputSizePixel().Width() )
+ rObject.m_aSize.Width() = pRefDevice->GetOutputSizePixel().Width();
+ if( rObject.m_aSize.Height() > pRefDevice->GetOutputSizePixel().Height() )
+ rObject.m_aSize.Height() = pRefDevice->GetOutputSizePixel().Height();
+ pRefDevice->SetMapMode( MapMode( MAP_PIXEL ) );
+ pRefDevice->DrawGradient( Rectangle( Point( 0, 0 ), rObject.m_aSize ), rObject.m_aGradient );
+
+ Bitmap aSample = pRefDevice->GetBitmap( Point( 0, 0 ), rObject.m_aSize );
+ BitmapReadAccess* pAccess = aSample.AcquireReadAccess();
+ AccessReleaser aReleaser( pAccess );
+
+ Size aSize = aSample.GetSizePixel();
+
+ OStringBuffer aLine( 120 );
+ aLine.append( nFunctionObject );
+ aLine.append( " 0 obj\r\n << /FunctionType 0\r\n /Domain [ 0 1 0 1 ]\r\n" );
+ aLine.append( " /Size [ " );
+ aLine.append( (sal_Int32)aSize.Width() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aSize.Height() );
+ aLine.append( " ]\r\n /BitsPerSample 8\r\n /Range [ 0 1 0 1 0 1 ]\r\n" );
+ aLine.append( " /Length " );
+ aLine.append( (sal_Int32)(aSize.Width()*aSize.Height()*3) );
+ aLine.append( "\r\n >>\r\nstream\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ for( int y = 0; y < aSize.Height(); y++ )
+ {
+ for( int x = 0; x < aSize.Width(); x++ )
+ {
+ sal_uInt8 aCol[3];
+ BitmapColor aColor = pAccess->GetColor( y, x );
+ aCol[0] = aColor.GetRed();
+ aCol[1] = aColor.GetGreen();
+ aCol[2] = aColor.GetBlue();
+ CHECK_RETURN( writeBuffer( aCol, 3 ) );
+ }
+ }
+ aLine.setLength( 0 );
+ aLine.append( "\r\nendstream\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ CHECK_RETURN( updateObject( rObject.m_nObject ) );
+ aLine.setLength( 0 );
+ aLine.append( rObject.m_nObject );
+ aLine.append( " 0 obj\r\n << /ShadingType 1\r\n /ColorSpace /DeviceRGB\r\n" );
+ aLine.append( " /AntiAlias true\r\n /Domain [ 0 1 0 1 ]\r\n" );
+ aLine.append( " /Matrix [ " );
+ aLine.append( (sal_Int32)aSize.Width() );
+ aLine.append( " 0 0 " );
+ aLine.append( (sal_Int32)aSize.Height() );
+ aLine.append( " 0 0 ]\r\n /Function " );
+ aLine.append( nFunctionObject );
+ aLine.append( " 0 R\r\n >>\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+}
+
+bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask )
+{
+ CHECK_RETURN( updateObject( rObject.m_nObject ) );
+
+ Bitmap aBitmap = ( bMask ? rObject.m_aBitmap.GetMask() : rObject.m_aBitmap.GetBitmap() );
+ Color aTransparentColor( COL_TRANSPARENT );
+ bool bDrawMask = false;
+ if( ! bMask )
+ {
+ switch( rObject.m_aBitmap.GetTransparentType() )
+ {
+ case TRANSPARENT_NONE:
+ // comes from drawMask
+ if( aBitmap.GetBitCount() == 1 &&
+ rObject.m_aBitmap.GetTransparentColor() == Color(COL_BLACK) )
+ bMask = true;
+ break;
+ case TRANSPARENT_COLOR:
+ aTransparentColor = rObject.m_aBitmap.GetTransparentColor();
+ break;
+ case TRANSPARENT_BITMAP:
+ bDrawMask = true;
+ break;
+ }
+ }
+ else
+ {
+ if( aBitmap.GetBitCount() > 1 )
+ aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+ DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
+ }
+
+ BitmapReadAccess* pAccess = aBitmap.AcquireReadAccess();
+ AccessReleaser aReleaser( pAccess );
+
+ bool bTrueColor;
+ sal_Int32 nBitsPerComponent;
+ switch( aBitmap.GetBitCount() )
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ bTrueColor = false;
+ nBitsPerComponent = aBitmap.GetBitCount();
+ DBG_ASSERT( pAccess->GetScanlineSize() == pAccess->GetBitCount()*pAccess->Width()/8, "wrong scanline size" );
+ break;
+ default:
+ bTrueColor = true;
+ nBitsPerComponent = 8;
+ break;
+ }
+
+ sal_Int32 nStreamLengthObject = createObject();
+ sal_Int32 nMaskObject = 0;
+
+ OStringBuffer aLine(80);
+ aLine.append( rObject.m_nObject );
+ aLine.append( " 0 obj\r\n << /Type /XObject\r\n /Subtype /Image\r\n /Width " );
+ aLine.append( (sal_Int32)aBitmap.GetSizePixel().Width() );
+ aLine.append( "\r\n /Height " );
+ aLine.append( (sal_Int32)aBitmap.GetSizePixel().Height() );
+ aLine.append( "\r\n /BitsPerComponent " );
+ aLine.append( nBitsPerComponent );
+ aLine.append( "\r\n /Length " );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 R\r\n" );
+
+ if( ! bMask )
+ {
+ aLine.append( " /ColorSpace " );
+ if( bTrueColor )
+ aLine.append( "/DeviceRGB\r\n" );
+ else
+ {
+ aLine.append( "[ /Indexed /DeviceRGB " );
+ aLine.append( (sal_Int32)pAccess->GetPaletteEntryCount()-1 );
+ aLine.append( " <\r\n" );
+ for( int i = 0; i < pAccess->GetPaletteEntryCount(); i++ )
+ {
+ const BitmapColor& rColor = pAccess->GetPaletteColor( i );
+ appendHex( rColor.GetRed(), aLine );
+ appendHex( rColor.GetGreen(), aLine );
+ appendHex( rColor.GetBlue(), aLine );
+ if( (i+1) & 7 )
+ aLine.append( ' ' );
+ else
+ aLine.append( "\r\n" );
+ }
+ aLine.append( "> ]\r\n" );
+ }
+ }
+ else
+ {
+ aLine.append( " /ImageMask true\r\n" );
+ sal_Int32 nBlackIndex = pAccess->GetBestPaletteIndex( BitmapColor( Color( COL_BLACK ) ) );
+ DBG_ASSERT( nBlackIndex == 0 || nBlackIndex == 1, "wrong black index" );
+ if( nBlackIndex )
+ aLine.append( " /Decode [ 1 0 ]\r\n" );
+ else
+ aLine.append( " /Decode [ 0 1 ]\r\n" );
+ }
+
+ if( ! bMask && m_eVersion > PDFWriter::PDF_1_2 )
+ {
+ if( bDrawMask )
+ {
+ nMaskObject = createObject();
+ aLine.append( " /Mask " );
+ aLine.append( nMaskObject );
+ aLine.append( " 0 R\r\n" );
+ }
+ else if( aTransparentColor != Color( COL_TRANSPARENT ) )
+ {
+ aLine.append( " /Mask [ " );
+ if( bTrueColor )
+ {
+ aLine.append( (sal_Int32)aTransparentColor.GetRed() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetRed() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetGreen() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
+ aLine.append( ' ' );
+ aLine.append( (sal_Int32)aTransparentColor.GetBlue() );
+ }
+ else
+ {
+ sal_Int32 nIndex = pAccess->GetBestPaletteIndex( BitmapColor( aTransparentColor ) );
+ aLine.append( nIndex );
+ }
+ aLine.append( " ]\r\n" );
+ }
+ }
+ aLine.append( " >>\r\nstream\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ sal_uInt64 nStartPos = 0;
+ CHECK_RETURN( osl_File_E_None == osl_getFilePos( m_aFile, &nStartPos ) );
+
+ if( ! bTrueColor || pAccess->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB )
+ {
+ for( int i = 0; i < pAccess->Height(); i++ )
+ {
+ CHECK_RETURN( writeBuffer( pAccess->GetScanline( i ), pAccess->GetScanlineSize() ) );
+ }
+ }
+ else
+ {
+ const int nScanLineBytes = pAccess->Width()*3;
+ sal_uInt8 *pCol = (sal_uInt8*)rtl_allocateMemory( nScanLineBytes );
+ for( int y = 0; y < pAccess->Height(); y++ )
+ {
+ for( int x = 0; x < pAccess->Width(); x++ )
+ {
+ BitmapColor aColor = pAccess->GetColor( y, x );
+ pCol[3*x+0] = aColor.GetRed();
+ pCol[3*x+1] = aColor.GetGreen();
+ pCol[3*x+2] = aColor.GetBlue();
+ }
+ CHECK_RETURN( writeBuffer( pCol, nScanLineBytes ) );
+ }
+ rtl_freeMemory( pCol );
+ }
+
+ sal_uInt64 nEndPos = 0;
+ CHECK_RETURN( osl_File_E_None == osl_getFilePos( m_aFile, &nEndPos ) );
+ aLine.setLength( 0 );
+ aLine.append( "\r\nendstream\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ CHECK_RETURN( updateObject( nStreamLengthObject ) );
+ aLine.setLength( 0 );
+ aLine.append( nStreamLengthObject );
+ aLine.append( " 0 obj\r\n" );
+ aLine.append( (sal_Int64)(nEndPos-nStartPos) );
+ aLine.append( "\r\nendobj\r\n\r\n" );
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+
+ if( nMaskObject )
+ {
+ BitmapEmit aEmit;
+ aEmit.m_nObject = nMaskObject;
+ aEmit.m_aBitmap = rObject.m_aBitmap;
+ return writeBitmapObject( aEmit, true );
+ }
+
+ return true;
+}
+
+void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor )
+{
+ OStringBuffer aLine( 80 );
+ updateGraphicsState();
+
+ aLine.append( "q " );
+ if( rFillColor != Color( COL_TRANSPARENT ) )
+ {
+ appendNonStrokingColor( rFillColor, aLine );
+ aLine.append( ' ' );
+ }
+ m_aPages.back().appendMappedLength( rDestSize.Width(), aLine, false );
+ aLine.append( " 0 0 " );
+ m_aPages.back().appendMappedLength( rDestSize.Height(), aLine, true );
+ aLine.append( ' ' );
+ m_aPages.back().appendPoint( rDestPoint + Point( 0, rDestSize.Height()-1 ), aLine );
+ aLine.append( " cm\r\n /Im" );
+ aLine.append( rBitmap.m_nObject );
+ aLine.append( " Do Q\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap )
+{
+ MARK( "drawBitmap (Bitmap)" );
+
+ m_aBitmaps.push_back( BitmapEmit() );
+ m_aBitmaps.back().m_nObject = createObject();
+ m_aBitmaps.back().m_aBitmap = BitmapEx( rBitmap );
+
+ drawBitmap( rDestPoint, rDestSize, m_aBitmaps.back(), Color( COL_TRANSPARENT ) );
+}
+
+void PDFWriterImpl::drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap )
+{
+ MARK( "drawBitmap (BitmapEx)" );
+
+ m_aBitmaps.push_back( BitmapEmit() );
+ m_aBitmaps.back().m_nObject = createObject();
+ m_aBitmaps.back().m_aBitmap = rBitmap;
+ drawBitmap( rDestPoint, rDestSize, m_aBitmaps.back(), Color( COL_TRANSPARENT ) );
+}
+
+void PDFWriterImpl::drawMask( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Color& rFillColor )
+{
+ MARK( "drawMask" );
+
+ Bitmap aBitmap( rBitmap );
+ if( aBitmap.GetBitCount() > 1 )
+ aBitmap.Convert( BMP_CONVERSION_1BIT_THRESHOLD );
+ DBG_ASSERT( aBitmap.GetBitCount() == 1, "mask conversion failed" );
+
+ m_aBitmaps.push_back( BitmapEmit() );
+ m_aBitmaps.back().m_nObject = createObject();
+ m_aBitmaps.back().m_aBitmap = aBitmap;
+ m_aBitmaps.back().m_aBitmap.SetTransparentColor( Color( COL_BLACK ) );
+
+ drawBitmap( rDestPoint, rDestSize, m_aBitmaps.back(), rFillColor );
+}
+
+sal_Int32 PDFWriterImpl::createGradient( const Gradient& rGradient, const Size& rSize )
+{
+ Size aPtSize = OutputDevice::LogicToLogic( rSize, m_aGraphicsStack.front().m_aMapMode, MapMode( MAP_POINT ) );
+ // check if we already have this gradient
+ for( std::list<GradientEmit>::iterator it = m_aGradients.begin(); it != m_aGradients.end(); ++it )
+ {
+ if( it->m_aGradient == rGradient )
+ {
+ if( it->m_aSize.Width() < aPtSize.Width() )
+ it->m_aSize.Width() = aPtSize.Width();
+ if( it->m_aSize.Height() <= aPtSize.Height() )
+ it->m_aSize.Height() = aPtSize.Height();
+ return it->m_nObject;
+ }
+ }
+
+ m_aGradients.push_back( GradientEmit() );
+ m_aGradients.back().m_aGradient = rGradient;
+ m_aGradients.back().m_nObject = createObject();
+ m_aGradients.back().m_aSize = aPtSize;
+ return m_aGradients.back().m_nObject;
+}
+
+void PDFWriterImpl::drawGradient( const Rectangle& rRect, const Gradient& rGradient )
+{
+ MARK( "drawGradient (Rectangle)" );
+
+ if( m_eVersion == PDFWriter::PDF_1_2 )
+ {
+ drawRectangle( rRect );
+ return;
+ }
+
+ sal_Int32 nGradient = createGradient( rGradient, rRect.GetSize() );
+
+ Point aTranslate( rRect.BottomLeft() );
+ aTranslate += Point( 0, 1 );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine( 80 );
+ aLine.append( "q 1 0 0 1 " );
+ m_aPages.back().appendPoint( aTranslate, aLine );
+ aLine.append( " cm " );
+ // if a stroke is appended reset the clip region before stroke
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( "q " );
+ aLine.append( "0 0 " );
+ m_aPages.back().appendMappedLength( rRect.GetWidth(), aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( rRect.GetHeight(), aLine, true );
+ aLine.append( " re W n\r\n" );
+
+ aLine.append( "/P" );
+ aLine.append( nGradient );
+ aLine.append( " sh " );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ {
+ aLine.append( "Q 0 0 " );
+ m_aPages.back().appendMappedLength( rRect.GetWidth(), aLine, false );
+ aLine.append( ' ' );
+ m_aPages.back().appendMappedLength( rRect.GetHeight(), aLine, true );
+ aLine.append( " re S " );
+ }
+ aLine.append( "Q\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient )
+{
+ MARK( "drawGradient (PolyPolygon)" );
+
+ if( m_eVersion == PDFWriter::PDF_1_2 )
+ {
+ drawPolyPolygon( rPolyPoly );
+ return;
+ }
+
+ sal_Int32 nGradient = createGradient( rGradient, rPolyPoly.GetBoundRect().GetSize() );
+
+ updateGraphicsState();
+
+ Rectangle aBoundRect = rPolyPoly.GetBoundRect();
+ Point aTranslate = aBoundRect.BottomLeft() + Point( 0, 1 );
+ int nPolygons = rPolyPoly.Count();
+
+ OStringBuffer aLine( 80*nPolygons );
+ aLine.append( "q " );
+ // set PolyPolygon as clip path
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
+ aLine.append( "W* n\r\n" );
+ aLine.append( "1 0 0 1 " );
+ m_aPages.back().appendPoint( aTranslate, aLine );
+ aLine.append( " cm\r\n" );
+ aLine.append( "/P" );
+ aLine.append( nGradient );
+ aLine.append( " sh Q\r\n" );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ {
+ // and draw the surrounding path
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
+ aLine.append( "S\r\n" );
+ }
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+sal_Int32 PDFWriterImpl::createHatch( const Hatch& rHatch )
+{
+ // check if we already have this gradient
+ for( std::list<HatchEmit>::iterator it = m_aHatches.begin(); it != m_aHatches.end(); ++it )
+ {
+ if( it->m_aHatch == rHatch )
+ return it->m_nObject;
+ }
+
+ m_aHatches.push_back( HatchEmit() );
+ m_aHatches.back().m_aHatch = rHatch;
+ m_aHatches.back().m_nObject = createObject();
+ return m_aHatches.back().m_nObject;
+}
+
+void PDFWriterImpl::drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch )
+{
+ MARK( "drawHatch" );
+
+ sal_Int32 nHatch = createHatch( rHatch );
+
+ updateGraphicsState();
+
+ OStringBuffer aLine( 256 );
+ aLine.append( "q /Pattern cs /P" );
+ aLine.append( nHatch );
+ aLine.append( " scn\r\n" );
+ m_aPages.back().appendPolyPolygon( rPolyPoly, aLine );
+ if( m_aGraphicsStack.front().m_aLineColor != Color( COL_TRANSPARENT ) )
+ aLine.append( " B* " );
+ else
+ aLine.append( " f* " );
+ aLine.append( "Q\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
+
+void PDFWriterImpl::drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall )
+{
+ MARK( "drawWallpaper" );
+
+ bool bDrawColor = false;
+ bool bDrawGradient = false;
+ bool bDrawBitmap = false;
+
+ BitmapEx aBitmap;
+ Point aBmpPos = rRect.TopLeft();
+ Size aBmpSize;
+ if( rWall.IsBitmap() )
+ {
+ aBitmap = rWall.GetBitmap();
+ aBmpSize = OutputDevice::LogicToLogic( aBitmap.GetPrefSize(),
+ aBitmap.GetPrefMapMode(),
+ getMapMode() );
+ Rectangle aRect( rRect );
+ if( rWall.IsRect() )
+ {
+ aRect = rWall.GetRect();
+ aBmpPos = aRect.TopLeft();
+ aBmpSize = aRect.GetSize();
+ }
+ if( rWall.GetStyle() != WALLPAPER_SCALE )
+ {
+ if( rWall.GetStyle() != WALLPAPER_TILE )
+ {
+ bDrawBitmap = true;
+ if( rWall.IsGradient() )
+ bDrawGradient = true;
+ else
+ bDrawColor = true;
+ switch( rWall.GetStyle() )
+ {
+ case WALLPAPER_TOPLEFT:
+ break;
+ case WALLPAPER_TOP:
+ aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
+ break;
+ case WALLPAPER_LEFT:
+ aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
+ break;
+ case WALLPAPER_TOPRIGHT:
+ aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
+ break;
+ case WALLPAPER_CENTER:
+ aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
+ aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
+ break;
+ case WALLPAPER_RIGHT:
+ aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
+ aBmpPos.Y() += (aRect.GetHeight()-aBmpSize.Height())/2;
+ break;
+ case WALLPAPER_BOTTOMLEFT:
+ aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
+ break;
+ case WALLPAPER_BOTTOM:
+ aBmpPos.X() += (aRect.GetWidth()-aBmpSize.Width())/2;
+ aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
+ break;
+ case WALLPAPER_BOTTOMRIGHT:
+ aBmpPos.X() += aRect.GetWidth()-aBmpSize.Width();
+ aBmpPos.Y() += aRect.GetHeight()-aBmpSize.Height();
+ break;
+ }
+ }
+ else
+ {
+ // push the bitmap
+ m_aBitmaps.push_back( BitmapEmit() );
+ m_aBitmaps.back().m_nObject = createObject();
+ m_aBitmaps.back().m_aBitmap = aBitmap;
+
+ // convert to internal mapmode (10th point)
+ Rectangle aConvertRect = OutputDevice::LogicToLogic( Rectangle( aBmpPos, aBmpSize ),
+ getMapMode(),
+ m_aMapMode );
+ // convert to page coordinates; this needs to be done here
+ // since the emit does not know the page anymore
+ sal_Int32 nMirror = m_aPages.back().m_nPageHeight ? m_aPages.back().m_nPageHeight : m_nInheritedPageHeight;
+ aConvertRect = Rectangle( Point( aConvertRect.BottomLeft().X(), 10*nMirror-aConvertRect.BottomLeft().Y() ),
+ aConvertRect.GetSize() );
+
+ // push the pattern
+ m_aTilings.push_back( BitmapPatternEmit() );
+ m_aTilings.back().m_nObject = createObject();
+ m_aTilings.back().m_nBitmapObject = m_aBitmaps.back().m_nObject;
+ m_aTilings.back().m_aRectangle = aConvertRect;
+
+ updateGraphicsState();
+
+ // fill a rRect with the pattern
+ OStringBuffer aLine( 100 );
+ aLine.append( "q /Pattern cs /P" );
+ aLine.append( m_aTilings.back().m_nObject );
+ aLine.append( " scn " );
+ m_aPages.back().appendRect( rRect, aLine );
+ aLine.append( " f Q\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ }
+ }
+ else
+ {
+ aBmpPos = aRect.TopLeft();
+ aBmpSize = aRect.GetSize();
+ bDrawBitmap = true;
+ }
+
+ if( aBitmap.IsTransparent() )
+ {
+ if( rWall.IsGradient() )
+ bDrawGradient = true;
+ else
+ bDrawColor = true;
+ }
+ }
+ else if( rWall.IsGradient() )
+ bDrawGradient = true;
+ else
+ bDrawColor = true;
+
+ if( bDrawGradient )
+ {
+ drawGradient( rRect, rWall.GetGradient() );
+ }
+ if( bDrawColor )
+ {
+ Color aOldLineColor = m_aGraphicsStack.front().m_aLineColor;
+ Color aOldFillColor = m_aGraphicsStack.front().m_aFillColor;
+ setLineColor( Color( COL_TRANSPARENT ) );
+ setFillColor( rWall.GetColor() );
+ drawRectangle( rRect );
+ setLineColor( aOldLineColor );
+ setFillColor( aOldFillColor );
+ }
+ if( bDrawBitmap )
+ {
+ // set temporary clip region since aBmpPos and aBmpSize
+ // may be outside rRect
+ OStringBuffer aLine( 20 );
+ aLine.append( "q " );
+ m_aPages.back().appendRect( rRect, aLine );
+ aLine.append( " W n\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ drawBitmap( aBmpPos, aBmpSize, aBitmap );
+ writeBuffer( "Q\r\n", 3 );
+ }
+}
+
+void PDFWriterImpl::updateGraphicsState()
+{
+ OStringBuffer aLine( 256 );
+ GraphicsState& rNewState = m_aGraphicsStack.front();
+ // first set clip region since it might invalidate everything else
+ Region& rNewClip = rNewState.m_aClipRegion;
+ if( m_aCurrentPDFState.m_aClipRegion != rNewClip )
+ {
+ if( ! m_aCurrentPDFState.m_aClipRegion.IsEmpty() &&
+ ! m_aCurrentPDFState.m_aClipRegion.IsNull() )
+ {
+ aLine.append( "Q " );
+ // invalidate everything
+ m_aCurrentPDFState = GraphicsState();
+ }
+ if( ! rNewClip.IsEmpty() && ! rNewClip.IsNull() )
+ {
+ aLine.append( "q " );
+ if( rNewClip.HasPolyPolygon() )
+ {
+ m_aPages.back().appendPolyPolygon( rNewClip.GetPolyPolygon(), aLine );
+ aLine.append( "W* n\r\n" );
+ }
+ else
+ {
+ // need to clip all rectangles
+ RegionHandle aHandle = rNewClip.BeginEnumRects();
+ Rectangle aRect;
+ while( rNewClip.GetNextEnumRect( aHandle, aRect ) )
+ {
+ m_aPages.back().appendRect( aRect, aLine );
+ if( aLine.getLength() > 80 )
+ {
+ aLine.append( "\r\n" );
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+ aLine.setLength( 0 );
+ }
+ else
+ aLine.append( ' ' );
+ }
+ rNewClip.EndEnumRects( aHandle );
+ aLine.append( "W* n\r\n" );
+ }
+ }
+ }
+
+ if( m_aCurrentPDFState.m_aLineColor != rNewState.m_aLineColor &&
+ rNewState.m_aLineColor != Color( COL_TRANSPARENT ) )
+ {
+ appendStrokingColor( rNewState.m_aLineColor, aLine );
+ aLine.append( "\r\n" );
+ }
+
+ if( m_aCurrentPDFState.m_aFillColor != rNewState.m_aFillColor &&
+ rNewState.m_aFillColor != Color( COL_TRANSPARENT ) )
+ {
+ appendNonStrokingColor( rNewState.m_aFillColor, aLine );
+ aLine.append( "\r\n" );
+ }
+
+ if( m_aCurrentPDFState.m_aFont != rNewState.m_aFont && rNewState.m_aFont.GetName().Len()
+ )
+ {
+ if( m_aFonts.find( rNewState.m_aFont ) == m_aFonts.end() )
+ m_aFonts[ rNewState.m_aFont ] = m_nNextFID++;
+ }
+
+ if( m_eVersion >= PDFWriter::PDF_1_4 && m_aCurrentPDFState.m_nTransparentPercent != rNewState.m_nTransparentPercent )
+ {
+ // TODO: switch extended graphicsstate
+ }
+
+ // everything is up to date now
+ m_aCurrentPDFState = m_aGraphicsStack.front();
+ if( aLine.getLength() )
+ writeBuffer( aLine.getStr(), aLine.getLength() );
+}
diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx
new file mode 100644
index 000000000000..53826811b31e
--- /dev/null
+++ b/vcl/source/gdi/pdfwriter_impl.hxx
@@ -0,0 +1,435 @@
+/*************************************************************************
+ *
+ * $RCSfile: pdfwriter_impl.hxx,v $
+ *
+ * $Revision: 1.1 $
+ *
+ * last change: $Author: pl $ $Date: 2002-07-08 14:18:57 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (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.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+#ifndef _VCL_PDFWRITER_IMPL_HXX
+#define _VCL_PDFWRITER_IMPL_HXX
+
+#ifndef _VCL_PDFWRITER_HXX
+#include <pdfwriter.hxx>
+#endif
+
+#ifndef _RTL_USTRING_HXX
+#include <rtl/ustring.hxx>
+#endif
+#ifndef _OSL_FILE_H
+#include <osl/file.h>
+#endif
+#ifndef _GEN_HXX
+#include <tools/gen.hxx>
+#endif
+#ifndef _SV_OUTDEV_HXX
+#include <outdev.hxx>
+#endif
+#ifndef _SV_BITMAPEX_HXX
+#include <bitmapex.hxx>
+#endif
+#ifndef _SV_GRADIENT_HXX
+#include <gradient.hxx>
+#endif
+#ifndef _SV_HATCH_HXX
+#include <hatch.hxx>
+#endif
+#ifndef _SV_WALL_HXX
+#include <wall.hxx>
+#endif
+#ifndef _SV_OUTDATA_HXX
+#include <outdata.hxx>
+#endif
+
+#include <vector>
+#include <map>
+#include <list>
+
+namespace rtl { class OStringBuffer; }
+
+namespace vcl
+{
+
+class PDFWriterImpl
+{
+private:
+ struct PDFPage
+ {
+ PDFWriterImpl* m_pWriter;
+ sal_Int32 m_nPageWidth; // in inch/72
+ sal_Int32 m_nPageHeight; // in inch/72
+ PDFWriter::Orientation m_eOrientation;
+ sal_Int32 m_nPageObject;
+ sal_Int32 m_nStreamObject;
+ sal_Int32 m_nStreamLengthObject;
+ sal_uInt64 m_nBeginStreamPos;
+
+ PDFPage( PDFWriterImpl* pWriter, sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation );
+ ~PDFPage();
+
+ void beginStream();
+ void endStream();
+ bool emit( sal_Int32 nParentPage );
+
+ // converts point from ref device coordinates to
+ // page coordinates and appends the point to the buffer
+ // if bNeg is true, the coordinates are inverted AFTER transformation
+ // to page (useful for transformation matrices
+ void appendPoint( const Point& rPoint, rtl::OStringBuffer& rBuffer, bool bNeg = false );
+ // appends a rectangle
+ void appendRect( const Rectangle& rRect, rtl::OStringBuffer& rBuffer );
+ // appends a polygon optionally closing it
+ void appendPolygon( const Polygon& rPoly, rtl::OStringBuffer& rBuffer, bool bClose = true );
+ // appends a polypolygon optionally closing the subpaths
+ void appendPolyPolygon( const PolyPolygon& rPolyPoly, rtl::OStringBuffer& rBuffer, bool bClose = true );
+ // converts a length (either vertical or horizontal; this
+ // can be important if the source MapMode is not
+ // symmetrical) to page length and appends it to the buffer
+ void appendMappedLength( sal_Int32 nLength, rtl::OStringBuffer& rBuffer, bool bVertical = true );
+ // appends LineInfo
+ void appendLineInfo( const LineInfo& rInfo, rtl::OStringBuffer& rBuffer );
+ };
+
+ friend struct PDFPage;
+
+ struct BitmapEmit
+ {
+ BitmapEx m_aBitmap;
+ sal_Int32 m_nObject;
+ };
+
+ struct GradientEmit
+ {
+ Gradient m_aGradient;
+ Size m_aSize;
+ sal_Int32 m_nObject;
+ };
+
+ struct HatchEmit
+ {
+ Hatch m_aHatch;
+ sal_Int32 m_nObject;
+ };
+
+ // for bitmap tilings (drawWallpaper)
+ struct BitmapPatternEmit
+ {
+ sal_Int32 m_nObject;
+ sal_Int32 m_nBitmapObject;
+ Rectangle m_aRectangle;
+ };
+
+ OutputDevice* m_pReferenceDevice;
+
+ MapMode m_aMapMode; // PDFWriterImpl scaled units
+ std::list< PDFPage > m_aPages;
+ /* maps object numbers to file offsets (needed for xref) */
+ std::vector< sal_uInt64 > m_aObjects;
+ /* contains Bitmaps until they are written to the
+ * file stream as XObjects*/
+ std::list< BitmapEmit > m_aBitmaps;
+ /* contains Bitmaps for gradient functions until they are written
+ * to the file stream */
+ std::list< GradientEmit > m_aGradients;
+ /* contains hatches to be emitted for the whole document
+ */
+ std::list< HatchEmit > m_aHatches;
+ /* contains bitmap tiling patterns */
+ std::list< BitmapPatternEmit > m_aTilings;
+
+ sal_Int32 m_nInheritedPageWidth; // in inch/72
+ sal_Int32 m_nInheritedPageHeight; // in inch/72
+ PDFWriter::Orientation m_eInheritedOrientation;
+ sal_Int32 m_nCurrentPage;
+
+ sal_Int32 m_nCatalogObject;
+
+ PDFWriter::PDFVersion m_eVersion;
+ rtl::OUString m_aFileName;
+ oslFileHandle m_aFile;
+ bool m_bOpen;
+
+ struct ltfont
+ {
+ bool operator()(const Font& rLeft, const Font& rRight)
+ {
+ StringCompare eComp = rLeft.GetName().CompareTo( rRight.GetName() );
+ if( eComp != COMPARE_EQUAL )
+ return eComp == COMPARE_LESS;
+ if( rLeft.GetItalic() != rRight.GetItalic() )
+ return rLeft.GetItalic() < rRight.GetItalic();
+ if( rLeft.GetWeight() != rRight.GetWeight() )
+ return rLeft.GetWeight() < rRight.GetWeight();
+ return rLeft.GetWidth() < rRight.GetWidth();
+ }
+ };
+
+ // fonts used in whole file, maps to font id
+ std::map< Font, sal_Int32, ltfont > m_aFonts;
+ sal_Int32 m_nNextFID;
+
+
+ // graphics state
+ struct GraphicsState
+ {
+ Font m_aFont;
+ MapMode m_aMapMode;
+ Color m_aLineColor;
+ Color m_aFillColor;
+ Color m_aTextLineColor;
+ Region m_aClipRegion;
+ sal_Int32 m_nAntiAlias;
+ sal_Int32 m_nLayoutMode;
+ TextAlign m_eTextAlign;
+ sal_Int32 m_nTransparentPercent;
+
+ GraphicsState() :
+ m_aLineColor( COL_TRANSPARENT ),
+ m_aFillColor( COL_TRANSPARENT ),
+ m_aTextLineColor( COL_BLACK ),
+ m_nTransparentPercent( 0 ) {}
+ GraphicsState( const GraphicsState& rState ) :
+ m_aFont( rState.m_aFont ),
+ m_aMapMode( rState.m_aMapMode ),
+ m_aLineColor( rState.m_aLineColor ),
+ m_aFillColor( rState.m_aFillColor ),
+ m_aTextLineColor( rState.m_aTextLineColor ),
+ m_aClipRegion( rState.m_aClipRegion ),
+ m_nAntiAlias( rState.m_nAntiAlias ),
+ m_nLayoutMode( rState.m_nLayoutMode ),
+ m_eTextAlign( rState.m_eTextAlign ),
+ m_nTransparentPercent( rState.m_nTransparentPercent )
+ {
+ }
+
+ GraphicsState& operator=(const GraphicsState& rState )
+ {
+ m_aFont = rState.m_aFont;
+ m_aMapMode = rState.m_aMapMode;
+ m_aLineColor = rState.m_aLineColor;
+ m_aFillColor = rState.m_aFillColor;
+ m_aTextLineColor = rState.m_aTextLineColor;
+ m_aClipRegion = rState.m_aClipRegion;
+ m_nAntiAlias = rState.m_nAntiAlias;
+ m_nLayoutMode = rState.m_nLayoutMode;
+ m_eTextAlign = rState.m_eTextAlign;
+ m_nTransparentPercent = rState.m_nTransparentPercent;
+ return *this;
+ }
+ };
+ std::list< GraphicsState > m_aGraphicsStack;
+ GraphicsState m_aCurrentPDFState;
+
+ /* writes differences between graphics stack and current real PDF
+ * state to the file
+ */
+ void updateGraphicsState();
+
+ /* writes an XObject of type image, may create
+ a second for the mask
+ */
+ bool writeBitmapObject( BitmapEmit& rObject, bool bMask = false );
+ /* writes the Do operation inside the content stream */
+ void drawBitmap( const Point& rDestPt, const Size& rDestSize, const BitmapEmit& rBitmap, const Color& rFillColor );
+ /* write the function object for a Gradient */
+ bool writeGradientFunction( GradientEmit& rObject );
+ /* creates a GradientEmit and returns its object number */
+ sal_Int32 createGradient( const Gradient& rGradient, const Size& rSize );
+ /* creates a HatchEmit and returns its object number */
+ sal_Int32 createHatch( const Hatch& rHatch );
+
+ /* writes all tilings */
+ bool emitTilings();
+ /* writes all gradient patterns */
+ bool emitGradients();
+ /* writes all hatch patterns */
+ bool emitHatches();
+ /* writes a font dictionary;
+ * returns object id (or 0 on error)
+ */
+ sal_Int32 emitFont( const Font& rFont );
+ /* writes the Resource dictionary;
+ * returns dict object id (or 0 on error)
+ */
+ sal_Int32 emitResources();
+ // writes page tree and catalog
+ bool emitCatalog();
+ // writes xref and trailer
+ bool emitTrailer();
+
+ /* adds an entry to m_aObjects and returns its index+1,
+ * sets the offset to ~0
+ */
+ sal_Int32 createObject();
+ /* sets the offset of object n to the current position of output file+1
+ */
+ bool updateObject( sal_Int32 n );
+
+ bool writeBuffer( const void* pBuffer, sal_uInt64 nBytes );
+ void endPage();
+public:
+ PDFWriterImpl( const rtl::OUString& rTargetFile, PDFWriter::PDFVersion eVersion = PDFWriter::PDF_1_4 );
+ ~PDFWriterImpl();
+
+ /* for documentation of public fucntions please see pdfwriter.hxx */
+
+ OutputDevice* getReferenceDevice();
+
+ /* document structure */
+ sal_Int32 newPage( sal_Int32 nPageWidth , sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation );
+ bool emit();
+
+ PDFWriter::PDFVersion getVersion() const { return m_eVersion; }
+
+ /* graphics state */
+ void push()
+ { m_aGraphicsStack.push_front( m_aGraphicsStack.front() ); }
+
+ void pop()
+ { m_aGraphicsStack.pop_front(); }
+
+ void setFont( const Font& rFont )
+ { m_aGraphicsStack.front().m_aFont = rFont; }
+
+ void setMapMode() { m_aGraphicsStack.front().m_aMapMode = m_aMapMode; }
+
+ void setMapMode( const MapMode& rMapMode )
+ { m_aGraphicsStack.front().m_aMapMode = rMapMode; }
+
+ const MapMode& getMapMode() { return m_aGraphicsStack.front().m_aMapMode; }
+
+ void setLineColor( const Color& rColor )
+ { m_aGraphicsStack.front().m_aLineColor = rColor; }
+
+ void setFillColor( const Color& rColor )
+ { m_aGraphicsStack.front().m_aFillColor = rColor; }
+
+ void setTextLineColor()
+ { m_aGraphicsStack.front().m_aTextLineColor = Color( COL_TRANSPARENT ); }
+
+ void setTextLineColor( const Color& rColor )
+ { m_aGraphicsStack.front().m_aTextLineColor = rColor; }
+
+ void setTextFillColor( const Color& rColor )
+ {
+ m_aGraphicsStack.front().m_aFont.SetFillColor( rColor );
+ m_aGraphicsStack.front().m_aFont.SetTransparent( ImplIsColorTransparent( rColor ) );
+ }
+ void setTextFillColor()
+ {
+ m_aGraphicsStack.front().m_aFont.SetFillColor( Color( COL_TRANSPARENT ) );
+ m_aGraphicsStack.front().m_aFont.SetTransparent( TRUE );
+ }
+ void setTextColor( const Color& rColor )
+ { m_aGraphicsStack.front().m_aFont.SetColor( rColor ); }
+
+ void clearClipRegion()
+ { m_aGraphicsStack.front().m_aClipRegion.SetEmpty(); }
+
+ void setClipRegion( const Region& rRegion )
+ { m_aGraphicsStack.front().m_aClipRegion = rRegion; }
+
+ void moveClipRegion( sal_Int32 nX, sal_Int32 nY )
+ { m_aGraphicsStack.front().m_aClipRegion.Move( nX, nY ); }
+
+ bool intersectClipRegion( const Rectangle& rRect )
+ { return m_aGraphicsStack.front().m_aClipRegion.Intersect( rRect ); }
+
+ bool intersectClipRegion( const Region& rRegion )
+ { return m_aGraphicsStack.front().m_aClipRegion.Intersect( rRegion ); }
+
+ void setLayoutMode( sal_Int32 nLayoutMode )
+ { m_aGraphicsStack.front().m_nLayoutMode = nLayoutMode; }
+
+ void setTextAlign( TextAlign eAlign )
+ { m_aGraphicsStack.front().m_eTextAlign = eAlign; }
+
+ void setAntiAlias( sal_Int32 nAntiAlias )
+ { m_aGraphicsStack.front().m_nAntiAlias = nAntiAlias; }
+
+ /* actual drawing functions */
+ void drawText( const Point& rPos, const String& rText );
+
+ void drawLine( const Point& rStart, const Point& rStop );
+ void drawLine( const Point& rStart, const Point& rStop, const LineInfo& rInfo );
+ void drawPolygon( const Polygon& rPoly );
+ void drawPolyPolygon( const PolyPolygon& rPolyPoly );
+ void drawPolyLine( const Polygon& rPoly );
+ void drawPolyLine( const Polygon& rPoly, const LineInfo& rInfo );
+
+ void drawPixel( const Point& rPt, const Color& rColor );
+ void drawPixel( const Polygon& rPts, const Color* pColors = NULL );
+
+ void drawRectangle( const Rectangle& rRect );
+ void drawRectangle( const Rectangle& rRect, sal_uInt32 nHorzRound, sal_uInt32 nVertRound );
+ void drawEllipse( const Rectangle& rRect );
+ void drawArc( const Rectangle& rRect, const Point& rStart, const Point& rStop, bool bWithPie, bool bWidthChord );
+
+ void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap );
+ void drawBitmap( const Point& rDestPoint, const Size& rDestSize, const BitmapEx& rBitmap );
+ void drawMask( const Point& rDestPoint, const Size& rDestSize, const Bitmap& rBitmap, const Color& rFillColor );
+ void drawGradient( const Rectangle& rRect, const Gradient& rGradient );
+ void drawGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient );
+ void drawHatch( const PolyPolygon& rPolyPoly, const Hatch& rHatch );
+ void drawWallpaper( const Rectangle& rRect, const Wallpaper& rWall );
+ void drawTransparent( const PolyPolygon& rPolyPoly, sal_uInt32 nTransparentPercent );
+
+
+ void emitComment( const rtl::OString& rComment );
+};
+
+}
+
+#endif //_VCL_PDFEXPORT_HXX