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