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