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