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