1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir #include "precompiled_vcl.hxx" 29*cdf0e10cSrcweir 30*cdf0e10cSrcweir #include "pdfwriter_impl.hxx" 31*cdf0e10cSrcweir 32*cdf0e10cSrcweir #include "vcl/pdfextoutdevdata.hxx" 33*cdf0e10cSrcweir #include "vcl/virdev.hxx" 34*cdf0e10cSrcweir #include "vcl/gdimtf.hxx" 35*cdf0e10cSrcweir #include "vcl/metaact.hxx" 36*cdf0e10cSrcweir #include "vcl/bmpacc.hxx" 37*cdf0e10cSrcweir #include "vcl/graph.hxx" 38*cdf0e10cSrcweir #include "vcl/rendergraphicrasterizer.hxx" 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir #include "svdata.hxx" 41*cdf0e10cSrcweir 42*cdf0e10cSrcweir #include "unotools/streamwrap.hxx" 43*cdf0e10cSrcweir #include "unotools/processfactory.hxx" 44*cdf0e10cSrcweir 45*cdf0e10cSrcweir #include "comphelper/processfactory.hxx" 46*cdf0e10cSrcweir 47*cdf0e10cSrcweir #include "com/sun/star/beans/PropertyValue.hpp" 48*cdf0e10cSrcweir #include "com/sun/star/io/XSeekable.hpp" 49*cdf0e10cSrcweir #include "com/sun/star/graphic/XGraphicProvider.hpp" 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir #include "cppuhelper/implbase1.hxx" 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir #include <rtl/digest.h> 54*cdf0e10cSrcweir 55*cdf0e10cSrcweir #undef USE_PDFGRADIENTS 56*cdf0e10cSrcweir 57*cdf0e10cSrcweir using namespace vcl; 58*cdf0e10cSrcweir using namespace rtl; 59*cdf0e10cSrcweir using namespace com::sun::star; 60*cdf0e10cSrcweir using namespace com::sun::star::uno; 61*cdf0e10cSrcweir using namespace com::sun::star::beans; 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir void PDFWriterImpl::implWriteGradient( const PolyPolygon& i_rPolyPoly, const Gradient& i_rGradient, 66*cdf0e10cSrcweir VirtualDevice* i_pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& i_rContext ) 67*cdf0e10cSrcweir { 68*cdf0e10cSrcweir GDIMetaFile aTmpMtf; 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir i_pDummyVDev->AddGradientActions( i_rPolyPoly.GetBoundRect(), i_rGradient, aTmpMtf ); 71*cdf0e10cSrcweir 72*cdf0e10cSrcweir m_rOuterFace.Push(); 73*cdf0e10cSrcweir m_rOuterFace.IntersectClipRegion( i_rPolyPoly.getB2DPolyPolygon() ); 74*cdf0e10cSrcweir playMetafile( aTmpMtf, NULL, i_rContext, i_pDummyVDev ); 75*cdf0e10cSrcweir m_rOuterFace.Pop(); 76*cdf0e10cSrcweir } 77*cdf0e10cSrcweir 78*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 79*cdf0e10cSrcweir 80*cdf0e10cSrcweir void PDFWriterImpl::implWriteBitmapEx( const Point& i_rPoint, const Size& i_rSize, const BitmapEx& i_rBitmapEx, 81*cdf0e10cSrcweir VirtualDevice* i_pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& i_rContext ) 82*cdf0e10cSrcweir { 83*cdf0e10cSrcweir if ( !i_rBitmapEx.IsEmpty() && i_rSize.Width() && i_rSize.Height() ) 84*cdf0e10cSrcweir { 85*cdf0e10cSrcweir BitmapEx aBitmapEx( i_rBitmapEx ); 86*cdf0e10cSrcweir Point aPoint( i_rPoint ); 87*cdf0e10cSrcweir Size aSize( i_rSize ); 88*cdf0e10cSrcweir 89*cdf0e10cSrcweir // #i19065# Negative sizes have mirror semantics on 90*cdf0e10cSrcweir // OutputDevice. BitmapEx and co. have no idea about that, so 91*cdf0e10cSrcweir // perform that _before_ doing anything with aBitmapEx. 92*cdf0e10cSrcweir sal_uLong nMirrorFlags(BMP_MIRROR_NONE); 93*cdf0e10cSrcweir if( aSize.Width() < 0 ) 94*cdf0e10cSrcweir { 95*cdf0e10cSrcweir aSize.Width() *= -1; 96*cdf0e10cSrcweir aPoint.X() -= aSize.Width(); 97*cdf0e10cSrcweir nMirrorFlags |= BMP_MIRROR_HORZ; 98*cdf0e10cSrcweir } 99*cdf0e10cSrcweir if( aSize.Height() < 0 ) 100*cdf0e10cSrcweir { 101*cdf0e10cSrcweir aSize.Height() *= -1; 102*cdf0e10cSrcweir aPoint.Y() -= aSize.Height(); 103*cdf0e10cSrcweir nMirrorFlags |= BMP_MIRROR_VERT; 104*cdf0e10cSrcweir } 105*cdf0e10cSrcweir 106*cdf0e10cSrcweir if( nMirrorFlags != BMP_MIRROR_NONE ) 107*cdf0e10cSrcweir { 108*cdf0e10cSrcweir aBitmapEx.Mirror( nMirrorFlags ); 109*cdf0e10cSrcweir } 110*cdf0e10cSrcweir if( i_rContext.m_nMaxImageResolution > 50 ) 111*cdf0e10cSrcweir { 112*cdf0e10cSrcweir // do downsampling if neccessary 113*cdf0e10cSrcweir const Size aDstSizeTwip( i_pDummyVDev->PixelToLogic( i_pDummyVDev->LogicToPixel( aSize ), MAP_TWIP ) ); 114*cdf0e10cSrcweir const Size aBmpSize( aBitmapEx.GetSizePixel() ); 115*cdf0e10cSrcweir const double fBmpPixelX = aBmpSize.Width(); 116*cdf0e10cSrcweir const double fBmpPixelY = aBmpSize.Height(); 117*cdf0e10cSrcweir const double fMaxPixelX = aDstSizeTwip.Width() * i_rContext.m_nMaxImageResolution / 1440.0; 118*cdf0e10cSrcweir const double fMaxPixelY = aDstSizeTwip.Height() * i_rContext.m_nMaxImageResolution / 1440.0; 119*cdf0e10cSrcweir 120*cdf0e10cSrcweir // check, if the bitmap DPI exceeds the maximum DPI (allow 4 pixel rounding tolerance) 121*cdf0e10cSrcweir if( ( ( fBmpPixelX > ( fMaxPixelX + 4 ) ) || 122*cdf0e10cSrcweir ( fBmpPixelY > ( fMaxPixelY + 4 ) ) ) && 123*cdf0e10cSrcweir ( fBmpPixelY > 0.0 ) && ( fMaxPixelY > 0.0 ) ) 124*cdf0e10cSrcweir { 125*cdf0e10cSrcweir // do scaling 126*cdf0e10cSrcweir Size aNewBmpSize; 127*cdf0e10cSrcweir const double fBmpWH = fBmpPixelX / fBmpPixelY; 128*cdf0e10cSrcweir const double fMaxWH = fMaxPixelX / fMaxPixelY; 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir if( fBmpWH < fMaxWH ) 131*cdf0e10cSrcweir { 132*cdf0e10cSrcweir aNewBmpSize.Width() = FRound( fMaxPixelY * fBmpWH ); 133*cdf0e10cSrcweir aNewBmpSize.Height() = FRound( fMaxPixelY ); 134*cdf0e10cSrcweir } 135*cdf0e10cSrcweir else if( fBmpWH > 0.0 ) 136*cdf0e10cSrcweir { 137*cdf0e10cSrcweir aNewBmpSize.Width() = FRound( fMaxPixelX ); 138*cdf0e10cSrcweir aNewBmpSize.Height() = FRound( fMaxPixelX / fBmpWH); 139*cdf0e10cSrcweir } 140*cdf0e10cSrcweir if( aNewBmpSize.Width() && aNewBmpSize.Height() ) 141*cdf0e10cSrcweir aBitmapEx.Scale( aNewBmpSize ); 142*cdf0e10cSrcweir else 143*cdf0e10cSrcweir aBitmapEx.SetEmpty(); 144*cdf0e10cSrcweir } 145*cdf0e10cSrcweir } 146*cdf0e10cSrcweir 147*cdf0e10cSrcweir const Size aSizePixel( aBitmapEx.GetSizePixel() ); 148*cdf0e10cSrcweir if ( aSizePixel.Width() && aSizePixel.Height() ) 149*cdf0e10cSrcweir { 150*cdf0e10cSrcweir if( m_aContext.ColorMode == PDFWriter::DrawGreyscale ) 151*cdf0e10cSrcweir { 152*cdf0e10cSrcweir BmpConversion eConv = BMP_CONVERSION_8BIT_GREYS; 153*cdf0e10cSrcweir int nDepth = aBitmapEx.GetBitmap().GetBitCount(); 154*cdf0e10cSrcweir if( nDepth <= 4 ) 155*cdf0e10cSrcweir eConv = BMP_CONVERSION_4BIT_GREYS; 156*cdf0e10cSrcweir if( nDepth > 1 ) 157*cdf0e10cSrcweir aBitmapEx.Convert( eConv ); 158*cdf0e10cSrcweir } 159*cdf0e10cSrcweir sal_Bool bUseJPGCompression = !i_rContext.m_bOnlyLosslessCompression; 160*cdf0e10cSrcweir if ( ( aSizePixel.Width() < 32 ) || ( aSizePixel.Height() < 32 ) ) 161*cdf0e10cSrcweir bUseJPGCompression = sal_False; 162*cdf0e10cSrcweir 163*cdf0e10cSrcweir SvMemoryStream aStrm; 164*cdf0e10cSrcweir Bitmap aMask; 165*cdf0e10cSrcweir 166*cdf0e10cSrcweir bool bTrueColorJPG = true; 167*cdf0e10cSrcweir if ( bUseJPGCompression ) 168*cdf0e10cSrcweir { 169*cdf0e10cSrcweir sal_uInt32 nZippedFileSize; // sj: we will calculate the filesize of a zipped bitmap 170*cdf0e10cSrcweir { // to determine if jpeg compression is usefull 171*cdf0e10cSrcweir SvMemoryStream aTemp; 172*cdf0e10cSrcweir aTemp.SetCompressMode( aTemp.GetCompressMode() | COMPRESSMODE_ZBITMAP ); 173*cdf0e10cSrcweir aTemp.SetVersion( SOFFICE_FILEFORMAT_40 ); // sj: up from version 40 our bitmap stream operator 174*cdf0e10cSrcweir aTemp << aBitmapEx; // is capable of zlib stream compression 175*cdf0e10cSrcweir aTemp.Seek( STREAM_SEEK_TO_END ); 176*cdf0e10cSrcweir nZippedFileSize = aTemp.Tell(); 177*cdf0e10cSrcweir } 178*cdf0e10cSrcweir if ( aBitmapEx.IsTransparent() ) 179*cdf0e10cSrcweir { 180*cdf0e10cSrcweir if ( aBitmapEx.IsAlpha() ) 181*cdf0e10cSrcweir aMask = aBitmapEx.GetAlpha().GetBitmap(); 182*cdf0e10cSrcweir else 183*cdf0e10cSrcweir aMask = aBitmapEx.GetMask(); 184*cdf0e10cSrcweir } 185*cdf0e10cSrcweir Graphic aGraphic( aBitmapEx.GetBitmap() ); 186*cdf0e10cSrcweir sal_Int32 nColorMode = 0; 187*cdf0e10cSrcweir 188*cdf0e10cSrcweir Sequence< PropertyValue > aFilterData( 2 ); 189*cdf0e10cSrcweir aFilterData[ 0 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "Quality" ) ); 190*cdf0e10cSrcweir aFilterData[ 0 ].Value <<= sal_Int32(i_rContext.m_nJPEGQuality); 191*cdf0e10cSrcweir aFilterData[ 1 ].Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "ColorMode" ) ); 192*cdf0e10cSrcweir aFilterData[ 1 ].Value <<= nColorMode; 193*cdf0e10cSrcweir 194*cdf0e10cSrcweir try 195*cdf0e10cSrcweir { 196*cdf0e10cSrcweir uno::Reference < io::XStream > xStream = new utl::OStreamWrapper( aStrm ); 197*cdf0e10cSrcweir uno::Reference< io::XSeekable > xSeekable( xStream, UNO_QUERY_THROW ); 198*cdf0e10cSrcweir uno::Reference< graphic::XGraphicProvider > xGraphicProvider( ImplGetSVData()->maAppData.mxMSF->createInstance( 199*cdf0e10cSrcweir OUString::createFromAscii( "com.sun.star.graphic.GraphicProvider" ) ), UNO_QUERY ); 200*cdf0e10cSrcweir if ( xGraphicProvider.is() ) 201*cdf0e10cSrcweir { 202*cdf0e10cSrcweir uno::Reference< graphic::XGraphic > xGraphic( aGraphic.GetXGraphic() ); 203*cdf0e10cSrcweir uno::Reference < io::XOutputStream > xOut( xStream->getOutputStream() ); 204*cdf0e10cSrcweir rtl::OUString aMimeType( ::rtl::OUString::createFromAscii( "image/jpeg" ) ); 205*cdf0e10cSrcweir uno::Sequence< beans::PropertyValue > aOutMediaProperties( 3 ); 206*cdf0e10cSrcweir aOutMediaProperties[0].Name = ::rtl::OUString::createFromAscii( "OutputStream" ); 207*cdf0e10cSrcweir aOutMediaProperties[0].Value <<= xOut; 208*cdf0e10cSrcweir aOutMediaProperties[1].Name = ::rtl::OUString::createFromAscii( "MimeType" ); 209*cdf0e10cSrcweir aOutMediaProperties[1].Value <<= aMimeType; 210*cdf0e10cSrcweir aOutMediaProperties[2].Name = ::rtl::OUString::createFromAscii( "FilterData" ); 211*cdf0e10cSrcweir aOutMediaProperties[2].Value <<= aFilterData; 212*cdf0e10cSrcweir xGraphicProvider->storeGraphic( xGraphic, aOutMediaProperties ); 213*cdf0e10cSrcweir xOut->flush(); 214*cdf0e10cSrcweir if ( xSeekable->getLength() > nZippedFileSize ) 215*cdf0e10cSrcweir { 216*cdf0e10cSrcweir bUseJPGCompression = sal_False; 217*cdf0e10cSrcweir } 218*cdf0e10cSrcweir else 219*cdf0e10cSrcweir { 220*cdf0e10cSrcweir aStrm.Seek( STREAM_SEEK_TO_END ); 221*cdf0e10cSrcweir 222*cdf0e10cSrcweir xSeekable->seek( 0 ); 223*cdf0e10cSrcweir Sequence< PropertyValue > aArgs( 1 ); 224*cdf0e10cSrcweir aArgs[ 0 ].Name = ::rtl::OUString::createFromAscii( "InputStream" ); 225*cdf0e10cSrcweir aArgs[ 0 ].Value <<= xStream; 226*cdf0e10cSrcweir uno::Reference< XPropertySet > xPropSet( xGraphicProvider->queryGraphicDescriptor( aArgs ) ); 227*cdf0e10cSrcweir if ( xPropSet.is() ) 228*cdf0e10cSrcweir { 229*cdf0e10cSrcweir sal_Int16 nBitsPerPixel = 24; 230*cdf0e10cSrcweir if ( xPropSet->getPropertyValue( ::rtl::OUString::createFromAscii( "BitsPerPixel" ) ) >>= nBitsPerPixel ) 231*cdf0e10cSrcweir { 232*cdf0e10cSrcweir bTrueColorJPG = nBitsPerPixel != 8; 233*cdf0e10cSrcweir } 234*cdf0e10cSrcweir } 235*cdf0e10cSrcweir } 236*cdf0e10cSrcweir } 237*cdf0e10cSrcweir else 238*cdf0e10cSrcweir bUseJPGCompression = sal_False; 239*cdf0e10cSrcweir } 240*cdf0e10cSrcweir catch( uno::Exception& ) 241*cdf0e10cSrcweir { 242*cdf0e10cSrcweir bUseJPGCompression = sal_False; 243*cdf0e10cSrcweir } 244*cdf0e10cSrcweir } 245*cdf0e10cSrcweir if ( bUseJPGCompression ) 246*cdf0e10cSrcweir m_rOuterFace.DrawJPGBitmap( aStrm, bTrueColorJPG, aSizePixel, Rectangle( aPoint, aSize ), aMask ); 247*cdf0e10cSrcweir else if ( aBitmapEx.IsTransparent() ) 248*cdf0e10cSrcweir m_rOuterFace.DrawBitmapEx( aPoint, aSize, aBitmapEx ); 249*cdf0e10cSrcweir else 250*cdf0e10cSrcweir m_rOuterFace.DrawBitmap( aPoint, aSize, aBitmapEx.GetBitmap() ); 251*cdf0e10cSrcweir } 252*cdf0e10cSrcweir } 253*cdf0e10cSrcweir } 254*cdf0e10cSrcweir 255*cdf0e10cSrcweir 256*cdf0e10cSrcweir // ----------------------------------------------------------------------------- 257*cdf0e10cSrcweir 258*cdf0e10cSrcweir void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevData* i_pOutDevData, const vcl::PDFWriter::PlayMetafileContext& i_rContext, VirtualDevice* pDummyVDev ) 259*cdf0e10cSrcweir { 260*cdf0e10cSrcweir bool bAssertionFired( false ); 261*cdf0e10cSrcweir 262*cdf0e10cSrcweir VirtualDevice* pPrivateDevice = NULL; 263*cdf0e10cSrcweir if( ! pDummyVDev ) 264*cdf0e10cSrcweir { 265*cdf0e10cSrcweir pPrivateDevice = pDummyVDev = new VirtualDevice(); 266*cdf0e10cSrcweir pDummyVDev->EnableOutput( sal_False ); 267*cdf0e10cSrcweir pDummyVDev->SetMapMode( i_rMtf.GetPrefMapMode() ); 268*cdf0e10cSrcweir } 269*cdf0e10cSrcweir GDIMetaFile aMtf( i_rMtf ); 270*cdf0e10cSrcweir 271*cdf0e10cSrcweir for( sal_uInt32 i = 0, nCount = aMtf.GetActionCount(); i < nCount; ) 272*cdf0e10cSrcweir { 273*cdf0e10cSrcweir if ( !i_pOutDevData || !i_pOutDevData->PlaySyncPageAct( m_rOuterFace, i ) ) 274*cdf0e10cSrcweir { 275*cdf0e10cSrcweir const MetaAction* pAction = aMtf.GetAction( i ); 276*cdf0e10cSrcweir const sal_uInt16 nType = pAction->GetType(); 277*cdf0e10cSrcweir 278*cdf0e10cSrcweir switch( nType ) 279*cdf0e10cSrcweir { 280*cdf0e10cSrcweir case( META_PIXEL_ACTION ): 281*cdf0e10cSrcweir { 282*cdf0e10cSrcweir const MetaPixelAction* pA = (const MetaPixelAction*) pAction; 283*cdf0e10cSrcweir m_rOuterFace.DrawPixel( pA->GetPoint(), pA->GetColor() ); 284*cdf0e10cSrcweir } 285*cdf0e10cSrcweir break; 286*cdf0e10cSrcweir 287*cdf0e10cSrcweir case( META_POINT_ACTION ): 288*cdf0e10cSrcweir { 289*cdf0e10cSrcweir const MetaPointAction* pA = (const MetaPointAction*) pAction; 290*cdf0e10cSrcweir m_rOuterFace.DrawPixel( pA->GetPoint() ); 291*cdf0e10cSrcweir } 292*cdf0e10cSrcweir break; 293*cdf0e10cSrcweir 294*cdf0e10cSrcweir case( META_LINE_ACTION ): 295*cdf0e10cSrcweir { 296*cdf0e10cSrcweir const MetaLineAction* pA = (const MetaLineAction*) pAction; 297*cdf0e10cSrcweir if ( pA->GetLineInfo().IsDefault() ) 298*cdf0e10cSrcweir m_rOuterFace.DrawLine( pA->GetStartPoint(), pA->GetEndPoint() ); 299*cdf0e10cSrcweir else 300*cdf0e10cSrcweir m_rOuterFace.DrawLine( pA->GetStartPoint(), pA->GetEndPoint(), pA->GetLineInfo() ); 301*cdf0e10cSrcweir } 302*cdf0e10cSrcweir break; 303*cdf0e10cSrcweir 304*cdf0e10cSrcweir case( META_RECT_ACTION ): 305*cdf0e10cSrcweir { 306*cdf0e10cSrcweir const MetaRectAction* pA = (const MetaRectAction*) pAction; 307*cdf0e10cSrcweir m_rOuterFace.DrawRect( pA->GetRect() ); 308*cdf0e10cSrcweir } 309*cdf0e10cSrcweir break; 310*cdf0e10cSrcweir 311*cdf0e10cSrcweir case( META_ROUNDRECT_ACTION ): 312*cdf0e10cSrcweir { 313*cdf0e10cSrcweir const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction; 314*cdf0e10cSrcweir m_rOuterFace.DrawRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() ); 315*cdf0e10cSrcweir } 316*cdf0e10cSrcweir break; 317*cdf0e10cSrcweir 318*cdf0e10cSrcweir case( META_ELLIPSE_ACTION ): 319*cdf0e10cSrcweir { 320*cdf0e10cSrcweir const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction; 321*cdf0e10cSrcweir m_rOuterFace.DrawEllipse( pA->GetRect() ); 322*cdf0e10cSrcweir } 323*cdf0e10cSrcweir break; 324*cdf0e10cSrcweir 325*cdf0e10cSrcweir case( META_ARC_ACTION ): 326*cdf0e10cSrcweir { 327*cdf0e10cSrcweir const MetaArcAction* pA = (const MetaArcAction*) pAction; 328*cdf0e10cSrcweir m_rOuterFace.DrawArc( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() ); 329*cdf0e10cSrcweir } 330*cdf0e10cSrcweir break; 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir case( META_PIE_ACTION ): 333*cdf0e10cSrcweir { 334*cdf0e10cSrcweir const MetaArcAction* pA = (const MetaArcAction*) pAction; 335*cdf0e10cSrcweir m_rOuterFace.DrawPie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() ); 336*cdf0e10cSrcweir } 337*cdf0e10cSrcweir break; 338*cdf0e10cSrcweir 339*cdf0e10cSrcweir case( META_CHORD_ACTION ): 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir const MetaChordAction* pA = (const MetaChordAction*) pAction; 342*cdf0e10cSrcweir m_rOuterFace.DrawChord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() ); 343*cdf0e10cSrcweir } 344*cdf0e10cSrcweir break; 345*cdf0e10cSrcweir 346*cdf0e10cSrcweir case( META_POLYGON_ACTION ): 347*cdf0e10cSrcweir { 348*cdf0e10cSrcweir const MetaPolygonAction* pA = (const MetaPolygonAction*) pAction; 349*cdf0e10cSrcweir m_rOuterFace.DrawPolygon( pA->GetPolygon() ); 350*cdf0e10cSrcweir } 351*cdf0e10cSrcweir break; 352*cdf0e10cSrcweir 353*cdf0e10cSrcweir case( META_POLYLINE_ACTION ): 354*cdf0e10cSrcweir { 355*cdf0e10cSrcweir const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction; 356*cdf0e10cSrcweir if ( pA->GetLineInfo().IsDefault() ) 357*cdf0e10cSrcweir m_rOuterFace.DrawPolyLine( pA->GetPolygon() ); 358*cdf0e10cSrcweir else 359*cdf0e10cSrcweir m_rOuterFace.DrawPolyLine( pA->GetPolygon(), pA->GetLineInfo() ); 360*cdf0e10cSrcweir } 361*cdf0e10cSrcweir break; 362*cdf0e10cSrcweir 363*cdf0e10cSrcweir case( META_POLYPOLYGON_ACTION ): 364*cdf0e10cSrcweir { 365*cdf0e10cSrcweir const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pAction; 366*cdf0e10cSrcweir m_rOuterFace.DrawPolyPolygon( pA->GetPolyPolygon() ); 367*cdf0e10cSrcweir } 368*cdf0e10cSrcweir break; 369*cdf0e10cSrcweir 370*cdf0e10cSrcweir case( META_GRADIENT_ACTION ): 371*cdf0e10cSrcweir { 372*cdf0e10cSrcweir const MetaGradientAction* pA = (const MetaGradientAction*) pAction; 373*cdf0e10cSrcweir #ifdef USE_PDFGRADIENTS 374*cdf0e10cSrcweir m_rOuterFace.DrawGradient( pA->GetRect(), pA->GetGradient() ); 375*cdf0e10cSrcweir #else 376*cdf0e10cSrcweir const PolyPolygon aPolyPoly( pA->GetRect() ); 377*cdf0e10cSrcweir implWriteGradient( aPolyPoly, pA->GetGradient(), pDummyVDev, i_rContext ); 378*cdf0e10cSrcweir #endif 379*cdf0e10cSrcweir } 380*cdf0e10cSrcweir break; 381*cdf0e10cSrcweir 382*cdf0e10cSrcweir case( META_GRADIENTEX_ACTION ): 383*cdf0e10cSrcweir { 384*cdf0e10cSrcweir const MetaGradientExAction* pA = (const MetaGradientExAction*) pAction; 385*cdf0e10cSrcweir #ifdef USE_PDFGRADIENTS 386*cdf0e10cSrcweir m_rOuterFace.DrawGradient( pA->GetPolyPolygon(), pA->GetGradient() ); 387*cdf0e10cSrcweir #else 388*cdf0e10cSrcweir implWriteGradient( pA->GetPolyPolygon(), pA->GetGradient(), pDummyVDev, i_rContext ); 389*cdf0e10cSrcweir #endif 390*cdf0e10cSrcweir } 391*cdf0e10cSrcweir break; 392*cdf0e10cSrcweir 393*cdf0e10cSrcweir case META_HATCH_ACTION: 394*cdf0e10cSrcweir { 395*cdf0e10cSrcweir const MetaHatchAction* pA = (const MetaHatchAction*) pAction; 396*cdf0e10cSrcweir m_rOuterFace.DrawHatch( pA->GetPolyPolygon(), pA->GetHatch() ); 397*cdf0e10cSrcweir } 398*cdf0e10cSrcweir break; 399*cdf0e10cSrcweir 400*cdf0e10cSrcweir case( META_TRANSPARENT_ACTION ): 401*cdf0e10cSrcweir { 402*cdf0e10cSrcweir const MetaTransparentAction* pA = (const MetaTransparentAction*) pAction; 403*cdf0e10cSrcweir m_rOuterFace.DrawTransparent( pA->GetPolyPolygon(), pA->GetTransparence() ); 404*cdf0e10cSrcweir } 405*cdf0e10cSrcweir break; 406*cdf0e10cSrcweir 407*cdf0e10cSrcweir case( META_FLOATTRANSPARENT_ACTION ): 408*cdf0e10cSrcweir { 409*cdf0e10cSrcweir const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction; 410*cdf0e10cSrcweir 411*cdf0e10cSrcweir GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() ); 412*cdf0e10cSrcweir const Point& rPos = pA->GetPoint(); 413*cdf0e10cSrcweir const Size& rSize= pA->GetSize(); 414*cdf0e10cSrcweir const Gradient& rTransparenceGradient = pA->GetGradient(); 415*cdf0e10cSrcweir 416*cdf0e10cSrcweir // special case constant alpha value 417*cdf0e10cSrcweir if( rTransparenceGradient.GetStartColor() == rTransparenceGradient.GetEndColor() ) 418*cdf0e10cSrcweir { 419*cdf0e10cSrcweir const Color aTransCol( rTransparenceGradient.GetStartColor() ); 420*cdf0e10cSrcweir const sal_uInt16 nTransPercent = aTransCol.GetLuminance() * 100 / 255; 421*cdf0e10cSrcweir m_rOuterFace.BeginTransparencyGroup(); 422*cdf0e10cSrcweir playMetafile( aTmpMtf, NULL, i_rContext, pDummyVDev ); 423*cdf0e10cSrcweir m_rOuterFace.EndTransparencyGroup( Rectangle( rPos, rSize ), nTransPercent ); 424*cdf0e10cSrcweir } 425*cdf0e10cSrcweir else 426*cdf0e10cSrcweir { 427*cdf0e10cSrcweir const Size aDstSizeTwip( pDummyVDev->PixelToLogic( pDummyVDev->LogicToPixel( rSize ), MAP_TWIP ) ); 428*cdf0e10cSrcweir sal_Int32 nMaxBmpDPI = i_rContext.m_bOnlyLosslessCompression ? 300 : 72; 429*cdf0e10cSrcweir if( i_rContext.m_nMaxImageResolution > 50 ) 430*cdf0e10cSrcweir { 431*cdf0e10cSrcweir if ( nMaxBmpDPI > i_rContext.m_nMaxImageResolution ) 432*cdf0e10cSrcweir nMaxBmpDPI = i_rContext.m_nMaxImageResolution; 433*cdf0e10cSrcweir } 434*cdf0e10cSrcweir const sal_Int32 nPixelX = (sal_Int32)((double)aDstSizeTwip.Width() * (double)nMaxBmpDPI / 1440.0); 435*cdf0e10cSrcweir const sal_Int32 nPixelY = (sal_Int32)((double)aDstSizeTwip.Height() * (double)nMaxBmpDPI / 1440.0); 436*cdf0e10cSrcweir if ( nPixelX && nPixelY ) 437*cdf0e10cSrcweir { 438*cdf0e10cSrcweir Size aDstSizePixel( nPixelX, nPixelY ); 439*cdf0e10cSrcweir VirtualDevice* pVDev = new VirtualDevice; 440*cdf0e10cSrcweir if( pVDev->SetOutputSizePixel( aDstSizePixel ) ) 441*cdf0e10cSrcweir { 442*cdf0e10cSrcweir Bitmap aPaint, aMask; 443*cdf0e10cSrcweir AlphaMask aAlpha; 444*cdf0e10cSrcweir Point aPoint; 445*cdf0e10cSrcweir 446*cdf0e10cSrcweir MapMode aMapMode( pDummyVDev->GetMapMode() ); 447*cdf0e10cSrcweir aMapMode.SetOrigin( aPoint ); 448*cdf0e10cSrcweir pVDev->SetMapMode( aMapMode ); 449*cdf0e10cSrcweir Size aDstSize( pVDev->PixelToLogic( aDstSizePixel ) ); 450*cdf0e10cSrcweir 451*cdf0e10cSrcweir Point aMtfOrigin( aTmpMtf.GetPrefMapMode().GetOrigin() ); 452*cdf0e10cSrcweir if ( aMtfOrigin.X() || aMtfOrigin.Y() ) 453*cdf0e10cSrcweir aTmpMtf.Move( -aMtfOrigin.X(), -aMtfOrigin.Y() ); 454*cdf0e10cSrcweir double fScaleX = (double)aDstSize.Width() / (double)aTmpMtf.GetPrefSize().Width(); 455*cdf0e10cSrcweir double fScaleY = (double)aDstSize.Height() / (double)aTmpMtf.GetPrefSize().Height(); 456*cdf0e10cSrcweir if( fScaleX != 1.0 || fScaleY != 1.0 ) 457*cdf0e10cSrcweir aTmpMtf.Scale( fScaleX, fScaleY ); 458*cdf0e10cSrcweir aTmpMtf.SetPrefMapMode( aMapMode ); 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir // create paint bitmap 461*cdf0e10cSrcweir aTmpMtf.WindStart(); 462*cdf0e10cSrcweir aTmpMtf.Play( pVDev, aPoint, aDstSize ); 463*cdf0e10cSrcweir aTmpMtf.WindStart(); 464*cdf0e10cSrcweir 465*cdf0e10cSrcweir pVDev->EnableMapMode( sal_False ); 466*cdf0e10cSrcweir aPaint = pVDev->GetBitmap( aPoint, aDstSizePixel ); 467*cdf0e10cSrcweir pVDev->EnableMapMode( sal_True ); 468*cdf0e10cSrcweir 469*cdf0e10cSrcweir // create mask bitmap 470*cdf0e10cSrcweir pVDev->SetLineColor( COL_BLACK ); 471*cdf0e10cSrcweir pVDev->SetFillColor( COL_BLACK ); 472*cdf0e10cSrcweir pVDev->DrawRect( Rectangle( aPoint, aDstSize ) ); 473*cdf0e10cSrcweir pVDev->SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT | 474*cdf0e10cSrcweir DRAWMODE_WHITEBITMAP | DRAWMODE_WHITEGRADIENT ); 475*cdf0e10cSrcweir aTmpMtf.WindStart(); 476*cdf0e10cSrcweir aTmpMtf.Play( pVDev, aPoint, aDstSize ); 477*cdf0e10cSrcweir aTmpMtf.WindStart(); 478*cdf0e10cSrcweir pVDev->EnableMapMode( sal_False ); 479*cdf0e10cSrcweir aMask = pVDev->GetBitmap( aPoint, aDstSizePixel ); 480*cdf0e10cSrcweir pVDev->EnableMapMode( sal_True ); 481*cdf0e10cSrcweir 482*cdf0e10cSrcweir // create alpha mask from gradient 483*cdf0e10cSrcweir pVDev->SetDrawMode( DRAWMODE_GRAYGRADIENT ); 484*cdf0e10cSrcweir pVDev->DrawGradient( Rectangle( aPoint, aDstSize ), rTransparenceGradient ); 485*cdf0e10cSrcweir pVDev->SetDrawMode( DRAWMODE_DEFAULT ); 486*cdf0e10cSrcweir pVDev->EnableMapMode( sal_False ); 487*cdf0e10cSrcweir pVDev->DrawMask( aPoint, aDstSizePixel, aMask, Color( COL_WHITE ) ); 488*cdf0e10cSrcweir aAlpha = pVDev->GetBitmap( aPoint, aDstSizePixel ); 489*cdf0e10cSrcweir implWriteBitmapEx( rPos, rSize, BitmapEx( aPaint, aAlpha ), pDummyVDev, i_rContext ); 490*cdf0e10cSrcweir } 491*cdf0e10cSrcweir delete pVDev; 492*cdf0e10cSrcweir } 493*cdf0e10cSrcweir } 494*cdf0e10cSrcweir } 495*cdf0e10cSrcweir break; 496*cdf0e10cSrcweir 497*cdf0e10cSrcweir case( META_EPS_ACTION ): 498*cdf0e10cSrcweir { 499*cdf0e10cSrcweir const MetaEPSAction* pA = (const MetaEPSAction*) pAction; 500*cdf0e10cSrcweir const GDIMetaFile aSubstitute( pA->GetSubstitute() ); 501*cdf0e10cSrcweir 502*cdf0e10cSrcweir m_rOuterFace.Push(); 503*cdf0e10cSrcweir pDummyVDev->Push(); 504*cdf0e10cSrcweir 505*cdf0e10cSrcweir MapMode aMapMode( aSubstitute.GetPrefMapMode() ); 506*cdf0e10cSrcweir Size aOutSize( pDummyVDev->LogicToLogic( pA->GetSize(), pDummyVDev->GetMapMode(), aMapMode ) ); 507*cdf0e10cSrcweir aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) ); 508*cdf0e10cSrcweir aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) ); 509*cdf0e10cSrcweir aMapMode.SetOrigin( pDummyVDev->LogicToLogic( pA->GetPoint(), pDummyVDev->GetMapMode(), aMapMode ) ); 510*cdf0e10cSrcweir 511*cdf0e10cSrcweir m_rOuterFace.SetMapMode( aMapMode ); 512*cdf0e10cSrcweir pDummyVDev->SetMapMode( aMapMode ); 513*cdf0e10cSrcweir playMetafile( aSubstitute, NULL, i_rContext, pDummyVDev ); 514*cdf0e10cSrcweir pDummyVDev->Pop(); 515*cdf0e10cSrcweir m_rOuterFace.Pop(); 516*cdf0e10cSrcweir } 517*cdf0e10cSrcweir break; 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir case( META_COMMENT_ACTION ): 520*cdf0e10cSrcweir if( ! i_rContext.m_bTransparenciesWereRemoved ) 521*cdf0e10cSrcweir { 522*cdf0e10cSrcweir const MetaCommentAction* pA = (const MetaCommentAction*) pAction; 523*cdf0e10cSrcweir String aSkipComment; 524*cdf0e10cSrcweir 525*cdf0e10cSrcweir if( pA->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL ) 526*cdf0e10cSrcweir { 527*cdf0e10cSrcweir const MetaGradientExAction* pGradAction = NULL; 528*cdf0e10cSrcweir sal_Bool bDone = sal_False; 529*cdf0e10cSrcweir 530*cdf0e10cSrcweir while( !bDone && ( ++i < nCount ) ) 531*cdf0e10cSrcweir { 532*cdf0e10cSrcweir pAction = aMtf.GetAction( i ); 533*cdf0e10cSrcweir 534*cdf0e10cSrcweir if( pAction->GetType() == META_GRADIENTEX_ACTION ) 535*cdf0e10cSrcweir pGradAction = (const MetaGradientExAction*) pAction; 536*cdf0e10cSrcweir else if( ( pAction->GetType() == META_COMMENT_ACTION ) && 537*cdf0e10cSrcweir ( ( (const MetaCommentAction*) pAction )->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL ) ) 538*cdf0e10cSrcweir { 539*cdf0e10cSrcweir bDone = sal_True; 540*cdf0e10cSrcweir } 541*cdf0e10cSrcweir } 542*cdf0e10cSrcweir 543*cdf0e10cSrcweir if( pGradAction ) 544*cdf0e10cSrcweir { 545*cdf0e10cSrcweir #if USE_PDFGRADIENTS 546*cdf0e10cSrcweir m_rOuterFace.DrawGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient() ); 547*cdf0e10cSrcweir #else 548*cdf0e10cSrcweir implWriteGradient( pGradAction->GetPolyPolygon(), pGradAction->GetGradient(), pDummyVDev, i_rContext ); 549*cdf0e10cSrcweir #endif 550*cdf0e10cSrcweir } 551*cdf0e10cSrcweir } 552*cdf0e10cSrcweir else 553*cdf0e10cSrcweir { 554*cdf0e10cSrcweir const sal_uInt8* pData = pA->GetData(); 555*cdf0e10cSrcweir if ( pData ) 556*cdf0e10cSrcweir { 557*cdf0e10cSrcweir SvMemoryStream aMemStm( (void*)pData, pA->GetDataSize(), STREAM_READ ); 558*cdf0e10cSrcweir sal_Bool bSkipSequence = sal_False; 559*cdf0e10cSrcweir ByteString sSeqEnd; 560*cdf0e10cSrcweir 561*cdf0e10cSrcweir if( pA->GetComment().Equals( "XPATHSTROKE_SEQ_BEGIN" ) ) 562*cdf0e10cSrcweir { 563*cdf0e10cSrcweir sSeqEnd = ByteString( "XPATHSTROKE_SEQ_END" ); 564*cdf0e10cSrcweir SvtGraphicStroke aStroke; 565*cdf0e10cSrcweir aMemStm >> aStroke; 566*cdf0e10cSrcweir 567*cdf0e10cSrcweir Polygon aPath; 568*cdf0e10cSrcweir aStroke.getPath( aPath ); 569*cdf0e10cSrcweir 570*cdf0e10cSrcweir PolyPolygon aStartArrow; 571*cdf0e10cSrcweir PolyPolygon aEndArrow; 572*cdf0e10cSrcweir double fTransparency( aStroke.getTransparency() ); 573*cdf0e10cSrcweir double fStrokeWidth( aStroke.getStrokeWidth() ); 574*cdf0e10cSrcweir SvtGraphicStroke::DashArray aDashArray; 575*cdf0e10cSrcweir 576*cdf0e10cSrcweir aStroke.getStartArrow( aStartArrow ); 577*cdf0e10cSrcweir aStroke.getEndArrow( aEndArrow ); 578*cdf0e10cSrcweir aStroke.getDashArray( aDashArray ); 579*cdf0e10cSrcweir 580*cdf0e10cSrcweir bSkipSequence = sal_True; 581*cdf0e10cSrcweir if ( aStartArrow.Count() || aEndArrow.Count() ) 582*cdf0e10cSrcweir bSkipSequence = sal_False; 583*cdf0e10cSrcweir if ( aDashArray.size() && ( fStrokeWidth != 0.0 ) && ( fTransparency == 0.0 ) ) 584*cdf0e10cSrcweir bSkipSequence = sal_False; 585*cdf0e10cSrcweir if ( bSkipSequence ) 586*cdf0e10cSrcweir { 587*cdf0e10cSrcweir PDFWriter::ExtLineInfo aInfo; 588*cdf0e10cSrcweir aInfo.m_fLineWidth = fStrokeWidth; 589*cdf0e10cSrcweir aInfo.m_fTransparency = fTransparency; 590*cdf0e10cSrcweir aInfo.m_fMiterLimit = aStroke.getMiterLimit(); 591*cdf0e10cSrcweir switch( aStroke.getCapType() ) 592*cdf0e10cSrcweir { 593*cdf0e10cSrcweir default: 594*cdf0e10cSrcweir case SvtGraphicStroke::capButt: aInfo.m_eCap = PDFWriter::capButt;break; 595*cdf0e10cSrcweir case SvtGraphicStroke::capRound: aInfo.m_eCap = PDFWriter::capRound;break; 596*cdf0e10cSrcweir case SvtGraphicStroke::capSquare: aInfo.m_eCap = PDFWriter::capSquare;break; 597*cdf0e10cSrcweir } 598*cdf0e10cSrcweir switch( aStroke.getJoinType() ) 599*cdf0e10cSrcweir { 600*cdf0e10cSrcweir default: 601*cdf0e10cSrcweir case SvtGraphicStroke::joinMiter: aInfo.m_eJoin = PDFWriter::joinMiter;break; 602*cdf0e10cSrcweir case SvtGraphicStroke::joinRound: aInfo.m_eJoin = PDFWriter::joinRound;break; 603*cdf0e10cSrcweir case SvtGraphicStroke::joinBevel: aInfo.m_eJoin = PDFWriter::joinBevel;break; 604*cdf0e10cSrcweir case SvtGraphicStroke::joinNone: 605*cdf0e10cSrcweir aInfo.m_eJoin = PDFWriter::joinMiter; 606*cdf0e10cSrcweir aInfo.m_fMiterLimit = 0.0; 607*cdf0e10cSrcweir break; 608*cdf0e10cSrcweir } 609*cdf0e10cSrcweir aInfo.m_aDashArray = aDashArray; 610*cdf0e10cSrcweir 611*cdf0e10cSrcweir if(SvtGraphicStroke::joinNone == aStroke.getJoinType() 612*cdf0e10cSrcweir && fStrokeWidth > 0.0) 613*cdf0e10cSrcweir { 614*cdf0e10cSrcweir // emulate no edge rounding by handling single edges 615*cdf0e10cSrcweir const sal_uInt16 nPoints(aPath.GetSize()); 616*cdf0e10cSrcweir const bool bCurve(aPath.HasFlags()); 617*cdf0e10cSrcweir 618*cdf0e10cSrcweir for(sal_uInt16 a(0); a + 1 < nPoints; a++) 619*cdf0e10cSrcweir { 620*cdf0e10cSrcweir if(bCurve 621*cdf0e10cSrcweir && POLY_NORMAL != aPath.GetFlags(a + 1) 622*cdf0e10cSrcweir && a + 2 < nPoints 623*cdf0e10cSrcweir && POLY_NORMAL != aPath.GetFlags(a + 2) 624*cdf0e10cSrcweir && a + 3 < nPoints) 625*cdf0e10cSrcweir { 626*cdf0e10cSrcweir const Polygon aSnippet(4, 627*cdf0e10cSrcweir aPath.GetConstPointAry() + a, 628*cdf0e10cSrcweir aPath.GetConstFlagAry() + a); 629*cdf0e10cSrcweir m_rOuterFace.DrawPolyLine( aSnippet, aInfo ); 630*cdf0e10cSrcweir a += 2; 631*cdf0e10cSrcweir } 632*cdf0e10cSrcweir else 633*cdf0e10cSrcweir { 634*cdf0e10cSrcweir const Polygon aSnippet(2, 635*cdf0e10cSrcweir aPath.GetConstPointAry() + a); 636*cdf0e10cSrcweir m_rOuterFace.DrawPolyLine( aSnippet, aInfo ); 637*cdf0e10cSrcweir } 638*cdf0e10cSrcweir } 639*cdf0e10cSrcweir } 640*cdf0e10cSrcweir else 641*cdf0e10cSrcweir { 642*cdf0e10cSrcweir m_rOuterFace.DrawPolyLine( aPath, aInfo ); 643*cdf0e10cSrcweir } 644*cdf0e10cSrcweir } 645*cdf0e10cSrcweir } 646*cdf0e10cSrcweir else if ( pA->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) ) 647*cdf0e10cSrcweir { 648*cdf0e10cSrcweir sSeqEnd = ByteString( "XPATHFILL_SEQ_END" ); 649*cdf0e10cSrcweir SvtGraphicFill aFill; 650*cdf0e10cSrcweir aMemStm >> aFill; 651*cdf0e10cSrcweir 652*cdf0e10cSrcweir if ( ( aFill.getFillType() == SvtGraphicFill::fillSolid ) && ( aFill.getFillRule() == SvtGraphicFill::fillEvenOdd ) ) 653*cdf0e10cSrcweir { 654*cdf0e10cSrcweir double fTransparency = aFill.getTransparency(); 655*cdf0e10cSrcweir if ( fTransparency == 0.0 ) 656*cdf0e10cSrcweir { 657*cdf0e10cSrcweir PolyPolygon aPath; 658*cdf0e10cSrcweir aFill.getPath( aPath ); 659*cdf0e10cSrcweir 660*cdf0e10cSrcweir bSkipSequence = sal_True; 661*cdf0e10cSrcweir m_rOuterFace.DrawPolyPolygon( aPath ); 662*cdf0e10cSrcweir } 663*cdf0e10cSrcweir else if ( fTransparency == 1.0 ) 664*cdf0e10cSrcweir bSkipSequence = sal_True; 665*cdf0e10cSrcweir } 666*cdf0e10cSrcweir /* #i81548# removing optimization for fill textures, because most of the texture settings are not 667*cdf0e10cSrcweir exported properly. In OpenOffice 3.1 the drawing layer will support graphic primitives, then it 668*cdf0e10cSrcweir will not be a problem to optimize the filltexture export. But for wysiwyg is more important than 669*cdf0e10cSrcweir filesize. 670*cdf0e10cSrcweir else if( aFill.getFillType() == SvtGraphicFill::fillTexture && aFill.isTiling() ) 671*cdf0e10cSrcweir { 672*cdf0e10cSrcweir sal_Int32 nPattern = mnCachePatternId; 673*cdf0e10cSrcweir Graphic aPatternGraphic; 674*cdf0e10cSrcweir aFill.getGraphic( aPatternGraphic ); 675*cdf0e10cSrcweir bool bUseCache = false; 676*cdf0e10cSrcweir SvtGraphicFill::Transform aPatTransform; 677*cdf0e10cSrcweir aFill.getTransform( aPatTransform ); 678*cdf0e10cSrcweir 679*cdf0e10cSrcweir if( mnCachePatternId >= 0 ) 680*cdf0e10cSrcweir { 681*cdf0e10cSrcweir SvtGraphicFill::Transform aCacheTransform; 682*cdf0e10cSrcweir maCacheFill.getTransform( aCacheTransform ); 683*cdf0e10cSrcweir if( aCacheTransform.matrix[0] == aPatTransform.matrix[0] && 684*cdf0e10cSrcweir aCacheTransform.matrix[1] == aPatTransform.matrix[1] && 685*cdf0e10cSrcweir aCacheTransform.matrix[2] == aPatTransform.matrix[2] && 686*cdf0e10cSrcweir aCacheTransform.matrix[3] == aPatTransform.matrix[3] && 687*cdf0e10cSrcweir aCacheTransform.matrix[4] == aPatTransform.matrix[4] && 688*cdf0e10cSrcweir aCacheTransform.matrix[5] == aPatTransform.matrix[5] 689*cdf0e10cSrcweir ) 690*cdf0e10cSrcweir { 691*cdf0e10cSrcweir Graphic aCacheGraphic; 692*cdf0e10cSrcweir maCacheFill.getGraphic( aCacheGraphic ); 693*cdf0e10cSrcweir if( aCacheGraphic == aPatternGraphic ) 694*cdf0e10cSrcweir bUseCache = true; 695*cdf0e10cSrcweir } 696*cdf0e10cSrcweir } 697*cdf0e10cSrcweir 698*cdf0e10cSrcweir if( ! bUseCache ) 699*cdf0e10cSrcweir { 700*cdf0e10cSrcweir 701*cdf0e10cSrcweir // paint graphic to metafile 702*cdf0e10cSrcweir GDIMetaFile aPattern; 703*cdf0e10cSrcweir pDummyVDev->SetConnectMetaFile( &aPattern ); 704*cdf0e10cSrcweir pDummyVDev->Push(); 705*cdf0e10cSrcweir pDummyVDev->SetMapMode( aPatternGraphic.GetPrefMapMode() ); 706*cdf0e10cSrcweir 707*cdf0e10cSrcweir aPatternGraphic.Draw( &rDummyVDev, Point( 0, 0 ) ); 708*cdf0e10cSrcweir pDummyVDev->Pop(); 709*cdf0e10cSrcweir pDummyVDev->SetConnectMetaFile( NULL ); 710*cdf0e10cSrcweir aPattern.WindStart(); 711*cdf0e10cSrcweir 712*cdf0e10cSrcweir MapMode aPatternMapMode( aPatternGraphic.GetPrefMapMode() ); 713*cdf0e10cSrcweir // prepare pattern from metafile 714*cdf0e10cSrcweir Size aPrefSize( aPatternGraphic.GetPrefSize() ); 715*cdf0e10cSrcweir // FIXME: this magic -1 shouldn't be necessary 716*cdf0e10cSrcweir aPrefSize.Width() -= 1; 717*cdf0e10cSrcweir aPrefSize.Height() -= 1; 718*cdf0e10cSrcweir aPrefSize = m_rOuterFace.GetReferenceDevice()-> 719*cdf0e10cSrcweir LogicToLogic( aPrefSize, 720*cdf0e10cSrcweir &aPatternMapMode, 721*cdf0e10cSrcweir &m_rOuterFace.GetReferenceDevice()->GetMapMode() ); 722*cdf0e10cSrcweir // build bounding rectangle of pattern 723*cdf0e10cSrcweir Rectangle aBound( Point( 0, 0 ), aPrefSize ); 724*cdf0e10cSrcweir m_rOuterFace.BeginPattern( aBound ); 725*cdf0e10cSrcweir m_rOuterFace.Push(); 726*cdf0e10cSrcweir pDummyVDev->Push(); 727*cdf0e10cSrcweir m_rOuterFace.SetMapMode( aPatternMapMode ); 728*cdf0e10cSrcweir pDummyVDev->SetMapMode( aPatternMapMode ); 729*cdf0e10cSrcweir ImplWriteActions( m_rOuterFace, NULL, aPattern, rDummyVDev ); 730*cdf0e10cSrcweir pDummyVDev->Pop(); 731*cdf0e10cSrcweir m_rOuterFace.Pop(); 732*cdf0e10cSrcweir 733*cdf0e10cSrcweir nPattern = m_rOuterFace.EndPattern( aPatTransform ); 734*cdf0e10cSrcweir 735*cdf0e10cSrcweir // try some caching and reuse pattern 736*cdf0e10cSrcweir mnCachePatternId = nPattern; 737*cdf0e10cSrcweir maCacheFill = aFill; 738*cdf0e10cSrcweir } 739*cdf0e10cSrcweir 740*cdf0e10cSrcweir // draw polypolygon with pattern fill 741*cdf0e10cSrcweir PolyPolygon aPath; 742*cdf0e10cSrcweir aFill.getPath( aPath ); 743*cdf0e10cSrcweir m_rOuterFace.DrawPolyPolygon( aPath, nPattern, aFill.getFillRule() == SvtGraphicFill::fillEvenOdd ); 744*cdf0e10cSrcweir 745*cdf0e10cSrcweir bSkipSequence = sal_True; 746*cdf0e10cSrcweir } 747*cdf0e10cSrcweir */ 748*cdf0e10cSrcweir } 749*cdf0e10cSrcweir if ( bSkipSequence ) 750*cdf0e10cSrcweir { 751*cdf0e10cSrcweir while( ++i < nCount ) 752*cdf0e10cSrcweir { 753*cdf0e10cSrcweir pAction = aMtf.GetAction( i ); 754*cdf0e10cSrcweir if ( pAction->GetType() == META_COMMENT_ACTION ) 755*cdf0e10cSrcweir { 756*cdf0e10cSrcweir ByteString sComment( ((MetaCommentAction*)pAction)->GetComment() ); 757*cdf0e10cSrcweir if ( sComment.Equals( sSeqEnd ) ) 758*cdf0e10cSrcweir break; 759*cdf0e10cSrcweir } 760*cdf0e10cSrcweir // #i44496# 761*cdf0e10cSrcweir // the replacement action for stroke is a filled rectangle 762*cdf0e10cSrcweir // the set fillcolor of the replacement is part of the graphics 763*cdf0e10cSrcweir // state and must not be skipped 764*cdf0e10cSrcweir else if( pAction->GetType() == META_FILLCOLOR_ACTION ) 765*cdf0e10cSrcweir { 766*cdf0e10cSrcweir const MetaFillColorAction* pMA = (const MetaFillColorAction*) pAction; 767*cdf0e10cSrcweir if( pMA->IsSetting() ) 768*cdf0e10cSrcweir m_rOuterFace.SetFillColor( pMA->GetColor() ); 769*cdf0e10cSrcweir else 770*cdf0e10cSrcweir m_rOuterFace.SetFillColor(); 771*cdf0e10cSrcweir } 772*cdf0e10cSrcweir } 773*cdf0e10cSrcweir } 774*cdf0e10cSrcweir } 775*cdf0e10cSrcweir } 776*cdf0e10cSrcweir } 777*cdf0e10cSrcweir break; 778*cdf0e10cSrcweir 779*cdf0e10cSrcweir case( META_BMP_ACTION ): 780*cdf0e10cSrcweir { 781*cdf0e10cSrcweir const MetaBmpAction* pA = (const MetaBmpAction*) pAction; 782*cdf0e10cSrcweir BitmapEx aBitmapEx( pA->GetBitmap() ); 783*cdf0e10cSrcweir Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(), 784*cdf0e10cSrcweir aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) ); 785*cdf0e10cSrcweir if( ! ( aSize.Width() && aSize.Height() ) ) 786*cdf0e10cSrcweir aSize = pDummyVDev->PixelToLogic( aBitmapEx.GetSizePixel() ); 787*cdf0e10cSrcweir implWriteBitmapEx( pA->GetPoint(), aSize, aBitmapEx, pDummyVDev, i_rContext ); 788*cdf0e10cSrcweir } 789*cdf0e10cSrcweir break; 790*cdf0e10cSrcweir 791*cdf0e10cSrcweir case( META_BMPSCALE_ACTION ): 792*cdf0e10cSrcweir { 793*cdf0e10cSrcweir const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction; 794*cdf0e10cSrcweir implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), BitmapEx( pA->GetBitmap() ), pDummyVDev, i_rContext ); 795*cdf0e10cSrcweir } 796*cdf0e10cSrcweir break; 797*cdf0e10cSrcweir 798*cdf0e10cSrcweir case( META_BMPSCALEPART_ACTION ): 799*cdf0e10cSrcweir { 800*cdf0e10cSrcweir const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction; 801*cdf0e10cSrcweir BitmapEx aBitmapEx( pA->GetBitmap() ); 802*cdf0e10cSrcweir aBitmapEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ); 803*cdf0e10cSrcweir implWriteBitmapEx( pA->GetDestPoint(), pA->GetDestSize(), aBitmapEx, pDummyVDev, i_rContext ); 804*cdf0e10cSrcweir } 805*cdf0e10cSrcweir break; 806*cdf0e10cSrcweir 807*cdf0e10cSrcweir case( META_BMPEX_ACTION ): 808*cdf0e10cSrcweir { 809*cdf0e10cSrcweir const MetaBmpExAction* pA = (const MetaBmpExAction*) pAction; 810*cdf0e10cSrcweir BitmapEx aBitmapEx( pA->GetBitmapEx() ); 811*cdf0e10cSrcweir Size aSize( OutputDevice::LogicToLogic( aBitmapEx.GetPrefSize(), 812*cdf0e10cSrcweir aBitmapEx.GetPrefMapMode(), pDummyVDev->GetMapMode() ) ); 813*cdf0e10cSrcweir implWriteBitmapEx( pA->GetPoint(), aSize, aBitmapEx, pDummyVDev, i_rContext ); 814*cdf0e10cSrcweir } 815*cdf0e10cSrcweir break; 816*cdf0e10cSrcweir 817*cdf0e10cSrcweir case( META_BMPEXSCALE_ACTION ): 818*cdf0e10cSrcweir { 819*cdf0e10cSrcweir const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction; 820*cdf0e10cSrcweir implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), pA->GetBitmapEx(), pDummyVDev, i_rContext ); 821*cdf0e10cSrcweir } 822*cdf0e10cSrcweir break; 823*cdf0e10cSrcweir 824*cdf0e10cSrcweir case( META_BMPEXSCALEPART_ACTION ): 825*cdf0e10cSrcweir { 826*cdf0e10cSrcweir const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction; 827*cdf0e10cSrcweir BitmapEx aBitmapEx( pA->GetBitmapEx() ); 828*cdf0e10cSrcweir aBitmapEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ); 829*cdf0e10cSrcweir implWriteBitmapEx( pA->GetDestPoint(), pA->GetDestSize(), aBitmapEx, pDummyVDev, i_rContext ); 830*cdf0e10cSrcweir } 831*cdf0e10cSrcweir break; 832*cdf0e10cSrcweir 833*cdf0e10cSrcweir case( META_MASK_ACTION ): 834*cdf0e10cSrcweir case( META_MASKSCALE_ACTION ): 835*cdf0e10cSrcweir case( META_MASKSCALEPART_ACTION ): 836*cdf0e10cSrcweir { 837*cdf0e10cSrcweir DBG_ERROR( "MetaMask...Action not supported yet" ); 838*cdf0e10cSrcweir } 839*cdf0e10cSrcweir break; 840*cdf0e10cSrcweir 841*cdf0e10cSrcweir case( META_TEXT_ACTION ): 842*cdf0e10cSrcweir { 843*cdf0e10cSrcweir const MetaTextAction* pA = (const MetaTextAction*) pAction; 844*cdf0e10cSrcweir m_rOuterFace.DrawText( pA->GetPoint(), String( pA->GetText(), pA->GetIndex(), pA->GetLen() ) ); 845*cdf0e10cSrcweir } 846*cdf0e10cSrcweir break; 847*cdf0e10cSrcweir 848*cdf0e10cSrcweir case( META_TEXTRECT_ACTION ): 849*cdf0e10cSrcweir { 850*cdf0e10cSrcweir const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction; 851*cdf0e10cSrcweir m_rOuterFace.DrawText( pA->GetRect(), String( pA->GetText() ), pA->GetStyle() ); 852*cdf0e10cSrcweir } 853*cdf0e10cSrcweir break; 854*cdf0e10cSrcweir 855*cdf0e10cSrcweir case( META_TEXTARRAY_ACTION ): 856*cdf0e10cSrcweir { 857*cdf0e10cSrcweir const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction; 858*cdf0e10cSrcweir m_rOuterFace.DrawTextArray( pA->GetPoint(), pA->GetText(), pA->GetDXArray(), pA->GetIndex(), pA->GetLen() ); 859*cdf0e10cSrcweir } 860*cdf0e10cSrcweir break; 861*cdf0e10cSrcweir 862*cdf0e10cSrcweir case( META_STRETCHTEXT_ACTION ): 863*cdf0e10cSrcweir { 864*cdf0e10cSrcweir const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction; 865*cdf0e10cSrcweir m_rOuterFace.DrawStretchText( pA->GetPoint(), pA->GetWidth(), pA->GetText(), pA->GetIndex(), pA->GetLen() ); 866*cdf0e10cSrcweir } 867*cdf0e10cSrcweir break; 868*cdf0e10cSrcweir 869*cdf0e10cSrcweir 870*cdf0e10cSrcweir case( META_TEXTLINE_ACTION ): 871*cdf0e10cSrcweir { 872*cdf0e10cSrcweir const MetaTextLineAction* pA = (const MetaTextLineAction*) pAction; 873*cdf0e10cSrcweir m_rOuterFace.DrawTextLine( pA->GetStartPoint(), pA->GetWidth(), pA->GetStrikeout(), pA->GetUnderline(), pA->GetOverline() ); 874*cdf0e10cSrcweir 875*cdf0e10cSrcweir } 876*cdf0e10cSrcweir break; 877*cdf0e10cSrcweir 878*cdf0e10cSrcweir case( META_CLIPREGION_ACTION ): 879*cdf0e10cSrcweir { 880*cdf0e10cSrcweir const MetaClipRegionAction* pA = (const MetaClipRegionAction*) pAction; 881*cdf0e10cSrcweir 882*cdf0e10cSrcweir if( pA->IsClipping() ) 883*cdf0e10cSrcweir { 884*cdf0e10cSrcweir if( pA->GetRegion().IsEmpty() ) 885*cdf0e10cSrcweir m_rOuterFace.SetClipRegion( basegfx::B2DPolyPolygon() ); 886*cdf0e10cSrcweir else 887*cdf0e10cSrcweir { 888*cdf0e10cSrcweir Region aReg( pA->GetRegion() ); 889*cdf0e10cSrcweir m_rOuterFace.SetClipRegion( aReg.ConvertToB2DPolyPolygon() ); 890*cdf0e10cSrcweir } 891*cdf0e10cSrcweir } 892*cdf0e10cSrcweir else 893*cdf0e10cSrcweir m_rOuterFace.SetClipRegion(); 894*cdf0e10cSrcweir } 895*cdf0e10cSrcweir break; 896*cdf0e10cSrcweir 897*cdf0e10cSrcweir case( META_ISECTRECTCLIPREGION_ACTION ): 898*cdf0e10cSrcweir { 899*cdf0e10cSrcweir const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pAction; 900*cdf0e10cSrcweir m_rOuterFace.IntersectClipRegion( pA->GetRect() ); 901*cdf0e10cSrcweir } 902*cdf0e10cSrcweir break; 903*cdf0e10cSrcweir 904*cdf0e10cSrcweir case( META_ISECTREGIONCLIPREGION_ACTION ): 905*cdf0e10cSrcweir { 906*cdf0e10cSrcweir const MetaISectRegionClipRegionAction* pA = (const MetaISectRegionClipRegionAction*) pAction; 907*cdf0e10cSrcweir Region aReg( pA->GetRegion() ); 908*cdf0e10cSrcweir m_rOuterFace.IntersectClipRegion( aReg.ConvertToB2DPolyPolygon() ); 909*cdf0e10cSrcweir } 910*cdf0e10cSrcweir break; 911*cdf0e10cSrcweir 912*cdf0e10cSrcweir case( META_MOVECLIPREGION_ACTION ): 913*cdf0e10cSrcweir { 914*cdf0e10cSrcweir const MetaMoveClipRegionAction* pA = (const MetaMoveClipRegionAction*) pAction; 915*cdf0e10cSrcweir m_rOuterFace.MoveClipRegion( pA->GetHorzMove(), pA->GetVertMove() ); 916*cdf0e10cSrcweir } 917*cdf0e10cSrcweir break; 918*cdf0e10cSrcweir 919*cdf0e10cSrcweir case( META_MAPMODE_ACTION ): 920*cdf0e10cSrcweir { 921*cdf0e10cSrcweir const_cast< MetaAction* >( pAction )->Execute( pDummyVDev ); 922*cdf0e10cSrcweir m_rOuterFace.SetMapMode( pDummyVDev->GetMapMode() ); 923*cdf0e10cSrcweir } 924*cdf0e10cSrcweir break; 925*cdf0e10cSrcweir 926*cdf0e10cSrcweir case( META_LINECOLOR_ACTION ): 927*cdf0e10cSrcweir { 928*cdf0e10cSrcweir const MetaLineColorAction* pA = (const MetaLineColorAction*) pAction; 929*cdf0e10cSrcweir 930*cdf0e10cSrcweir if( pA->IsSetting() ) 931*cdf0e10cSrcweir m_rOuterFace.SetLineColor( pA->GetColor() ); 932*cdf0e10cSrcweir else 933*cdf0e10cSrcweir m_rOuterFace.SetLineColor(); 934*cdf0e10cSrcweir } 935*cdf0e10cSrcweir break; 936*cdf0e10cSrcweir 937*cdf0e10cSrcweir case( META_FILLCOLOR_ACTION ): 938*cdf0e10cSrcweir { 939*cdf0e10cSrcweir const MetaFillColorAction* pA = (const MetaFillColorAction*) pAction; 940*cdf0e10cSrcweir 941*cdf0e10cSrcweir if( pA->IsSetting() ) 942*cdf0e10cSrcweir m_rOuterFace.SetFillColor( pA->GetColor() ); 943*cdf0e10cSrcweir else 944*cdf0e10cSrcweir m_rOuterFace.SetFillColor(); 945*cdf0e10cSrcweir } 946*cdf0e10cSrcweir break; 947*cdf0e10cSrcweir 948*cdf0e10cSrcweir case( META_TEXTLINECOLOR_ACTION ): 949*cdf0e10cSrcweir { 950*cdf0e10cSrcweir const MetaTextLineColorAction* pA = (const MetaTextLineColorAction*) pAction; 951*cdf0e10cSrcweir 952*cdf0e10cSrcweir if( pA->IsSetting() ) 953*cdf0e10cSrcweir m_rOuterFace.SetTextLineColor( pA->GetColor() ); 954*cdf0e10cSrcweir else 955*cdf0e10cSrcweir m_rOuterFace.SetTextLineColor(); 956*cdf0e10cSrcweir } 957*cdf0e10cSrcweir break; 958*cdf0e10cSrcweir 959*cdf0e10cSrcweir case( META_OVERLINECOLOR_ACTION ): 960*cdf0e10cSrcweir { 961*cdf0e10cSrcweir const MetaOverlineColorAction* pA = (const MetaOverlineColorAction*) pAction; 962*cdf0e10cSrcweir 963*cdf0e10cSrcweir if( pA->IsSetting() ) 964*cdf0e10cSrcweir m_rOuterFace.SetOverlineColor( pA->GetColor() ); 965*cdf0e10cSrcweir else 966*cdf0e10cSrcweir m_rOuterFace.SetOverlineColor(); 967*cdf0e10cSrcweir } 968*cdf0e10cSrcweir break; 969*cdf0e10cSrcweir 970*cdf0e10cSrcweir case( META_TEXTFILLCOLOR_ACTION ): 971*cdf0e10cSrcweir { 972*cdf0e10cSrcweir const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*) pAction; 973*cdf0e10cSrcweir 974*cdf0e10cSrcweir if( pA->IsSetting() ) 975*cdf0e10cSrcweir m_rOuterFace.SetTextFillColor( pA->GetColor() ); 976*cdf0e10cSrcweir else 977*cdf0e10cSrcweir m_rOuterFace.SetTextFillColor(); 978*cdf0e10cSrcweir } 979*cdf0e10cSrcweir break; 980*cdf0e10cSrcweir 981*cdf0e10cSrcweir case( META_TEXTCOLOR_ACTION ): 982*cdf0e10cSrcweir { 983*cdf0e10cSrcweir const MetaTextColorAction* pA = (const MetaTextColorAction*) pAction; 984*cdf0e10cSrcweir m_rOuterFace.SetTextColor( pA->GetColor() ); 985*cdf0e10cSrcweir } 986*cdf0e10cSrcweir break; 987*cdf0e10cSrcweir 988*cdf0e10cSrcweir case( META_TEXTALIGN_ACTION ): 989*cdf0e10cSrcweir { 990*cdf0e10cSrcweir const MetaTextAlignAction* pA = (const MetaTextAlignAction*) pAction; 991*cdf0e10cSrcweir m_rOuterFace.SetTextAlign( pA->GetTextAlign() ); 992*cdf0e10cSrcweir } 993*cdf0e10cSrcweir break; 994*cdf0e10cSrcweir 995*cdf0e10cSrcweir case( META_FONT_ACTION ): 996*cdf0e10cSrcweir { 997*cdf0e10cSrcweir const MetaFontAction* pA = (const MetaFontAction*) pAction; 998*cdf0e10cSrcweir m_rOuterFace.SetFont( pA->GetFont() ); 999*cdf0e10cSrcweir } 1000*cdf0e10cSrcweir break; 1001*cdf0e10cSrcweir 1002*cdf0e10cSrcweir case( META_PUSH_ACTION ): 1003*cdf0e10cSrcweir { 1004*cdf0e10cSrcweir const MetaPushAction* pA = (const MetaPushAction*) pAction; 1005*cdf0e10cSrcweir 1006*cdf0e10cSrcweir pDummyVDev->Push( pA->GetFlags() ); 1007*cdf0e10cSrcweir m_rOuterFace.Push( pA->GetFlags() ); 1008*cdf0e10cSrcweir } 1009*cdf0e10cSrcweir break; 1010*cdf0e10cSrcweir 1011*cdf0e10cSrcweir case( META_POP_ACTION ): 1012*cdf0e10cSrcweir { 1013*cdf0e10cSrcweir pDummyVDev->Pop(); 1014*cdf0e10cSrcweir m_rOuterFace.Pop(); 1015*cdf0e10cSrcweir } 1016*cdf0e10cSrcweir break; 1017*cdf0e10cSrcweir 1018*cdf0e10cSrcweir case( META_LAYOUTMODE_ACTION ): 1019*cdf0e10cSrcweir { 1020*cdf0e10cSrcweir const MetaLayoutModeAction* pA = (const MetaLayoutModeAction*) pAction; 1021*cdf0e10cSrcweir m_rOuterFace.SetLayoutMode( pA->GetLayoutMode() ); 1022*cdf0e10cSrcweir } 1023*cdf0e10cSrcweir break; 1024*cdf0e10cSrcweir 1025*cdf0e10cSrcweir case META_TEXTLANGUAGE_ACTION: 1026*cdf0e10cSrcweir { 1027*cdf0e10cSrcweir const MetaTextLanguageAction* pA = (const MetaTextLanguageAction*) pAction; 1028*cdf0e10cSrcweir m_rOuterFace.SetDigitLanguage( pA->GetTextLanguage() ); 1029*cdf0e10cSrcweir } 1030*cdf0e10cSrcweir break; 1031*cdf0e10cSrcweir 1032*cdf0e10cSrcweir case( META_WALLPAPER_ACTION ): 1033*cdf0e10cSrcweir { 1034*cdf0e10cSrcweir const MetaWallpaperAction* pA = (const MetaWallpaperAction*) pAction; 1035*cdf0e10cSrcweir m_rOuterFace.DrawWallpaper( pA->GetRect(), pA->GetWallpaper() ); 1036*cdf0e10cSrcweir } 1037*cdf0e10cSrcweir break; 1038*cdf0e10cSrcweir 1039*cdf0e10cSrcweir case( META_RASTEROP_ACTION ): 1040*cdf0e10cSrcweir { 1041*cdf0e10cSrcweir // !!! >>> we don't want to support this actions 1042*cdf0e10cSrcweir } 1043*cdf0e10cSrcweir break; 1044*cdf0e10cSrcweir 1045*cdf0e10cSrcweir case( META_REFPOINT_ACTION ): 1046*cdf0e10cSrcweir { 1047*cdf0e10cSrcweir // !!! >>> we don't want to support this actions 1048*cdf0e10cSrcweir } 1049*cdf0e10cSrcweir break; 1050*cdf0e10cSrcweir 1051*cdf0e10cSrcweir case( META_RENDERGRAPHIC_ACTION ): 1052*cdf0e10cSrcweir { 1053*cdf0e10cSrcweir const MetaRenderGraphicAction* pA = static_cast< const MetaRenderGraphicAction* >( pAction ); 1054*cdf0e10cSrcweir const ::vcl::RenderGraphicRasterizer aRasterizer( pA->GetRenderGraphic() ); 1055*cdf0e10cSrcweir 1056*cdf0e10cSrcweir implWriteBitmapEx( pA->GetPoint(), pA->GetSize(), 1057*cdf0e10cSrcweir aRasterizer.Rasterize( pDummyVDev->LogicToPixel( pA->GetSize() ) ), 1058*cdf0e10cSrcweir pDummyVDev, i_rContext ); 1059*cdf0e10cSrcweir } 1060*cdf0e10cSrcweir break; 1061*cdf0e10cSrcweir 1062*cdf0e10cSrcweir default: 1063*cdf0e10cSrcweir // #i24604# Made assertion fire only once per 1064*cdf0e10cSrcweir // metafile. The asserted actions here are all 1065*cdf0e10cSrcweir // deprecated 1066*cdf0e10cSrcweir if( !bAssertionFired ) 1067*cdf0e10cSrcweir { 1068*cdf0e10cSrcweir bAssertionFired = true; 1069*cdf0e10cSrcweir DBG_ERROR( "PDFExport::ImplWriteActions: deprecated and unsupported MetaAction encountered" ); 1070*cdf0e10cSrcweir } 1071*cdf0e10cSrcweir break; 1072*cdf0e10cSrcweir } 1073*cdf0e10cSrcweir i++; 1074*cdf0e10cSrcweir } 1075*cdf0e10cSrcweir } 1076*cdf0e10cSrcweir 1077*cdf0e10cSrcweir delete pPrivateDevice; 1078*cdf0e10cSrcweir } 1079*cdf0e10cSrcweir 1080*cdf0e10cSrcweir // Encryption methods 1081*cdf0e10cSrcweir 1082*cdf0e10cSrcweir /* a crutch to transport an rtlDigest safely though UNO API 1083*cdf0e10cSrcweir this is needed for the PDF export dialog, which otherwise would have to pass 1084*cdf0e10cSrcweir clear text passwords down till they can be used in PDFWriter. Unfortunately 1085*cdf0e10cSrcweir the MD5 sum of the password (which is needed to create the PDF encryption key) 1086*cdf0e10cSrcweir is not sufficient, since an rtl MD5 digest cannot be created in an arbitrary state 1087*cdf0e10cSrcweir which would be needed in PDFWriterImpl::computeEncryptionKey. 1088*cdf0e10cSrcweir */ 1089*cdf0e10cSrcweir class EncHashTransporter : public cppu::WeakImplHelper1 < com::sun::star::beans::XMaterialHolder > 1090*cdf0e10cSrcweir { 1091*cdf0e10cSrcweir rtlDigest maUDigest; 1092*cdf0e10cSrcweir sal_IntPtr maID; 1093*cdf0e10cSrcweir std::vector< sal_uInt8 > maOValue; 1094*cdf0e10cSrcweir 1095*cdf0e10cSrcweir static std::map< sal_IntPtr, EncHashTransporter* > sTransporters; 1096*cdf0e10cSrcweir public: 1097*cdf0e10cSrcweir EncHashTransporter() 1098*cdf0e10cSrcweir : maUDigest( rtl_digest_createMD5() ) 1099*cdf0e10cSrcweir { 1100*cdf0e10cSrcweir maID = reinterpret_cast< sal_IntPtr >(this); 1101*cdf0e10cSrcweir while( sTransporters.find( maID ) != sTransporters.end() ) // paranoia mode 1102*cdf0e10cSrcweir maID++; 1103*cdf0e10cSrcweir sTransporters[ maID ] = this; 1104*cdf0e10cSrcweir } 1105*cdf0e10cSrcweir 1106*cdf0e10cSrcweir virtual ~EncHashTransporter() 1107*cdf0e10cSrcweir { 1108*cdf0e10cSrcweir sTransporters.erase( maID ); 1109*cdf0e10cSrcweir if( maUDigest ) 1110*cdf0e10cSrcweir rtl_digest_destroyMD5( maUDigest ); 1111*cdf0e10cSrcweir OSL_TRACE( "EncHashTransporter freed\n" ); 1112*cdf0e10cSrcweir } 1113*cdf0e10cSrcweir 1114*cdf0e10cSrcweir rtlDigest getUDigest() const { return maUDigest; }; 1115*cdf0e10cSrcweir std::vector< sal_uInt8 >& getOValue() { return maOValue; } 1116*cdf0e10cSrcweir void invalidate() 1117*cdf0e10cSrcweir { 1118*cdf0e10cSrcweir if( maUDigest ) 1119*cdf0e10cSrcweir { 1120*cdf0e10cSrcweir rtl_digest_destroyMD5( maUDigest ); 1121*cdf0e10cSrcweir maUDigest = NULL; 1122*cdf0e10cSrcweir } 1123*cdf0e10cSrcweir } 1124*cdf0e10cSrcweir 1125*cdf0e10cSrcweir // XMaterialHolder 1126*cdf0e10cSrcweir virtual uno::Any SAL_CALL getMaterial() throw() 1127*cdf0e10cSrcweir { 1128*cdf0e10cSrcweir return uno::makeAny( sal_Int64(maID) ); 1129*cdf0e10cSrcweir } 1130*cdf0e10cSrcweir 1131*cdf0e10cSrcweir static EncHashTransporter* getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& ); 1132*cdf0e10cSrcweir 1133*cdf0e10cSrcweir }; 1134*cdf0e10cSrcweir 1135*cdf0e10cSrcweir std::map< sal_IntPtr, EncHashTransporter* > EncHashTransporter::sTransporters; 1136*cdf0e10cSrcweir 1137*cdf0e10cSrcweir EncHashTransporter* EncHashTransporter::getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& xRef ) 1138*cdf0e10cSrcweir { 1139*cdf0e10cSrcweir EncHashTransporter* pResult = NULL; 1140*cdf0e10cSrcweir if( xRef.is() ) 1141*cdf0e10cSrcweir { 1142*cdf0e10cSrcweir uno::Any aMat( xRef->getMaterial() ); 1143*cdf0e10cSrcweir sal_Int64 nMat = 0; 1144*cdf0e10cSrcweir if( aMat >>= nMat ) 1145*cdf0e10cSrcweir { 1146*cdf0e10cSrcweir std::map< sal_IntPtr, EncHashTransporter* >::iterator it = sTransporters.find( static_cast<sal_IntPtr>(nMat) ); 1147*cdf0e10cSrcweir if( it != sTransporters.end() ) 1148*cdf0e10cSrcweir pResult = it->second; 1149*cdf0e10cSrcweir } 1150*cdf0e10cSrcweir } 1151*cdf0e10cSrcweir return pResult; 1152*cdf0e10cSrcweir } 1153*cdf0e10cSrcweir 1154*cdf0e10cSrcweir sal_Bool PDFWriterImpl::checkEncryptionBufferSize( register sal_Int32 newSize ) 1155*cdf0e10cSrcweir { 1156*cdf0e10cSrcweir if( m_nEncryptionBufferSize < newSize ) 1157*cdf0e10cSrcweir { 1158*cdf0e10cSrcweir /* reallocate the buffer, the used function allocate as rtl_allocateMemory 1159*cdf0e10cSrcweir if the pointer parameter is NULL */ 1160*cdf0e10cSrcweir m_pEncryptionBuffer = (sal_uInt8*)rtl_reallocateMemory( m_pEncryptionBuffer, newSize ); 1161*cdf0e10cSrcweir if( m_pEncryptionBuffer ) 1162*cdf0e10cSrcweir m_nEncryptionBufferSize = newSize; 1163*cdf0e10cSrcweir else 1164*cdf0e10cSrcweir m_nEncryptionBufferSize = 0; 1165*cdf0e10cSrcweir } 1166*cdf0e10cSrcweir return ( m_nEncryptionBufferSize != 0 ); 1167*cdf0e10cSrcweir } 1168*cdf0e10cSrcweir 1169*cdf0e10cSrcweir void PDFWriterImpl::checkAndEnableStreamEncryption( register sal_Int32 nObject ) 1170*cdf0e10cSrcweir { 1171*cdf0e10cSrcweir if( m_aContext.Encryption.Encrypt() ) 1172*cdf0e10cSrcweir { 1173*cdf0e10cSrcweir m_bEncryptThisStream = true; 1174*cdf0e10cSrcweir sal_Int32 i = m_nKeyLength; 1175*cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject; 1176*cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); 1177*cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); 1178*cdf0e10cSrcweir //the other location of m_nEncryptionKey are already set to 0, our fixed generation number 1179*cdf0e10cSrcweir // do the MD5 hash 1180*cdf0e10cSrcweir sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; 1181*cdf0e10cSrcweir // the i+2 to take into account the generation number, always zero 1182*cdf0e10cSrcweir rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) ); 1183*cdf0e10cSrcweir // initialize the RC4 with the key 1184*cdf0e10cSrcweir // key legth: see algoritm 3.1, step 4: (N+5) max 16 1185*cdf0e10cSrcweir rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); 1186*cdf0e10cSrcweir } 1187*cdf0e10cSrcweir } 1188*cdf0e10cSrcweir 1189*cdf0e10cSrcweir void PDFWriterImpl::enableStringEncryption( register sal_Int32 nObject ) 1190*cdf0e10cSrcweir { 1191*cdf0e10cSrcweir if( m_aContext.Encryption.Encrypt() ) 1192*cdf0e10cSrcweir { 1193*cdf0e10cSrcweir sal_Int32 i = m_nKeyLength; 1194*cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject; 1195*cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); 1196*cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); 1197*cdf0e10cSrcweir //the other location of m_nEncryptionKey are already set to 0, our fixed generation number 1198*cdf0e10cSrcweir // do the MD5 hash 1199*cdf0e10cSrcweir sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; 1200*cdf0e10cSrcweir // the i+2 to take into account the generation number, always zero 1201*cdf0e10cSrcweir rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) ); 1202*cdf0e10cSrcweir // initialize the RC4 with the key 1203*cdf0e10cSrcweir // key legth: see algoritm 3.1, step 4: (N+5) max 16 1204*cdf0e10cSrcweir rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); 1205*cdf0e10cSrcweir } 1206*cdf0e10cSrcweir } 1207*cdf0e10cSrcweir 1208*cdf0e10cSrcweir /* init the encryption engine 1209*cdf0e10cSrcweir 1. init the document id, used both for building the document id and for building the encryption key(s) 1210*cdf0e10cSrcweir 2. build the encryption key following algorithms described in the PDF specification 1211*cdf0e10cSrcweir */ 1212*cdf0e10cSrcweir uno::Reference< beans::XMaterialHolder > PDFWriterImpl::initEncryption( const rtl::OUString& i_rOwnerPassword, 1213*cdf0e10cSrcweir const rtl::OUString& i_rUserPassword, 1214*cdf0e10cSrcweir bool b128Bit 1215*cdf0e10cSrcweir ) 1216*cdf0e10cSrcweir { 1217*cdf0e10cSrcweir uno::Reference< beans::XMaterialHolder > xResult; 1218*cdf0e10cSrcweir if( i_rOwnerPassword.getLength() || i_rUserPassword.getLength() ) 1219*cdf0e10cSrcweir { 1220*cdf0e10cSrcweir EncHashTransporter* pTransporter = new EncHashTransporter; 1221*cdf0e10cSrcweir xResult = pTransporter; 1222*cdf0e10cSrcweir 1223*cdf0e10cSrcweir // get padded passwords 1224*cdf0e10cSrcweir sal_uInt8 aPadUPW[ENCRYPTED_PWD_SIZE], aPadOPW[ENCRYPTED_PWD_SIZE]; 1225*cdf0e10cSrcweir padPassword( i_rOwnerPassword.getLength() ? i_rOwnerPassword : i_rUserPassword, aPadOPW ); 1226*cdf0e10cSrcweir padPassword( i_rUserPassword, aPadUPW ); 1227*cdf0e10cSrcweir sal_Int32 nKeyLength = SECUR_40BIT_KEY; 1228*cdf0e10cSrcweir if( b128Bit ) 1229*cdf0e10cSrcweir nKeyLength = SECUR_128BIT_KEY; 1230*cdf0e10cSrcweir 1231*cdf0e10cSrcweir if( computeODictionaryValue( aPadOPW, aPadUPW, pTransporter->getOValue(), nKeyLength ) ) 1232*cdf0e10cSrcweir { 1233*cdf0e10cSrcweir rtlDigest aDig = pTransporter->getUDigest(); 1234*cdf0e10cSrcweir if( rtl_digest_updateMD5( aDig, aPadUPW, ENCRYPTED_PWD_SIZE ) != rtl_Digest_E_None ) 1235*cdf0e10cSrcweir xResult.clear(); 1236*cdf0e10cSrcweir } 1237*cdf0e10cSrcweir else 1238*cdf0e10cSrcweir xResult.clear(); 1239*cdf0e10cSrcweir 1240*cdf0e10cSrcweir // trash temporary padded cleartext PWDs 1241*cdf0e10cSrcweir rtl_zeroMemory( aPadOPW, sizeof(aPadOPW) ); 1242*cdf0e10cSrcweir rtl_zeroMemory( aPadUPW, sizeof(aPadUPW) ); 1243*cdf0e10cSrcweir 1244*cdf0e10cSrcweir } 1245*cdf0e10cSrcweir return xResult; 1246*cdf0e10cSrcweir } 1247*cdf0e10cSrcweir 1248*cdf0e10cSrcweir bool PDFWriterImpl::prepareEncryption( const uno::Reference< beans::XMaterialHolder >& xEnc ) 1249*cdf0e10cSrcweir { 1250*cdf0e10cSrcweir bool bSuccess = false; 1251*cdf0e10cSrcweir EncHashTransporter* pTransporter = EncHashTransporter::getEncHashTransporter( xEnc ); 1252*cdf0e10cSrcweir if( pTransporter ) 1253*cdf0e10cSrcweir { 1254*cdf0e10cSrcweir sal_Int32 nKeyLength = 0, nRC4KeyLength = 0; 1255*cdf0e10cSrcweir sal_Int32 nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, nKeyLength, nRC4KeyLength ); 1256*cdf0e10cSrcweir m_aContext.Encryption.OValue = pTransporter->getOValue(); 1257*cdf0e10cSrcweir bSuccess = computeUDictionaryValue( pTransporter, m_aContext.Encryption, nKeyLength, nAccessPermissions ); 1258*cdf0e10cSrcweir } 1259*cdf0e10cSrcweir if( ! bSuccess ) 1260*cdf0e10cSrcweir { 1261*cdf0e10cSrcweir m_aContext.Encryption.OValue.clear(); 1262*cdf0e10cSrcweir m_aContext.Encryption.UValue.clear(); 1263*cdf0e10cSrcweir m_aContext.Encryption.EncryptionKey.clear(); 1264*cdf0e10cSrcweir } 1265*cdf0e10cSrcweir return bSuccess; 1266*cdf0e10cSrcweir } 1267*cdf0e10cSrcweir 1268*cdf0e10cSrcweir sal_Int32 PDFWriterImpl::computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties, 1269*cdf0e10cSrcweir sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength ) 1270*cdf0e10cSrcweir { 1271*cdf0e10cSrcweir /* 1272*cdf0e10cSrcweir 2) compute the access permissions, in numerical form 1273*cdf0e10cSrcweir 1274*cdf0e10cSrcweir the default value depends on the revision 2 (40 bit) or 3 (128 bit security): 1275*cdf0e10cSrcweir - for 40 bit security the unused bit must be set to 1, since they are not used 1276*cdf0e10cSrcweir - for 128 bit security the same bit must be preset to 0 and set later if needed 1277*cdf0e10cSrcweir according to the table 3.15, pdf v 1.4 */ 1278*cdf0e10cSrcweir sal_Int32 nAccessPermissions = ( i_rProperties.Security128bit ) ? 0xfffff0c0 : 0xffffffc0 ; 1279*cdf0e10cSrcweir 1280*cdf0e10cSrcweir /* check permissions for 40 bit security case */ 1281*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanPrintTheDocument ) ? 1 << 2 : 0; 1282*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanModifyTheContent ) ? 1 << 3 : 0; 1283*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanCopyOrExtract ) ? 1 << 4 : 0; 1284*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanAddOrModify ) ? 1 << 5 : 0; 1285*cdf0e10cSrcweir o_rKeyLength = SECUR_40BIT_KEY; 1286*cdf0e10cSrcweir o_rRC4KeyLength = SECUR_40BIT_KEY+5; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 5 1287*cdf0e10cSrcweir 1288*cdf0e10cSrcweir if( i_rProperties.Security128bit ) 1289*cdf0e10cSrcweir { 1290*cdf0e10cSrcweir o_rKeyLength = SECUR_128BIT_KEY; 1291*cdf0e10cSrcweir o_rRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16, thus maximum 1292*cdf0e10cSrcweir // permitted value is 16 1293*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanFillInteractive ) ? 1 << 8 : 0; 1294*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanExtractForAccessibility ) ? 1 << 9 : 0; 1295*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanAssemble ) ? 1 << 10 : 0; 1296*cdf0e10cSrcweir nAccessPermissions |= ( i_rProperties.CanPrintFull ) ? 1 << 11 : 0; 1297*cdf0e10cSrcweir } 1298*cdf0e10cSrcweir return nAccessPermissions; 1299*cdf0e10cSrcweir } 1300*cdf0e10cSrcweir 1301*cdf0e10cSrcweir /************************************************************* 1302*cdf0e10cSrcweir begin i12626 methods 1303*cdf0e10cSrcweir 1304*cdf0e10cSrcweir Implements Algorithm 3.2, step 1 only 1305*cdf0e10cSrcweir */ 1306*cdf0e10cSrcweir void PDFWriterImpl::padPassword( const rtl::OUString& i_rPassword, sal_uInt8* o_pPaddedPW ) 1307*cdf0e10cSrcweir { 1308*cdf0e10cSrcweir // get ansi-1252 version of the password string CHECKIT ! i12626 1309*cdf0e10cSrcweir rtl::OString aString( rtl::OUStringToOString( i_rPassword, RTL_TEXTENCODING_MS_1252 ) ); 1310*cdf0e10cSrcweir 1311*cdf0e10cSrcweir //copy the string to the target 1312*cdf0e10cSrcweir sal_Int32 nToCopy = ( aString.getLength() < ENCRYPTED_PWD_SIZE ) ? aString.getLength() : ENCRYPTED_PWD_SIZE; 1313*cdf0e10cSrcweir sal_Int32 nCurrentChar; 1314*cdf0e10cSrcweir 1315*cdf0e10cSrcweir for( nCurrentChar = 0; nCurrentChar < nToCopy; nCurrentChar++ ) 1316*cdf0e10cSrcweir o_pPaddedPW[nCurrentChar] = (sal_uInt8)( aString.getStr()[nCurrentChar] ); 1317*cdf0e10cSrcweir 1318*cdf0e10cSrcweir //pad it with standard byte string 1319*cdf0e10cSrcweir sal_Int32 i,y; 1320*cdf0e10cSrcweir for( i = nCurrentChar, y = 0 ; i < ENCRYPTED_PWD_SIZE; i++, y++ ) 1321*cdf0e10cSrcweir o_pPaddedPW[i] = s_nPadString[y]; 1322*cdf0e10cSrcweir 1323*cdf0e10cSrcweir // trash memory of temporary clear text password 1324*cdf0e10cSrcweir rtl_zeroMemory( (sal_Char*)aString.getStr(), aString.getLength() ); 1325*cdf0e10cSrcweir } 1326*cdf0e10cSrcweir 1327*cdf0e10cSrcweir /********************************** 1328*cdf0e10cSrcweir Algorithm 3.2 Compute the encryption key used 1329*cdf0e10cSrcweir 1330*cdf0e10cSrcweir step 1 should already be done before calling, the paThePaddedPassword parameter should contain 1331*cdf0e10cSrcweir the padded password and must be 32 byte long, the encryption key is returned into the paEncryptionKey parameter, 1332*cdf0e10cSrcweir it will be 16 byte long for 128 bit security; for 40 bit security only the first 5 bytes are used 1333*cdf0e10cSrcweir 1334*cdf0e10cSrcweir TODO: in pdf ver 1.5 and 1.6 the step 6 is different, should be implemented. See spec. 1335*cdf0e10cSrcweir 1336*cdf0e10cSrcweir */ 1337*cdf0e10cSrcweir bool PDFWriterImpl::computeEncryptionKey( EncHashTransporter* i_pTransporter, vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, sal_Int32 i_nAccessPermissions ) 1338*cdf0e10cSrcweir { 1339*cdf0e10cSrcweir bool bSuccess = true; 1340*cdf0e10cSrcweir sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; 1341*cdf0e10cSrcweir 1342*cdf0e10cSrcweir // transporter contains an MD5 digest with the padded user password already 1343*cdf0e10cSrcweir rtlDigest aDigest = i_pTransporter->getUDigest(); 1344*cdf0e10cSrcweir rtlDigestError nError = rtl_Digest_E_None; 1345*cdf0e10cSrcweir if( aDigest ) 1346*cdf0e10cSrcweir { 1347*cdf0e10cSrcweir //step 3 1348*cdf0e10cSrcweir if( ! io_rProperties.OValue.empty() ) 1349*cdf0e10cSrcweir nError = rtl_digest_updateMD5( aDigest, &io_rProperties.OValue[0] , sal_Int32(io_rProperties.OValue.size()) ); 1350*cdf0e10cSrcweir else 1351*cdf0e10cSrcweir bSuccess = false; 1352*cdf0e10cSrcweir //Step 4 1353*cdf0e10cSrcweir sal_uInt8 nPerm[4]; 1354*cdf0e10cSrcweir 1355*cdf0e10cSrcweir nPerm[0] = (sal_uInt8)i_nAccessPermissions; 1356*cdf0e10cSrcweir nPerm[1] = (sal_uInt8)( i_nAccessPermissions >> 8 ); 1357*cdf0e10cSrcweir nPerm[2] = (sal_uInt8)( i_nAccessPermissions >> 16 ); 1358*cdf0e10cSrcweir nPerm[3] = (sal_uInt8)( i_nAccessPermissions >> 24 ); 1359*cdf0e10cSrcweir 1360*cdf0e10cSrcweir if( nError == rtl_Digest_E_None ) 1361*cdf0e10cSrcweir nError = rtl_digest_updateMD5( aDigest, nPerm , sizeof( nPerm ) ); 1362*cdf0e10cSrcweir 1363*cdf0e10cSrcweir //step 5, get the document ID, binary form 1364*cdf0e10cSrcweir if( nError == rtl_Digest_E_None ) 1365*cdf0e10cSrcweir nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) ); 1366*cdf0e10cSrcweir //get the digest 1367*cdf0e10cSrcweir if( nError == rtl_Digest_E_None ) 1368*cdf0e10cSrcweir { 1369*cdf0e10cSrcweir rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); 1370*cdf0e10cSrcweir 1371*cdf0e10cSrcweir //step 6, only if 128 bit 1372*cdf0e10cSrcweir if( io_rProperties.Security128bit ) 1373*cdf0e10cSrcweir { 1374*cdf0e10cSrcweir for( sal_Int32 i = 0; i < 50; i++ ) 1375*cdf0e10cSrcweir { 1376*cdf0e10cSrcweir nError = rtl_digest_updateMD5( aDigest, &nMD5Sum, sizeof( nMD5Sum ) ); 1377*cdf0e10cSrcweir if( nError != rtl_Digest_E_None ) 1378*cdf0e10cSrcweir { 1379*cdf0e10cSrcweir bSuccess = false; 1380*cdf0e10cSrcweir break; 1381*cdf0e10cSrcweir } 1382*cdf0e10cSrcweir rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); 1383*cdf0e10cSrcweir } 1384*cdf0e10cSrcweir } 1385*cdf0e10cSrcweir } 1386*cdf0e10cSrcweir } 1387*cdf0e10cSrcweir else 1388*cdf0e10cSrcweir bSuccess = false; 1389*cdf0e10cSrcweir 1390*cdf0e10cSrcweir i_pTransporter->invalidate(); 1391*cdf0e10cSrcweir 1392*cdf0e10cSrcweir //Step 7 1393*cdf0e10cSrcweir if( bSuccess ) 1394*cdf0e10cSrcweir { 1395*cdf0e10cSrcweir io_rProperties.EncryptionKey.resize( MAXIMUM_RC4_KEY_LENGTH ); 1396*cdf0e10cSrcweir for( sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++ ) 1397*cdf0e10cSrcweir io_rProperties.EncryptionKey[i] = nMD5Sum[i]; 1398*cdf0e10cSrcweir } 1399*cdf0e10cSrcweir else 1400*cdf0e10cSrcweir io_rProperties.EncryptionKey.clear(); 1401*cdf0e10cSrcweir 1402*cdf0e10cSrcweir return bSuccess; 1403*cdf0e10cSrcweir } 1404*cdf0e10cSrcweir 1405*cdf0e10cSrcweir /********************************** 1406*cdf0e10cSrcweir Algorithm 3.3 Compute the encryption dictionary /O value, save into the class data member 1407*cdf0e10cSrcweir the step numbers down here correspond to the ones in PDF v.1.4 specfication 1408*cdf0e10cSrcweir */ 1409*cdf0e10cSrcweir bool PDFWriterImpl::computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, 1410*cdf0e10cSrcweir const sal_uInt8* i_pPaddedUserPassword, 1411*cdf0e10cSrcweir std::vector< sal_uInt8 >& io_rOValue, 1412*cdf0e10cSrcweir sal_Int32 i_nKeyLength 1413*cdf0e10cSrcweir ) 1414*cdf0e10cSrcweir { 1415*cdf0e10cSrcweir bool bSuccess = true; 1416*cdf0e10cSrcweir 1417*cdf0e10cSrcweir io_rOValue.resize( ENCRYPTED_PWD_SIZE ); 1418*cdf0e10cSrcweir 1419*cdf0e10cSrcweir rtlDigest aDigest = rtl_digest_createMD5(); 1420*cdf0e10cSrcweir rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); 1421*cdf0e10cSrcweir if( aDigest && aCipher) 1422*cdf0e10cSrcweir { 1423*cdf0e10cSrcweir //step 1 already done, data is in i_pPaddedOwnerPassword 1424*cdf0e10cSrcweir //step 2 1425*cdf0e10cSrcweir 1426*cdf0e10cSrcweir rtlDigestError nError = rtl_digest_updateMD5( aDigest, i_pPaddedOwnerPassword, ENCRYPTED_PWD_SIZE ); 1427*cdf0e10cSrcweir if( nError == rtl_Digest_E_None ) 1428*cdf0e10cSrcweir { 1429*cdf0e10cSrcweir sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; 1430*cdf0e10cSrcweir 1431*cdf0e10cSrcweir rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) ); 1432*cdf0e10cSrcweir //step 3, only if 128 bit 1433*cdf0e10cSrcweir if( i_nKeyLength == SECUR_128BIT_KEY ) 1434*cdf0e10cSrcweir { 1435*cdf0e10cSrcweir sal_Int32 i; 1436*cdf0e10cSrcweir for( i = 0; i < 50; i++ ) 1437*cdf0e10cSrcweir { 1438*cdf0e10cSrcweir nError = rtl_digest_updateMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); 1439*cdf0e10cSrcweir if( nError != rtl_Digest_E_None ) 1440*cdf0e10cSrcweir { 1441*cdf0e10cSrcweir bSuccess = false; 1442*cdf0e10cSrcweir break; 1443*cdf0e10cSrcweir } 1444*cdf0e10cSrcweir rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); 1445*cdf0e10cSrcweir } 1446*cdf0e10cSrcweir } 1447*cdf0e10cSrcweir //Step 4, the key is in nMD5Sum 1448*cdf0e10cSrcweir //step 5 already done, data is in i_pPaddedUserPassword 1449*cdf0e10cSrcweir //step 6 1450*cdf0e10cSrcweir rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, 1451*cdf0e10cSrcweir nMD5Sum, i_nKeyLength , NULL, 0 ); 1452*cdf0e10cSrcweir // encrypt the user password using the key set above 1453*cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( aCipher, i_pPaddedUserPassword, ENCRYPTED_PWD_SIZE, // the data to be encrypted 1454*cdf0e10cSrcweir &io_rOValue[0], sal_Int32(io_rOValue.size()) ); //encrypted data 1455*cdf0e10cSrcweir //Step 7, only if 128 bit 1456*cdf0e10cSrcweir if( i_nKeyLength == SECUR_128BIT_KEY ) 1457*cdf0e10cSrcweir { 1458*cdf0e10cSrcweir sal_uInt32 i, y; 1459*cdf0e10cSrcweir sal_uInt8 nLocalKey[ SECUR_128BIT_KEY ]; // 16 = 128 bit key 1460*cdf0e10cSrcweir 1461*cdf0e10cSrcweir for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 1462*cdf0e10cSrcweir { 1463*cdf0e10cSrcweir for( y = 0; y < sizeof( nLocalKey ); y++ ) 1464*cdf0e10cSrcweir nLocalKey[y] = (sal_uInt8)( nMD5Sum[y] ^ i ); 1465*cdf0e10cSrcweir 1466*cdf0e10cSrcweir rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, 1467*cdf0e10cSrcweir nLocalKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area, on init can be NULL 1468*cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( aCipher, &io_rOValue[0], sal_Int32(io_rOValue.size()), // the data to be encrypted 1469*cdf0e10cSrcweir &io_rOValue[0], sal_Int32(io_rOValue.size()) ); // encrypted data, can be the same as the input, encrypt "in place" 1470*cdf0e10cSrcweir //step 8, store in class data member 1471*cdf0e10cSrcweir } 1472*cdf0e10cSrcweir } 1473*cdf0e10cSrcweir } 1474*cdf0e10cSrcweir else 1475*cdf0e10cSrcweir bSuccess = false; 1476*cdf0e10cSrcweir } 1477*cdf0e10cSrcweir else 1478*cdf0e10cSrcweir bSuccess = false; 1479*cdf0e10cSrcweir 1480*cdf0e10cSrcweir if( aDigest ) 1481*cdf0e10cSrcweir rtl_digest_destroyMD5( aDigest ); 1482*cdf0e10cSrcweir if( aCipher ) 1483*cdf0e10cSrcweir rtl_cipher_destroyARCFOUR( aCipher ); 1484*cdf0e10cSrcweir 1485*cdf0e10cSrcweir if( ! bSuccess ) 1486*cdf0e10cSrcweir io_rOValue.clear(); 1487*cdf0e10cSrcweir return bSuccess; 1488*cdf0e10cSrcweir } 1489*cdf0e10cSrcweir 1490*cdf0e10cSrcweir /********************************** 1491*cdf0e10cSrcweir Algorithms 3.4 and 3.5 Compute the encryption dictionary /U value, save into the class data member, revision 2 (40 bit) or 3 (128 bit) 1492*cdf0e10cSrcweir */ 1493*cdf0e10cSrcweir bool PDFWriterImpl::computeUDictionaryValue( EncHashTransporter* i_pTransporter, 1494*cdf0e10cSrcweir vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, 1495*cdf0e10cSrcweir sal_Int32 i_nKeyLength, 1496*cdf0e10cSrcweir sal_Int32 i_nAccessPermissions 1497*cdf0e10cSrcweir ) 1498*cdf0e10cSrcweir { 1499*cdf0e10cSrcweir bool bSuccess = true; 1500*cdf0e10cSrcweir 1501*cdf0e10cSrcweir io_rProperties.UValue.resize( ENCRYPTED_PWD_SIZE ); 1502*cdf0e10cSrcweir 1503*cdf0e10cSrcweir rtlDigest aDigest = rtl_digest_createMD5(); 1504*cdf0e10cSrcweir rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); 1505*cdf0e10cSrcweir if( aDigest && aCipher ) 1506*cdf0e10cSrcweir { 1507*cdf0e10cSrcweir //step 1, common to both 3.4 and 3.5 1508*cdf0e10cSrcweir if( computeEncryptionKey( i_pTransporter, io_rProperties, i_nAccessPermissions ) ) 1509*cdf0e10cSrcweir { 1510*cdf0e10cSrcweir // prepare encryption key for object 1511*cdf0e10cSrcweir for( sal_Int32 i = i_nKeyLength, y = 0; y < 5 ; y++ ) 1512*cdf0e10cSrcweir io_rProperties.EncryptionKey[i++] = 0; 1513*cdf0e10cSrcweir 1514*cdf0e10cSrcweir if( io_rProperties.Security128bit == false ) 1515*cdf0e10cSrcweir { 1516*cdf0e10cSrcweir //3.4 1517*cdf0e10cSrcweir //step 2 and 3 1518*cdf0e10cSrcweir rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, 1519*cdf0e10cSrcweir &io_rProperties.EncryptionKey[0], 5 , // key and key length 1520*cdf0e10cSrcweir NULL, 0 ); //destination data area 1521*cdf0e10cSrcweir // encrypt the user password using the key set above, save for later use 1522*cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( aCipher, s_nPadString, sizeof( s_nPadString ), // the data to be encrypted 1523*cdf0e10cSrcweir &io_rProperties.UValue[0], sal_Int32(io_rProperties.UValue.size()) ); //encrypted data, stored in class data member 1524*cdf0e10cSrcweir } 1525*cdf0e10cSrcweir else 1526*cdf0e10cSrcweir { 1527*cdf0e10cSrcweir //or 3.5, for 128 bit security 1528*cdf0e10cSrcweir //step6, initilize the last 16 bytes of the encrypted user password to 0 1529*cdf0e10cSrcweir for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sal_uInt32(io_rProperties.UValue.size()); i++) 1530*cdf0e10cSrcweir io_rProperties.UValue[i] = 0; 1531*cdf0e10cSrcweir //step 2 1532*cdf0e10cSrcweir rtlDigestError nError = rtl_digest_updateMD5( aDigest, s_nPadString, sizeof( s_nPadString ) ); 1533*cdf0e10cSrcweir //step 3 1534*cdf0e10cSrcweir if( nError == rtl_Digest_E_None ) 1535*cdf0e10cSrcweir nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) ); 1536*cdf0e10cSrcweir else 1537*cdf0e10cSrcweir bSuccess = false; 1538*cdf0e10cSrcweir 1539*cdf0e10cSrcweir sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; 1540*cdf0e10cSrcweir rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) ); 1541*cdf0e10cSrcweir //Step 4 1542*cdf0e10cSrcweir rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, 1543*cdf0e10cSrcweir &io_rProperties.EncryptionKey[0], SECUR_128BIT_KEY, NULL, 0 ); //destination data area 1544*cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( aCipher, nMD5Sum, sizeof( nMD5Sum ), // the data to be encrypted 1545*cdf0e10cSrcweir &io_rProperties.UValue[0], sizeof( nMD5Sum ) ); //encrypted data, stored in class data member 1546*cdf0e10cSrcweir //step 5 1547*cdf0e10cSrcweir sal_uInt32 i, y; 1548*cdf0e10cSrcweir sal_uInt8 nLocalKey[SECUR_128BIT_KEY]; 1549*cdf0e10cSrcweir 1550*cdf0e10cSrcweir for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 1551*cdf0e10cSrcweir { 1552*cdf0e10cSrcweir for( y = 0; y < sizeof( nLocalKey ) ; y++ ) 1553*cdf0e10cSrcweir nLocalKey[y] = (sal_uInt8)( io_rProperties.EncryptionKey[y] ^ i ); 1554*cdf0e10cSrcweir 1555*cdf0e10cSrcweir rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, 1556*cdf0e10cSrcweir nLocalKey, SECUR_128BIT_KEY, // key and key length 1557*cdf0e10cSrcweir NULL, 0 ); //destination data area, on init can be NULL 1558*cdf0e10cSrcweir rtl_cipher_encodeARCFOUR( aCipher, &io_rProperties.UValue[0], SECUR_128BIT_KEY, // the data to be encrypted 1559*cdf0e10cSrcweir &io_rProperties.UValue[0], SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place" 1560*cdf0e10cSrcweir } 1561*cdf0e10cSrcweir } 1562*cdf0e10cSrcweir } 1563*cdf0e10cSrcweir else 1564*cdf0e10cSrcweir bSuccess = false; 1565*cdf0e10cSrcweir } 1566*cdf0e10cSrcweir else 1567*cdf0e10cSrcweir bSuccess = false; 1568*cdf0e10cSrcweir 1569*cdf0e10cSrcweir if( aDigest ) 1570*cdf0e10cSrcweir rtl_digest_destroyMD5( aDigest ); 1571*cdf0e10cSrcweir if( aCipher ) 1572*cdf0e10cSrcweir rtl_cipher_destroyARCFOUR( aCipher ); 1573*cdf0e10cSrcweir 1574*cdf0e10cSrcweir if( ! bSuccess ) 1575*cdf0e10cSrcweir io_rProperties.UValue.clear(); 1576*cdf0e10cSrcweir return bSuccess; 1577*cdf0e10cSrcweir } 1578*cdf0e10cSrcweir 1579*cdf0e10cSrcweir /* end i12626 methods */ 1580*cdf0e10cSrcweir 1581*cdf0e10cSrcweir static const long unsetRun[256] = 1582*cdf0e10cSrcweir { 1583*cdf0e10cSrcweir 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, /* 0x00 - 0x0f */ 1584*cdf0e10cSrcweir 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0x10 - 0x1f */ 1585*cdf0e10cSrcweir 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x20 - 0x2f */ 1586*cdf0e10cSrcweir 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0x30 - 0x3f */ 1587*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40 - 0x4f */ 1588*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x50 - 0x5f */ 1589*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60 - 0x6f */ 1590*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x70 - 0x7f */ 1591*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 - 0x8f */ 1592*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 - 0x9f */ 1593*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 - 0xaf */ 1594*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 - 0xbf */ 1595*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 - 0xcf */ 1596*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 - 0xdf */ 1597*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 - 0xef */ 1598*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 - 0xff */ 1599*cdf0e10cSrcweir }; 1600*cdf0e10cSrcweir 1601*cdf0e10cSrcweir static const long setRun[256] = 1602*cdf0e10cSrcweir { 1603*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00 - 0x0f */ 1604*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 - 0x1f */ 1605*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20 - 0x2f */ 1606*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */ 1607*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */ 1608*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */ 1609*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 - 0x6f */ 1610*cdf0e10cSrcweir 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 - 0x7f */ 1611*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x80 - 0x8f */ 1612*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x90 - 0x9f */ 1613*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xa0 - 0xaf */ 1614*cdf0e10cSrcweir 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xb0 - 0xbf */ 1615*cdf0e10cSrcweir 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xc0 - 0xcf */ 1616*cdf0e10cSrcweir 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xd0 - 0xdf */ 1617*cdf0e10cSrcweir 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* 0xe0 - 0xef */ 1618*cdf0e10cSrcweir 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, /* 0xf0 - 0xff */ 1619*cdf0e10cSrcweir }; 1620*cdf0e10cSrcweir 1621*cdf0e10cSrcweir inline bool isSet( const Scanline i_pLine, long i_nIndex ) 1622*cdf0e10cSrcweir { 1623*cdf0e10cSrcweir return (i_pLine[ i_nIndex/8 ] & (0x80 >> (i_nIndex&7))) != 0; 1624*cdf0e10cSrcweir } 1625*cdf0e10cSrcweir 1626*cdf0e10cSrcweir long findBitRun( const Scanline i_pLine, long i_nStartIndex, long i_nW, bool i_bSet ) 1627*cdf0e10cSrcweir { 1628*cdf0e10cSrcweir if( i_nStartIndex < 0 ) 1629*cdf0e10cSrcweir return i_nW; 1630*cdf0e10cSrcweir 1631*cdf0e10cSrcweir long nIndex = i_nStartIndex; 1632*cdf0e10cSrcweir if( nIndex < i_nW ) 1633*cdf0e10cSrcweir { 1634*cdf0e10cSrcweir const sal_uInt8 * pByte = static_cast<sal_uInt8*>(i_pLine) + (nIndex/8); 1635*cdf0e10cSrcweir sal_uInt8 nByte = *pByte; 1636*cdf0e10cSrcweir 1637*cdf0e10cSrcweir // run up to byte boundary 1638*cdf0e10cSrcweir long nBitInByte = (nIndex & 7); 1639*cdf0e10cSrcweir if( nBitInByte ) 1640*cdf0e10cSrcweir { 1641*cdf0e10cSrcweir sal_uInt8 nMask = 0x80 >> nBitInByte; 1642*cdf0e10cSrcweir while( nBitInByte != 8 ) 1643*cdf0e10cSrcweir { 1644*cdf0e10cSrcweir if( (nByte & nMask) != (i_bSet ? nMask : 0) ) 1645*cdf0e10cSrcweir return nIndex < i_nW ? nIndex : i_nW; 1646*cdf0e10cSrcweir nMask = nMask >> 1; 1647*cdf0e10cSrcweir nBitInByte++; 1648*cdf0e10cSrcweir nIndex++; 1649*cdf0e10cSrcweir } 1650*cdf0e10cSrcweir if( nIndex < i_nW ) 1651*cdf0e10cSrcweir { 1652*cdf0e10cSrcweir pByte++; 1653*cdf0e10cSrcweir nByte = *pByte; 1654*cdf0e10cSrcweir } 1655*cdf0e10cSrcweir } 1656*cdf0e10cSrcweir 1657*cdf0e10cSrcweir sal_uInt8 nRunByte; 1658*cdf0e10cSrcweir const long* pRunTable; 1659*cdf0e10cSrcweir if( i_bSet ) 1660*cdf0e10cSrcweir { 1661*cdf0e10cSrcweir nRunByte = 0xff; 1662*cdf0e10cSrcweir pRunTable = setRun; 1663*cdf0e10cSrcweir } 1664*cdf0e10cSrcweir else 1665*cdf0e10cSrcweir { 1666*cdf0e10cSrcweir nRunByte = 0; 1667*cdf0e10cSrcweir pRunTable = unsetRun; 1668*cdf0e10cSrcweir } 1669*cdf0e10cSrcweir 1670*cdf0e10cSrcweir while( nByte == nRunByte && nIndex < i_nW ) 1671*cdf0e10cSrcweir { 1672*cdf0e10cSrcweir nIndex += 8; 1673*cdf0e10cSrcweir pByte++; 1674*cdf0e10cSrcweir nByte = *pByte; 1675*cdf0e10cSrcweir } 1676*cdf0e10cSrcweir if( nIndex < i_nW ) 1677*cdf0e10cSrcweir { 1678*cdf0e10cSrcweir nIndex += pRunTable[nByte]; 1679*cdf0e10cSrcweir } 1680*cdf0e10cSrcweir } 1681*cdf0e10cSrcweir return nIndex < i_nW ? nIndex : i_nW; 1682*cdf0e10cSrcweir } 1683*cdf0e10cSrcweir 1684*cdf0e10cSrcweir struct BitStreamState 1685*cdf0e10cSrcweir { 1686*cdf0e10cSrcweir sal_uInt8 mnBuffer; 1687*cdf0e10cSrcweir sal_uInt32 mnNextBitPos; 1688*cdf0e10cSrcweir 1689*cdf0e10cSrcweir BitStreamState() 1690*cdf0e10cSrcweir : mnBuffer( 0 ) 1691*cdf0e10cSrcweir , mnNextBitPos( 8 ) 1692*cdf0e10cSrcweir { 1693*cdf0e10cSrcweir } 1694*cdf0e10cSrcweir 1695*cdf0e10cSrcweir const sal_uInt8* getByte() const { return &mnBuffer; } 1696*cdf0e10cSrcweir void flush() { mnNextBitPos = 8; mnBuffer = 0; } 1697*cdf0e10cSrcweir }; 1698*cdf0e10cSrcweir 1699*cdf0e10cSrcweir void PDFWriterImpl::putG4Bits( sal_uInt32 i_nLength, sal_uInt32 i_nCode, BitStreamState& io_rState ) 1700*cdf0e10cSrcweir { 1701*cdf0e10cSrcweir while( i_nLength > io_rState.mnNextBitPos ) 1702*cdf0e10cSrcweir { 1703*cdf0e10cSrcweir io_rState.mnBuffer |= static_cast<sal_uInt8>( i_nCode >> (i_nLength - io_rState.mnNextBitPos) ); 1704*cdf0e10cSrcweir i_nLength -= io_rState.mnNextBitPos; 1705*cdf0e10cSrcweir writeBuffer( io_rState.getByte(), 1 ); 1706*cdf0e10cSrcweir io_rState.flush(); 1707*cdf0e10cSrcweir } 1708*cdf0e10cSrcweir OSL_ASSERT( i_nLength < 9 ); 1709*cdf0e10cSrcweir static const unsigned int msbmask[9] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; 1710*cdf0e10cSrcweir io_rState.mnBuffer |= static_cast<sal_uInt8>( (i_nCode & msbmask[i_nLength]) << (io_rState.mnNextBitPos - i_nLength) ); 1711*cdf0e10cSrcweir io_rState.mnNextBitPos -= i_nLength; 1712*cdf0e10cSrcweir if( io_rState.mnNextBitPos == 0 ) 1713*cdf0e10cSrcweir { 1714*cdf0e10cSrcweir writeBuffer( io_rState.getByte(), 1 ); 1715*cdf0e10cSrcweir io_rState.flush(); 1716*cdf0e10cSrcweir } 1717*cdf0e10cSrcweir } 1718*cdf0e10cSrcweir 1719*cdf0e10cSrcweir struct PixelCode 1720*cdf0e10cSrcweir { 1721*cdf0e10cSrcweir sal_uInt32 mnEncodedPixels; 1722*cdf0e10cSrcweir sal_uInt32 mnCodeBits; 1723*cdf0e10cSrcweir sal_uInt32 mnCode; 1724*cdf0e10cSrcweir }; 1725*cdf0e10cSrcweir 1726*cdf0e10cSrcweir static const PixelCode WhitePixelCodes[] = 1727*cdf0e10cSrcweir { 1728*cdf0e10cSrcweir { 0, 8, 0x35 }, // 0011 0101 1729*cdf0e10cSrcweir { 1, 6, 0x7 }, // 0001 11 1730*cdf0e10cSrcweir { 2, 4, 0x7 }, // 0111 1731*cdf0e10cSrcweir { 3, 4, 0x8 }, // 1000 1732*cdf0e10cSrcweir { 4, 4, 0xB }, // 1011 1733*cdf0e10cSrcweir { 5, 4, 0xC }, // 1100 1734*cdf0e10cSrcweir { 6, 4, 0xE }, // 1110 1735*cdf0e10cSrcweir { 7, 4, 0xF }, // 1111 1736*cdf0e10cSrcweir { 8, 5, 0x13 }, // 1001 1 1737*cdf0e10cSrcweir { 9, 5, 0x14 }, // 1010 0 1738*cdf0e10cSrcweir { 10, 5, 0x7 }, // 0011 1 1739*cdf0e10cSrcweir { 11, 5, 0x8 }, // 0100 0 1740*cdf0e10cSrcweir { 12, 6, 0x8 }, // 0010 00 1741*cdf0e10cSrcweir { 13, 6, 0x3 }, // 0000 11 1742*cdf0e10cSrcweir { 14, 6, 0x34 }, // 1101 00 1743*cdf0e10cSrcweir { 15, 6, 0x35 }, // 1101 01 1744*cdf0e10cSrcweir { 16, 6, 0x2A }, // 1010 10 1745*cdf0e10cSrcweir { 17, 6, 0x2B }, // 1010 11 1746*cdf0e10cSrcweir { 18, 7, 0x27 }, // 0100 111 1747*cdf0e10cSrcweir { 19, 7, 0xC }, // 0001 100 1748*cdf0e10cSrcweir { 20, 7, 0x8 }, // 0001 000 1749*cdf0e10cSrcweir { 21, 7, 0x17 }, // 0010 111 1750*cdf0e10cSrcweir { 22, 7, 0x3 }, // 0000 011 1751*cdf0e10cSrcweir { 23, 7, 0x4 }, // 0000 100 1752*cdf0e10cSrcweir { 24, 7, 0x28 }, // 0101 000 1753*cdf0e10cSrcweir { 25, 7, 0x2B }, // 0101 011 1754*cdf0e10cSrcweir { 26, 7, 0x13 }, // 0010 011 1755*cdf0e10cSrcweir { 27, 7, 0x24 }, // 0100 100 1756*cdf0e10cSrcweir { 28, 7, 0x18 }, // 0011 000 1757*cdf0e10cSrcweir { 29, 8, 0x2 }, // 0000 0010 1758*cdf0e10cSrcweir { 30, 8, 0x3 }, // 0000 0011 1759*cdf0e10cSrcweir { 31, 8, 0x1A }, // 0001 1010 1760*cdf0e10cSrcweir { 32, 8, 0x1B }, // 0001 1011 1761*cdf0e10cSrcweir { 33, 8, 0x12 }, // 0001 0010 1762*cdf0e10cSrcweir { 34, 8, 0x13 }, // 0001 0011 1763*cdf0e10cSrcweir { 35, 8, 0x14 }, // 0001 0100 1764*cdf0e10cSrcweir { 36, 8, 0x15 }, // 0001 0101 1765*cdf0e10cSrcweir { 37, 8, 0x16 }, // 0001 0110 1766*cdf0e10cSrcweir { 38, 8, 0x17 }, // 0001 0111 1767*cdf0e10cSrcweir { 39, 8, 0x28 }, // 0010 1000 1768*cdf0e10cSrcweir { 40, 8, 0x29 }, // 0010 1001 1769*cdf0e10cSrcweir { 41, 8, 0x2A }, // 0010 1010 1770*cdf0e10cSrcweir { 42, 8, 0x2B }, // 0010 1011 1771*cdf0e10cSrcweir { 43, 8, 0x2C }, // 0010 1100 1772*cdf0e10cSrcweir { 44, 8, 0x2D }, // 0010 1101 1773*cdf0e10cSrcweir { 45, 8, 0x4 }, // 0000 0100 1774*cdf0e10cSrcweir { 46, 8, 0x5 }, // 0000 0101 1775*cdf0e10cSrcweir { 47, 8, 0xA }, // 0000 1010 1776*cdf0e10cSrcweir { 48, 8, 0xB }, // 0000 1011 1777*cdf0e10cSrcweir { 49, 8, 0x52 }, // 0101 0010 1778*cdf0e10cSrcweir { 50, 8, 0x53 }, // 0101 0011 1779*cdf0e10cSrcweir { 51, 8, 0x54 }, // 0101 0100 1780*cdf0e10cSrcweir { 52, 8, 0x55 }, // 0101 0101 1781*cdf0e10cSrcweir { 53, 8, 0x24 }, // 0010 0100 1782*cdf0e10cSrcweir { 54, 8, 0x25 }, // 0010 0101 1783*cdf0e10cSrcweir { 55, 8, 0x58 }, // 0101 1000 1784*cdf0e10cSrcweir { 56, 8, 0x59 }, // 0101 1001 1785*cdf0e10cSrcweir { 57, 8, 0x5A }, // 0101 1010 1786*cdf0e10cSrcweir { 58, 8, 0x5B }, // 0101 1011 1787*cdf0e10cSrcweir { 59, 8, 0x4A }, // 0100 1010 1788*cdf0e10cSrcweir { 60, 8, 0x4B }, // 0100 1011 1789*cdf0e10cSrcweir { 61, 8, 0x32 }, // 0011 0010 1790*cdf0e10cSrcweir { 62, 8, 0x33 }, // 0011 0011 1791*cdf0e10cSrcweir { 63, 8, 0x34 }, // 0011 0100 1792*cdf0e10cSrcweir { 64, 5, 0x1B }, // 1101 1 1793*cdf0e10cSrcweir { 128, 5, 0x12 }, // 1001 0 1794*cdf0e10cSrcweir { 192, 6, 0x17 }, // 0101 11 1795*cdf0e10cSrcweir { 256, 7, 0x37 }, // 0110 111 1796*cdf0e10cSrcweir { 320, 8, 0x36 }, // 0011 0110 1797*cdf0e10cSrcweir { 384, 8, 0x37 }, // 0011 0111 1798*cdf0e10cSrcweir { 448, 8, 0x64 }, // 0110 0100 1799*cdf0e10cSrcweir { 512, 8, 0x65 }, // 0110 0101 1800*cdf0e10cSrcweir { 576, 8, 0x68 }, // 0110 1000 1801*cdf0e10cSrcweir { 640, 8, 0x67 }, // 0110 0111 1802*cdf0e10cSrcweir { 704, 9, 0xCC }, // 0110 0110 0 1803*cdf0e10cSrcweir { 768, 9, 0xCD }, // 0110 0110 1 1804*cdf0e10cSrcweir { 832, 9, 0xD2 }, // 0110 1001 0 1805*cdf0e10cSrcweir { 896, 9, 0xD3 }, // 0110 1001 1 1806*cdf0e10cSrcweir { 960, 9, 0xD4 }, // 0110 1010 0 1807*cdf0e10cSrcweir { 1024, 9, 0xD5 }, // 0110 1010 1 1808*cdf0e10cSrcweir { 1088, 9, 0xD6 }, // 0110 1011 0 1809*cdf0e10cSrcweir { 1152, 9, 0xD7 }, // 0110 1011 1 1810*cdf0e10cSrcweir { 1216, 9, 0xD8 }, // 0110 1100 0 1811*cdf0e10cSrcweir { 1280, 9, 0xD9 }, // 0110 1100 1 1812*cdf0e10cSrcweir { 1344, 9, 0xDA }, // 0110 1101 0 1813*cdf0e10cSrcweir { 1408, 9, 0xDB }, // 0110 1101 1 1814*cdf0e10cSrcweir { 1472, 9, 0x98 }, // 0100 1100 0 1815*cdf0e10cSrcweir { 1536, 9, 0x99 }, // 0100 1100 1 1816*cdf0e10cSrcweir { 1600, 9, 0x9A }, // 0100 1101 0 1817*cdf0e10cSrcweir { 1664, 6, 0x18 }, // 0110 00 1818*cdf0e10cSrcweir { 1728, 9, 0x9B }, // 0100 1101 1 1819*cdf0e10cSrcweir { 1792, 11, 0x8 }, // 0000 0001 000 1820*cdf0e10cSrcweir { 1856, 11, 0xC }, // 0000 0001 100 1821*cdf0e10cSrcweir { 1920, 11, 0xD }, // 0000 0001 101 1822*cdf0e10cSrcweir { 1984, 12, 0x12 }, // 0000 0001 0010 1823*cdf0e10cSrcweir { 2048, 12, 0x13 }, // 0000 0001 0011 1824*cdf0e10cSrcweir { 2112, 12, 0x14 }, // 0000 0001 0100 1825*cdf0e10cSrcweir { 2176, 12, 0x15 }, // 0000 0001 0101 1826*cdf0e10cSrcweir { 2240, 12, 0x16 }, // 0000 0001 0110 1827*cdf0e10cSrcweir { 2304, 12, 0x17 }, // 0000 0001 0111 1828*cdf0e10cSrcweir { 2368, 12, 0x1C }, // 0000 0001 1100 1829*cdf0e10cSrcweir { 2432, 12, 0x1D }, // 0000 0001 1101 1830*cdf0e10cSrcweir { 2496, 12, 0x1E }, // 0000 0001 1110 1831*cdf0e10cSrcweir { 2560, 12, 0x1F } // 0000 0001 1111 1832*cdf0e10cSrcweir }; 1833*cdf0e10cSrcweir 1834*cdf0e10cSrcweir static const PixelCode BlackPixelCodes[] = 1835*cdf0e10cSrcweir { 1836*cdf0e10cSrcweir { 0, 10, 0x37 }, // 0000 1101 11 1837*cdf0e10cSrcweir { 1, 3, 0x2 }, // 010 1838*cdf0e10cSrcweir { 2, 2, 0x3 }, // 11 1839*cdf0e10cSrcweir { 3, 2, 0x2 }, // 10 1840*cdf0e10cSrcweir { 4, 3, 0x3 }, // 011 1841*cdf0e10cSrcweir { 5, 4, 0x3 }, // 0011 1842*cdf0e10cSrcweir { 6, 4, 0x2 }, // 0010 1843*cdf0e10cSrcweir { 7, 5, 0x3 }, // 0001 1 1844*cdf0e10cSrcweir { 8, 6, 0x5 }, // 0001 01 1845*cdf0e10cSrcweir { 9, 6, 0x4 }, // 0001 00 1846*cdf0e10cSrcweir { 10, 7, 0x4 }, // 0000 100 1847*cdf0e10cSrcweir { 11, 7, 0x5 }, // 0000 101 1848*cdf0e10cSrcweir { 12, 7, 0x7 }, // 0000 111 1849*cdf0e10cSrcweir { 13, 8, 0x4 }, // 0000 0100 1850*cdf0e10cSrcweir { 14, 8, 0x7 }, // 0000 0111 1851*cdf0e10cSrcweir { 15, 9, 0x18 }, // 0000 1100 0 1852*cdf0e10cSrcweir { 16, 10, 0x17 }, // 0000 0101 11 1853*cdf0e10cSrcweir { 17, 10, 0x18 }, // 0000 0110 00 1854*cdf0e10cSrcweir { 18, 10, 0x8 }, // 0000 0010 00 1855*cdf0e10cSrcweir { 19, 11, 0x67 }, // 0000 1100 111 1856*cdf0e10cSrcweir { 20, 11, 0x68 }, // 0000 1101 000 1857*cdf0e10cSrcweir { 21, 11, 0x6C }, // 0000 1101 100 1858*cdf0e10cSrcweir { 22, 11, 0x37 }, // 0000 0110 111 1859*cdf0e10cSrcweir { 23, 11, 0x28 }, // 0000 0101 000 1860*cdf0e10cSrcweir { 24, 11, 0x17 }, // 0000 0010 111 1861*cdf0e10cSrcweir { 25, 11, 0x18 }, // 0000 0011 000 1862*cdf0e10cSrcweir { 26, 12, 0xCA }, // 0000 1100 1010 1863*cdf0e10cSrcweir { 27, 12, 0xCB }, // 0000 1100 1011 1864*cdf0e10cSrcweir { 28, 12, 0xCC }, // 0000 1100 1100 1865*cdf0e10cSrcweir { 29, 12, 0xCD }, // 0000 1100 1101 1866*cdf0e10cSrcweir { 30, 12, 0x68 }, // 0000 0110 1000 1867*cdf0e10cSrcweir { 31, 12, 0x69 }, // 0000 0110 1001 1868*cdf0e10cSrcweir { 32, 12, 0x6A }, // 0000 0110 1010 1869*cdf0e10cSrcweir { 33, 12, 0x6B }, // 0000 0110 1011 1870*cdf0e10cSrcweir { 34, 12, 0xD2 }, // 0000 1101 0010 1871*cdf0e10cSrcweir { 35, 12, 0xD3 }, // 0000 1101 0011 1872*cdf0e10cSrcweir { 36, 12, 0xD4 }, // 0000 1101 0100 1873*cdf0e10cSrcweir { 37, 12, 0xD5 }, // 0000 1101 0101 1874*cdf0e10cSrcweir { 38, 12, 0xD6 }, // 0000 1101 0110 1875*cdf0e10cSrcweir { 39, 12, 0xD7 }, // 0000 1101 0111 1876*cdf0e10cSrcweir { 40, 12, 0x6C }, // 0000 0110 1100 1877*cdf0e10cSrcweir { 41, 12, 0x6D }, // 0000 0110 1101 1878*cdf0e10cSrcweir { 42, 12, 0xDA }, // 0000 1101 1010 1879*cdf0e10cSrcweir { 43, 12, 0xDB }, // 0000 1101 1011 1880*cdf0e10cSrcweir { 44, 12, 0x54 }, // 0000 0101 0100 1881*cdf0e10cSrcweir { 45, 12, 0x55 }, // 0000 0101 0101 1882*cdf0e10cSrcweir { 46, 12, 0x56 }, // 0000 0101 0110 1883*cdf0e10cSrcweir { 47, 12, 0x57 }, // 0000 0101 0111 1884*cdf0e10cSrcweir { 48, 12, 0x64 }, // 0000 0110 0100 1885*cdf0e10cSrcweir { 49, 12, 0x65 }, // 0000 0110 0101 1886*cdf0e10cSrcweir { 50, 12, 0x52 }, // 0000 0101 0010 1887*cdf0e10cSrcweir { 51, 12, 0x53 }, // 0000 0101 0011 1888*cdf0e10cSrcweir { 52, 12, 0x24 }, // 0000 0010 0100 1889*cdf0e10cSrcweir { 53, 12, 0x37 }, // 0000 0011 0111 1890*cdf0e10cSrcweir { 54, 12, 0x38 }, // 0000 0011 1000 1891*cdf0e10cSrcweir { 55, 12, 0x27 }, // 0000 0010 0111 1892*cdf0e10cSrcweir { 56, 12, 0x28 }, // 0000 0010 1000 1893*cdf0e10cSrcweir { 57, 12, 0x58 }, // 0000 0101 1000 1894*cdf0e10cSrcweir { 58, 12, 0x59 }, // 0000 0101 1001 1895*cdf0e10cSrcweir { 59, 12, 0x2B }, // 0000 0010 1011 1896*cdf0e10cSrcweir { 60, 12, 0x2C }, // 0000 0010 1100 1897*cdf0e10cSrcweir { 61, 12, 0x5A }, // 0000 0101 1010 1898*cdf0e10cSrcweir { 62, 12, 0x66 }, // 0000 0110 0110 1899*cdf0e10cSrcweir { 63, 12, 0x67 }, // 0000 0110 0111 1900*cdf0e10cSrcweir { 64, 10, 0xF }, // 0000 0011 11 1901*cdf0e10cSrcweir { 128, 12, 0xC8 }, // 0000 1100 1000 1902*cdf0e10cSrcweir { 192, 12, 0xC9 }, // 0000 1100 1001 1903*cdf0e10cSrcweir { 256, 12, 0x5B }, // 0000 0101 1011 1904*cdf0e10cSrcweir { 320, 12, 0x33 }, // 0000 0011 0011 1905*cdf0e10cSrcweir { 384, 12, 0x34 }, // 0000 0011 0100 1906*cdf0e10cSrcweir { 448, 12, 0x35 }, // 0000 0011 0101 1907*cdf0e10cSrcweir { 512, 13, 0x6C }, // 0000 0011 0110 0 1908*cdf0e10cSrcweir { 576, 13, 0x6D }, // 0000 0011 0110 1 1909*cdf0e10cSrcweir { 640, 13, 0x4A }, // 0000 0010 0101 0 1910*cdf0e10cSrcweir { 704, 13, 0x4B }, // 0000 0010 0101 1 1911*cdf0e10cSrcweir { 768, 13, 0x4C }, // 0000 0010 0110 0 1912*cdf0e10cSrcweir { 832, 13, 0x4D }, // 0000 0010 0110 1 1913*cdf0e10cSrcweir { 896, 13, 0x72 }, // 0000 0011 1001 0 1914*cdf0e10cSrcweir { 960, 13, 0x73 }, // 0000 0011 1001 1 1915*cdf0e10cSrcweir { 1024, 13, 0x74 }, // 0000 0011 1010 0 1916*cdf0e10cSrcweir { 1088, 13, 0x75 }, // 0000 0011 1010 1 1917*cdf0e10cSrcweir { 1152, 13, 0x76 }, // 0000 0011 1011 0 1918*cdf0e10cSrcweir { 1216, 13, 0x77 }, // 0000 0011 1011 1 1919*cdf0e10cSrcweir { 1280, 13, 0x52 }, // 0000 0010 1001 0 1920*cdf0e10cSrcweir { 1344, 13, 0x53 }, // 0000 0010 1001 1 1921*cdf0e10cSrcweir { 1408, 13, 0x54 }, // 0000 0010 1010 0 1922*cdf0e10cSrcweir { 1472, 13, 0x55 }, // 0000 0010 1010 1 1923*cdf0e10cSrcweir { 1536, 13, 0x5A }, // 0000 0010 1101 0 1924*cdf0e10cSrcweir { 1600, 13, 0x5B }, // 0000 0010 1101 1 1925*cdf0e10cSrcweir { 1664, 13, 0x64 }, // 0000 0011 0010 0 1926*cdf0e10cSrcweir { 1728, 13, 0x65 }, // 0000 0011 0010 1 1927*cdf0e10cSrcweir { 1792, 11, 0x8 }, // 0000 0001 000 1928*cdf0e10cSrcweir { 1856, 11, 0xC }, // 0000 0001 100 1929*cdf0e10cSrcweir { 1920, 11, 0xD }, // 0000 0001 101 1930*cdf0e10cSrcweir { 1984, 12, 0x12 }, // 0000 0001 0010 1931*cdf0e10cSrcweir { 2048, 12, 0x13 }, // 0000 0001 0011 1932*cdf0e10cSrcweir { 2112, 12, 0x14 }, // 0000 0001 0100 1933*cdf0e10cSrcweir { 2176, 12, 0x15 }, // 0000 0001 0101 1934*cdf0e10cSrcweir { 2240, 12, 0x16 }, // 0000 0001 0110 1935*cdf0e10cSrcweir { 2304, 12, 0x17 }, // 0000 0001 0111 1936*cdf0e10cSrcweir { 2368, 12, 0x1C }, // 0000 0001 1100 1937*cdf0e10cSrcweir { 2432, 12, 0x1D }, // 0000 0001 1101 1938*cdf0e10cSrcweir { 2496, 12, 0x1E }, // 0000 0001 1110 1939*cdf0e10cSrcweir { 2560, 12, 0x1F } // 0000 0001 1111 1940*cdf0e10cSrcweir }; 1941*cdf0e10cSrcweir 1942*cdf0e10cSrcweir 1943*cdf0e10cSrcweir void PDFWriterImpl::putG4Span( long i_nSpan, bool i_bWhitePixel, BitStreamState& io_rState ) 1944*cdf0e10cSrcweir { 1945*cdf0e10cSrcweir const PixelCode* pTable = i_bWhitePixel ? WhitePixelCodes : BlackPixelCodes; 1946*cdf0e10cSrcweir // maximum encoded span is 2560 consecutive pixels 1947*cdf0e10cSrcweir while( i_nSpan > 2623 ) 1948*cdf0e10cSrcweir { 1949*cdf0e10cSrcweir // write 2560 bits, that is entry (63 + (2560 >> 6)) == 103 in the appropriate table 1950*cdf0e10cSrcweir putG4Bits( pTable[103].mnCodeBits, pTable[103].mnCode, io_rState ); 1951*cdf0e10cSrcweir i_nSpan -= pTable[103].mnEncodedPixels; 1952*cdf0e10cSrcweir } 1953*cdf0e10cSrcweir // write multiples of 64 pixels up to 2560 1954*cdf0e10cSrcweir if( i_nSpan > 63 ) 1955*cdf0e10cSrcweir { 1956*cdf0e10cSrcweir sal_uInt32 nTabIndex = 63 + (i_nSpan >> 6); 1957*cdf0e10cSrcweir OSL_ASSERT( pTable[nTabIndex].mnEncodedPixels == static_cast<sal_uInt32>(64*(i_nSpan >> 6)) ); 1958*cdf0e10cSrcweir putG4Bits( pTable[nTabIndex].mnCodeBits, pTable[nTabIndex].mnCode, io_rState ); 1959*cdf0e10cSrcweir i_nSpan -= pTable[nTabIndex].mnEncodedPixels; 1960*cdf0e10cSrcweir } 1961*cdf0e10cSrcweir putG4Bits( pTable[i_nSpan].mnCodeBits, pTable[i_nSpan].mnCode, io_rState ); 1962*cdf0e10cSrcweir } 1963*cdf0e10cSrcweir 1964*cdf0e10cSrcweir void PDFWriterImpl::writeG4Stream( BitmapReadAccess* i_pBitmap ) 1965*cdf0e10cSrcweir { 1966*cdf0e10cSrcweir long nW = i_pBitmap->Width(); 1967*cdf0e10cSrcweir long nH = i_pBitmap->Height(); 1968*cdf0e10cSrcweir if( nW <= 0 || nH <= 0 ) 1969*cdf0e10cSrcweir return; 1970*cdf0e10cSrcweir if( i_pBitmap->GetBitCount() != 1 ) 1971*cdf0e10cSrcweir return; 1972*cdf0e10cSrcweir 1973*cdf0e10cSrcweir BitStreamState aBitState; 1974*cdf0e10cSrcweir 1975*cdf0e10cSrcweir // the first reference line is virtual and completely empty 1976*cdf0e10cSrcweir const Scanline pFirstRefLine = (Scanline)rtl_allocateZeroMemory( nW/8 + 1 ); 1977*cdf0e10cSrcweir Scanline pRefLine = pFirstRefLine; 1978*cdf0e10cSrcweir for( long nY = 0; nY < nH; nY++ ) 1979*cdf0e10cSrcweir { 1980*cdf0e10cSrcweir const Scanline pCurLine = i_pBitmap->GetScanline( nY ); 1981*cdf0e10cSrcweir long nLineIndex = 0; 1982*cdf0e10cSrcweir bool bRunSet = (*pCurLine & 0x80) ? true : false; 1983*cdf0e10cSrcweir bool bRefSet = (*pRefLine & 0x80) ? true : false; 1984*cdf0e10cSrcweir long nRunIndex1 = bRunSet ? 0 : findBitRun( pCurLine, 0, nW, bRunSet ); 1985*cdf0e10cSrcweir long nRefIndex1 = bRefSet ? 0 : findBitRun( pRefLine, 0, nW, bRefSet ); 1986*cdf0e10cSrcweir for( ; nLineIndex < nW; ) 1987*cdf0e10cSrcweir { 1988*cdf0e10cSrcweir long nRefIndex2 = findBitRun( pRefLine, nRefIndex1, nW, isSet( pRefLine, nRefIndex1 ) ); 1989*cdf0e10cSrcweir if( nRefIndex2 >= nRunIndex1 ) 1990*cdf0e10cSrcweir { 1991*cdf0e10cSrcweir long nDiff = nRefIndex1 - nRunIndex1; 1992*cdf0e10cSrcweir if( -3 <= nDiff && nDiff <= 3 ) 1993*cdf0e10cSrcweir { // vertical coding 1994*cdf0e10cSrcweir static const struct 1995*cdf0e10cSrcweir { 1996*cdf0e10cSrcweir sal_uInt32 mnCodeBits; 1997*cdf0e10cSrcweir sal_uInt32 mnCode; 1998*cdf0e10cSrcweir } VerticalCodes[7] = { 1999*cdf0e10cSrcweir { 7, 0x03 }, // 0000 011 2000*cdf0e10cSrcweir { 6, 0x03 }, // 0000 11 2001*cdf0e10cSrcweir { 3, 0x03 }, // 011 2002*cdf0e10cSrcweir { 1, 0x1 }, // 1 2003*cdf0e10cSrcweir { 3, 0x2 }, // 010 2004*cdf0e10cSrcweir { 6, 0x02 }, // 0000 10 2005*cdf0e10cSrcweir { 7, 0x02 } // 0000 010 2006*cdf0e10cSrcweir }; 2007*cdf0e10cSrcweir // convert to index 2008*cdf0e10cSrcweir nDiff += 3; 2009*cdf0e10cSrcweir 2010*cdf0e10cSrcweir // emit diff code 2011*cdf0e10cSrcweir putG4Bits( VerticalCodes[nDiff].mnCodeBits, VerticalCodes[nDiff].mnCode, aBitState ); 2012*cdf0e10cSrcweir nLineIndex = nRunIndex1; 2013*cdf0e10cSrcweir } 2014*cdf0e10cSrcweir else 2015*cdf0e10cSrcweir { // difference too large, horizontal coding 2016*cdf0e10cSrcweir // emit horz code 001 2017*cdf0e10cSrcweir putG4Bits( 3, 0x1, aBitState ); 2018*cdf0e10cSrcweir long nRunIndex2 = findBitRun( pCurLine, nRunIndex1, nW, isSet( pCurLine, nRunIndex1 ) ); 2019*cdf0e10cSrcweir bool bWhiteFirst = ( nLineIndex + nRunIndex1 == 0 || ! isSet( pCurLine, nLineIndex ) ); 2020*cdf0e10cSrcweir putG4Span( nRunIndex1 - nLineIndex, bWhiteFirst, aBitState ); 2021*cdf0e10cSrcweir putG4Span( nRunIndex2 - nRunIndex1, ! bWhiteFirst, aBitState ); 2022*cdf0e10cSrcweir nLineIndex = nRunIndex2; 2023*cdf0e10cSrcweir } 2024*cdf0e10cSrcweir } 2025*cdf0e10cSrcweir else 2026*cdf0e10cSrcweir { // emit pass code 0001 2027*cdf0e10cSrcweir putG4Bits( 4, 0x1, aBitState ); 2028*cdf0e10cSrcweir nLineIndex = nRefIndex2; 2029*cdf0e10cSrcweir } 2030*cdf0e10cSrcweir if( nLineIndex < nW ) 2031*cdf0e10cSrcweir { 2032*cdf0e10cSrcweir bool bSet = isSet( pCurLine, nLineIndex ); 2033*cdf0e10cSrcweir nRunIndex1 = findBitRun( pCurLine, nLineIndex, nW, bSet ); 2034*cdf0e10cSrcweir nRefIndex1 = findBitRun( pRefLine, nLineIndex, nW, ! bSet ); 2035*cdf0e10cSrcweir nRefIndex1 = findBitRun( pRefLine, nRefIndex1, nW, bSet ); 2036*cdf0e10cSrcweir } 2037*cdf0e10cSrcweir } 2038*cdf0e10cSrcweir 2039*cdf0e10cSrcweir // the current line is the reference for the next line 2040*cdf0e10cSrcweir pRefLine = pCurLine; 2041*cdf0e10cSrcweir } 2042*cdf0e10cSrcweir // terminate strip with EOFB 2043*cdf0e10cSrcweir putG4Bits( 12, 1, aBitState ); 2044*cdf0e10cSrcweir putG4Bits( 12, 1, aBitState ); 2045*cdf0e10cSrcweir if( aBitState.mnNextBitPos != 8 ) 2046*cdf0e10cSrcweir { 2047*cdf0e10cSrcweir writeBuffer( aBitState.getByte(), 1 ); 2048*cdf0e10cSrcweir aBitState.flush(); 2049*cdf0e10cSrcweir } 2050*cdf0e10cSrcweir 2051*cdf0e10cSrcweir rtl_freeMemory( pFirstRefLine ); 2052*cdf0e10cSrcweir } 2053