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