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