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