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