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