1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <vcl/canvastools.hxx>
21 #include <vcl/pdfextoutdevdata.hxx>
22 #include <vcl/graph.hxx>
23 #include <vcl/outdev.hxx>
24 #include <vcl/gfxlink.hxx>
25 #include <vcl/metaact.hxx>
26 #include <vcl/graphicfilter.hxx>
27 #include <basegfx/polygon/b2dpolygon.hxx>
28 #include <basegfx/polygon/b2dpolygontools.hxx>
29 #include <sal/log.hxx>
30 #include <o3tl/safeint.hxx>
31 #include <osl/diagnose.h>
32 #include <tools/stream.hxx>
41 struct PDFExtOutDevDataSync
43 enum Action
{ CreateNamedDest
,
56 BeginStructureElement
,
58 SetCurrentStructureElement
,
59 SetStructureAttribute
,
60 SetStructureAttributeNumerical
,
61 SetStructureBoundingBox
,
73 struct PDFLinkDestination
75 tools::Rectangle mRect
;
78 PDFWriter::DestAreaType mAreaType
;
85 std::deque
< PDFExtOutDevDataSync::Action
> mActions
;
86 std::deque
< MapMode
> mParaMapModes
;
87 std::deque
< tools::Rectangle
> mParaRects
;
88 std::deque
< sal_Int32
> mParaInts
;
89 std::deque
< sal_uInt32
> mParauInts
;
90 std::deque
< OUString
> mParaOUStrings
;
91 std::deque
< PDFWriter::DestAreaType
> mParaDestAreaTypes
;
92 std::deque
< PDFNote
> mParaPDFNotes
;
93 std::deque
< PDFWriter::PageTransition
> mParaPageTransitions
;
94 ::std::map
< sal_Int32
, PDFLinkDestination
> mFutureDestinations
;
96 sal_Int32
GetMappedId();
97 sal_Int32
GetMappedStructId( sal_Int32
);
100 std::vector
< sal_Int32
> mParaIds
;
101 std::vector
< sal_Int32
> mStructIdMap
;
103 sal_Int32 mCurrentStructElement
;
104 std::vector
< sal_Int32
> mStructParents
;
107 mCurrentStructElement( 0 )
109 mStructParents
.push_back( 0 );
110 mStructIdMap
.push_back( 0 );
112 void PlayGlobalActions( PDFWriter
& rWriter
);
115 sal_Int32
GlobalSyncData::GetMappedId()
117 sal_Int32 nLinkId
= mParaInts
.front();
118 mParaInts
.pop_front();
120 /* negative values are intentionally passed as invalid IDs
121 * e.g. to create a new top level outline item
125 if ( o3tl::make_unsigned(nLinkId
) < mParaIds
.size() )
126 nLinkId
= mParaIds
[ nLinkId
];
130 SAL_WARN_IF( nLinkId
< 0, "vcl", "unmapped id in GlobalSyncData" );
136 sal_Int32
GlobalSyncData::GetMappedStructId( sal_Int32 nStructId
)
138 if ( o3tl::make_unsigned(nStructId
) < mStructIdMap
.size() )
139 nStructId
= mStructIdMap
[ nStructId
];
143 SAL_WARN_IF( nStructId
< 0, "vcl", "unmapped structure id in GlobalSyncData" );
148 void GlobalSyncData::PlayGlobalActions( PDFWriter
& rWriter
)
150 for (auto const& action
: mActions
)
154 case PDFExtOutDevDataSync::CreateNamedDest
: //i56629
156 rWriter
.Push( PushFlags::MAPMODE
);
157 rWriter
.SetMapMode( mParaMapModes
.front() );
158 mParaMapModes
.pop_front();
159 mParaIds
.push_back( rWriter
.CreateNamedDest( mParaOUStrings
.front(), mParaRects
.front(), mParaInts
.front(), mParaDestAreaTypes
.front() ) );
160 mParaOUStrings
.pop_front();
161 mParaRects
.pop_front();
162 mParaInts
.pop_front();
163 mParaDestAreaTypes
.pop_front();
167 case PDFExtOutDevDataSync::CreateDest
:
169 rWriter
.Push( PushFlags::MAPMODE
);
170 rWriter
.SetMapMode( mParaMapModes
.front() );
171 mParaMapModes
.pop_front();
172 mParaIds
.push_back( rWriter
.CreateDest( mParaRects
.front(), mParaInts
.front(), mParaDestAreaTypes
.front() ) );
173 mParaRects
.pop_front();
174 mParaInts
.pop_front();
175 mParaDestAreaTypes
.pop_front();
179 case PDFExtOutDevDataSync::CreateLink
:
181 rWriter
.Push( PushFlags::MAPMODE
);
182 rWriter
.SetMapMode( mParaMapModes
.front() );
183 mParaMapModes
.pop_front();
184 mParaIds
.push_back( rWriter
.CreateLink( mParaRects
.front(), mParaInts
.front() ) );
185 // resolve LinkAnnotation structural attribute
186 rWriter
.SetLinkPropertyID( mParaIds
.back(), sal_Int32(mParaIds
.size()-1) );
187 mParaRects
.pop_front();
188 mParaInts
.pop_front();
192 case PDFExtOutDevDataSync::CreateScreen
:
194 rWriter
.Push(PushFlags::MAPMODE
);
195 rWriter
.SetMapMode(mParaMapModes
.front());
196 mParaMapModes
.pop_front();
197 mParaIds
.push_back(rWriter
.CreateScreen(mParaRects
.front(), mParaInts
.front()));
198 mParaRects
.pop_front();
199 mParaInts
.pop_front();
203 case PDFExtOutDevDataSync::SetLinkDest
:
205 sal_Int32 nLinkId
= GetMappedId();
206 sal_Int32 nDestId
= GetMappedId();
207 rWriter
.SetLinkDest( nLinkId
, nDestId
);
210 case PDFExtOutDevDataSync::SetLinkURL
:
212 sal_Int32 nLinkId
= GetMappedId();
213 rWriter
.SetLinkURL( nLinkId
, mParaOUStrings
.front() );
214 mParaOUStrings
.pop_front();
217 case PDFExtOutDevDataSync::SetScreenURL
:
219 sal_Int32 nScreenId
= GetMappedId();
220 rWriter
.SetScreenURL(nScreenId
, mParaOUStrings
.front());
221 mParaOUStrings
.pop_front();
224 case PDFExtOutDevDataSync::SetScreenStream
:
226 sal_Int32 nScreenId
= GetMappedId();
227 rWriter
.SetScreenStream(nScreenId
, mParaOUStrings
.front());
228 mParaOUStrings
.pop_front();
231 case PDFExtOutDevDataSync::RegisterDest
:
233 const sal_Int32 nDestId
= mParaInts
.front();
234 mParaInts
.pop_front();
235 OSL_ENSURE( mFutureDestinations
.find( nDestId
) != mFutureDestinations
.end(),
236 "GlobalSyncData::PlayGlobalActions: DescribeRegisteredRequest has not been called for that destination!" );
238 PDFLinkDestination
& rDest
= mFutureDestinations
[ nDestId
];
240 rWriter
.Push( PushFlags::MAPMODE
);
241 rWriter
.SetMapMode( rDest
.mMapMode
);
242 mParaIds
.push_back( rWriter
.RegisterDestReference( nDestId
, rDest
.mRect
, rDest
.mPageNr
, rDest
.mAreaType
) );
246 case PDFExtOutDevDataSync::CreateOutlineItem
:
248 sal_Int32 nParent
= GetMappedId();
249 sal_Int32 nLinkId
= GetMappedId();
250 mParaIds
.push_back( rWriter
.CreateOutlineItem( nParent
, mParaOUStrings
.front(), nLinkId
) );
251 mParaOUStrings
.pop_front();
254 case PDFExtOutDevDataSync::CreateNote
:
256 rWriter
.Push( PushFlags::MAPMODE
);
257 rWriter
.SetMapMode( mParaMapModes
.front() );
258 rWriter
.CreateNote( mParaRects
.front(), mParaPDFNotes
.front(), mParaInts
.front() );
259 mParaMapModes
.pop_front();
260 mParaRects
.pop_front();
261 mParaPDFNotes
.pop_front();
262 mParaInts
.pop_front();
265 case PDFExtOutDevDataSync::SetPageTransition
:
267 rWriter
.SetPageTransition( mParaPageTransitions
.front(), mParauInts
.front(), mParaInts
.front() );
268 mParaPageTransitions
.pop_front();
269 mParauInts
.pop_front();
270 mParaInts
.pop_front();
273 case PDFExtOutDevDataSync::BeginStructureElement
:
274 case PDFExtOutDevDataSync::EndStructureElement
:
275 case PDFExtOutDevDataSync::SetCurrentStructureElement
:
276 case PDFExtOutDevDataSync::SetStructureAttribute
:
277 case PDFExtOutDevDataSync::SetStructureAttributeNumerical
:
278 case PDFExtOutDevDataSync::SetStructureBoundingBox
:
279 case PDFExtOutDevDataSync::SetActualText
:
280 case PDFExtOutDevDataSync::SetAlternateText
:
281 case PDFExtOutDevDataSync::CreateControl
:
282 case PDFExtOutDevDataSync::BeginGroup
:
283 case PDFExtOutDevDataSync::EndGroupGfxLink
:
291 std::deque
< PDFExtOutDevDataSync
> mActions
;
292 std::deque
< tools::Rectangle
> mParaRects
;
293 std::deque
< sal_Int32
> mParaInts
;
294 std::deque
< OUString
> mParaOUStrings
;
295 std::deque
< PDFWriter::StructElement
> mParaStructElements
;
296 std::deque
< PDFWriter::StructAttribute
> mParaStructAttributes
;
297 std::deque
< PDFWriter::StructAttributeValue
> mParaStructAttributeValues
;
298 std::deque
< Graphic
> mGraphics
;
299 Graphic mCurrentGraphic
;
300 std::deque
< std::shared_ptr
< PDFWriter::AnyWidget
> >
302 GlobalSyncData
* mpGlobalData
;
304 bool mbGroupIgnoreGDIMtfActions
;
307 explicit PageSyncData( GlobalSyncData
* pGlobal
)
308 : mbGroupIgnoreGDIMtfActions ( false )
309 { mpGlobalData
= pGlobal
; }
311 void PushAction( const OutputDevice
& rOutDev
, const PDFExtOutDevDataSync::Action eAct
);
312 bool PlaySyncPageAct( PDFWriter
& rWriter
, sal_uInt32
& rCurGDIMtfAction
, const GDIMetaFile
& rMtf
, const PDFExtOutDevData
& rOutDevData
);
315 void PageSyncData::PushAction( const OutputDevice
& rOutDev
, const PDFExtOutDevDataSync::Action eAct
)
317 GDIMetaFile
* pMtf
= rOutDev
.GetConnectMetaFile();
318 SAL_WARN_IF( !pMtf
, "vcl", "PageSyncData::PushAction -> no ConnectMetaFile !!!" );
320 PDFExtOutDevDataSync aSync
;
323 aSync
.nIdx
= pMtf
->GetActionSize();
325 aSync
.nIdx
= 0x7fffffff; // sync not possible
326 mActions
.push_back( aSync
);
328 bool PageSyncData::PlaySyncPageAct( PDFWriter
& rWriter
, sal_uInt32
& rCurGDIMtfAction
, const GDIMetaFile
& rMtf
, const PDFExtOutDevData
& rOutDevData
)
331 if ( !mActions
.empty() && ( mActions
.front().nIdx
== rCurGDIMtfAction
) )
334 PDFExtOutDevDataSync aDataSync
= mActions
.front();
335 mActions
.pop_front();
336 switch( aDataSync
.eAct
)
338 case PDFExtOutDevDataSync::BeginStructureElement
:
340 sal_Int32 nNewEl
= rWriter
.BeginStructureElement( mParaStructElements
.front(), mParaOUStrings
.front() ) ;
341 mParaStructElements
.pop_front();
342 mParaOUStrings
.pop_front();
343 mpGlobalData
->mStructIdMap
.push_back( nNewEl
);
346 case PDFExtOutDevDataSync::EndStructureElement
:
348 rWriter
.EndStructureElement();
351 case PDFExtOutDevDataSync::SetCurrentStructureElement
:
353 rWriter
.SetCurrentStructureElement( mpGlobalData
->GetMappedStructId( mParaInts
.front() ) );
354 mParaInts
.pop_front();
357 case PDFExtOutDevDataSync::SetStructureAttribute
:
359 rWriter
.SetStructureAttribute( mParaStructAttributes
.front(), mParaStructAttributeValues
.front() );
360 mParaStructAttributeValues
.pop_front();
361 mParaStructAttributes
.pop_front();
364 case PDFExtOutDevDataSync::SetStructureAttributeNumerical
:
366 rWriter
.SetStructureAttributeNumerical( mParaStructAttributes
.front(), mParaInts
.front() );
367 mParaStructAttributes
.pop_front();
368 mParaInts
.pop_front();
371 case PDFExtOutDevDataSync::SetStructureBoundingBox
:
373 rWriter
.SetStructureBoundingBox( mParaRects
.front() );
374 mParaRects
.pop_front();
377 case PDFExtOutDevDataSync::SetActualText
:
379 rWriter
.SetActualText( mParaOUStrings
.front() );
380 mParaOUStrings
.pop_front();
383 case PDFExtOutDevDataSync::SetAlternateText
:
385 rWriter
.SetAlternateText( mParaOUStrings
.front() );
386 mParaOUStrings
.pop_front();
389 case PDFExtOutDevDataSync::CreateControl
:
391 std::shared_ptr
< PDFWriter::AnyWidget
> pControl( mControls
.front() );
392 SAL_WARN_IF( !pControl
, "vcl", "PageSyncData::PlaySyncPageAct: invalid widget!" );
394 rWriter
.CreateControl( *pControl
);
395 mControls
.pop_front();
398 case PDFExtOutDevDataSync::BeginGroup
:
400 /* first determining if this BeginGroup is starting a GfxLink,
401 by searching for an EndGroup or an EndGroupGfxLink */
402 mbGroupIgnoreGDIMtfActions
= false;
403 auto isStartingGfxLink
= std::any_of(mActions
.begin(), mActions
.end(),
404 [](const PDFExtOutDevDataSync
& rAction
) { return rAction
.eAct
== PDFExtOutDevDataSync::EndGroupGfxLink
; });
405 if ( isStartingGfxLink
)
407 Graphic
& rGraphic
= mGraphics
.front();
408 if ( rGraphic
.IsGfxLink() && mParaRects
.size() >= 2 )
410 GfxLinkType eType
= rGraphic
.GetGfxLink().GetType();
411 if ( eType
== GfxLinkType::NativeJpg
)
413 mbGroupIgnoreGDIMtfActions
= rOutDevData
.HasAdequateCompression(rGraphic
, mParaRects
[0], mParaRects
[1]);
414 if ( !mbGroupIgnoreGDIMtfActions
)
415 mCurrentGraphic
= rGraphic
;
417 else if ( eType
== GfxLinkType::NativePng
|| eType
== GfxLinkType::NativePdf
)
419 if ( eType
== GfxLinkType::NativePdf
|| rOutDevData
.HasAdequateCompression(rGraphic
, mParaRects
[0], mParaRects
[1]) )
420 mCurrentGraphic
= rGraphic
;
426 case PDFExtOutDevDataSync::EndGroupGfxLink
:
428 tools::Rectangle aOutputRect
, aVisibleOutputRect
;
429 Graphic
aGraphic( mGraphics
.front() );
431 mGraphics
.pop_front();
432 sal_Int32 nTransparency
= mParaInts
.front();
433 mParaInts
.pop_front();
434 aOutputRect
= mParaRects
.front();
435 mParaRects
.pop_front();
436 aVisibleOutputRect
= mParaRects
.front();
437 mParaRects
.pop_front();
439 if ( mbGroupIgnoreGDIMtfActions
)
441 bool bClippingNeeded
= ( aOutputRect
!= aVisibleOutputRect
) && !aVisibleOutputRect
.IsEmpty();
443 GfxLink
aGfxLink( aGraphic
.GetGfxLink() );
444 if ( aGfxLink
.GetType() == GfxLinkType::NativeJpg
)
446 if ( bClippingNeeded
)
449 basegfx::B2DPolyPolygon
aRect( basegfx::utils::createPolygonFromRect(
450 vcl::unotools::b2DRectangleFromRectangle(aVisibleOutputRect
) ) );
451 rWriter
.SetClipRegion( aRect
);
454 AlphaMask aAlphaMask
;
457 aAlphaMask
= AlphaMask(aGraphic
.GetSizePixel());
458 aAlphaMask
.Erase(nTransparency
);
462 const sal_uInt8
* pData
= aGfxLink
.GetData();
463 sal_uInt32 nBytes
= aGfxLink
.GetDataSize();
464 if( pData
&& nBytes
)
466 aTmp
.WriteBytes( pData
, nBytes
);
468 // Look up the output rectangle from the previous
469 // bitmap scale action if possible. This has the
470 // correct position and size for images with a
471 // custom translation (Writer header) or scaling
472 // (Impress notes page).
473 if (rCurGDIMtfAction
> 0)
475 const MetaAction
* pAction
= rMtf
.GetAction(rCurGDIMtfAction
- 1);
476 if (pAction
&& pAction
->GetType() == MetaActionType::BMPSCALE
)
478 const MetaBmpScaleAction
* pA
479 = static_cast<const MetaBmpScaleAction
*>(pAction
);
480 aOutputRect
.SetPos(pA
->GetPoint());
481 aOutputRect
.SetSize(pA
->GetSize());
484 auto ePixelFormat
= aGraphic
.GetBitmapEx().getPixelFormat();
485 rWriter
.DrawJPGBitmap(aTmp
, ePixelFormat
> vcl::PixelFormat::N8_BPP
, aGraphic
.GetSizePixel(), aOutputRect
, aAlphaMask
, aGraphic
);
488 if ( bClippingNeeded
)
491 mbGroupIgnoreGDIMtfActions
= false;
493 mCurrentGraphic
.Clear();
496 case PDFExtOutDevDataSync::CreateNamedDest
:
497 case PDFExtOutDevDataSync::CreateDest
:
498 case PDFExtOutDevDataSync::CreateLink
:
499 case PDFExtOutDevDataSync::CreateScreen
:
500 case PDFExtOutDevDataSync::SetLinkDest
:
501 case PDFExtOutDevDataSync::SetLinkURL
:
502 case PDFExtOutDevDataSync::SetScreenURL
:
503 case PDFExtOutDevDataSync::SetScreenStream
:
504 case PDFExtOutDevDataSync::RegisterDest
:
505 case PDFExtOutDevDataSync::CreateOutlineItem
:
506 case PDFExtOutDevDataSync::CreateNote
:
507 case PDFExtOutDevDataSync::SetPageTransition
:
511 else if ( mbGroupIgnoreGDIMtfActions
)
519 PDFExtOutDevData::PDFExtOutDevData( const OutputDevice
& rOutDev
) :
520 mrOutDev ( rOutDev
),
521 mbTaggedPDF ( false ),
522 mbExportNotes ( true ),
523 mbExportNotesPages ( false ),
524 mbTransitionEffects ( true ),
525 mbUseLosslessCompression( true ),
526 mbReduceImageResolution ( false ),
527 mbExportFormFields ( false ),
528 mbExportBookmarks ( false ),
529 mbExportHiddenSlides ( false ),
530 mbSinglePageSheets ( false ),
531 mbExportNDests ( false ),
533 mnCompressionQuality ( 90 ),
534 mpGlobalSyncData ( new GlobalSyncData() )
536 mpPageSyncData
.reset( new PageSyncData( mpGlobalSyncData
.get() ) );
539 PDFExtOutDevData::~PDFExtOutDevData()
541 mpPageSyncData
.reset();
542 mpGlobalSyncData
.reset();
545 const Graphic
& PDFExtOutDevData::GetCurrentGraphic() const
547 return mpPageSyncData
->mCurrentGraphic
;
550 void PDFExtOutDevData::SetDocumentLocale( const css::lang::Locale
& rLoc
)
554 void PDFExtOutDevData::SetCurrentPageNumber( const sal_Int32 nPage
)
558 void PDFExtOutDevData::SetIsLosslessCompression( const bool bUseLosslessCompression
)
560 mbUseLosslessCompression
= bUseLosslessCompression
;
562 void PDFExtOutDevData::SetCompressionQuality( const sal_Int32 nQuality
)
564 mnCompressionQuality
= nQuality
;
566 void PDFExtOutDevData::SetIsReduceImageResolution( const bool bReduceImageResolution
)
568 mbReduceImageResolution
= bReduceImageResolution
;
570 void PDFExtOutDevData::SetIsExportNotes( const bool bExportNotes
)
572 mbExportNotes
= bExportNotes
;
574 void PDFExtOutDevData::SetIsExportNotesPages( const bool bExportNotesPages
)
576 mbExportNotesPages
= bExportNotesPages
;
578 void PDFExtOutDevData::SetIsExportTaggedPDF( const bool bTaggedPDF
)
580 mbTaggedPDF
= bTaggedPDF
;
582 void PDFExtOutDevData::SetIsExportTransitionEffects( const bool bTransitionEffects
)
584 mbTransitionEffects
= bTransitionEffects
;
586 void PDFExtOutDevData::SetIsExportFormFields( const bool bExportFomtFields
)
588 mbExportFormFields
= bExportFomtFields
;
590 void PDFExtOutDevData::SetIsExportBookmarks( const bool bExportBookmarks
)
592 mbExportBookmarks
= bExportBookmarks
;
594 void PDFExtOutDevData::SetIsExportHiddenSlides( const bool bExportHiddenSlides
)
596 mbExportHiddenSlides
= bExportHiddenSlides
;
598 void PDFExtOutDevData::SetIsSinglePageSheets( const bool bSinglePageSheets
)
600 mbSinglePageSheets
= bSinglePageSheets
;
602 void PDFExtOutDevData::SetIsExportNamedDestinations( const bool bExportNDests
)
604 mbExportNDests
= bExportNDests
;
606 void PDFExtOutDevData::ResetSyncData()
608 *mpPageSyncData
= PageSyncData( mpGlobalSyncData
.get() );
610 bool PDFExtOutDevData::PlaySyncPageAct( PDFWriter
& rWriter
, sal_uInt32
& rIdx
, const GDIMetaFile
& rMtf
)
612 return mpPageSyncData
->PlaySyncPageAct( rWriter
, rIdx
, rMtf
, *this );
614 void PDFExtOutDevData::PlayGlobalActions( PDFWriter
& rWriter
)
616 mpGlobalSyncData
->PlayGlobalActions( rWriter
);
619 /* global actions, synchronisation to the recorded metafile isn't needed,
620 all actions will be played after the last page was recorded
623 sal_Int32
PDFExtOutDevData::CreateNamedDest(const OUString
& sDestName
, const tools::Rectangle
& rRect
, sal_Int32 nPageNr
)
625 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::CreateNamedDest
);
626 mpGlobalSyncData
->mParaOUStrings
.push_back( sDestName
);
627 mpGlobalSyncData
->mParaRects
.push_back( rRect
);
628 mpGlobalSyncData
->mParaMapModes
.push_back( mrOutDev
.GetMapMode() );
629 mpGlobalSyncData
->mParaInts
.push_back( nPageNr
== -1 ? mnPage
: nPageNr
);
630 mpGlobalSyncData
->mParaDestAreaTypes
.push_back( PDFWriter::DestAreaType::XYZ
);
632 return mpGlobalSyncData
->mCurId
++;
635 sal_Int32
PDFExtOutDevData::RegisterDest()
637 const sal_Int32 nLinkDestID
= mpGlobalSyncData
->mCurId
++;
638 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::RegisterDest
);
639 mpGlobalSyncData
->mParaInts
.push_back( nLinkDestID
);
643 void PDFExtOutDevData::DescribeRegisteredDest( sal_Int32 nDestId
, const tools::Rectangle
& rRect
, sal_Int32 nPageNr
, PDFWriter::DestAreaType eType
)
645 OSL_PRECOND( nDestId
!= -1, "PDFExtOutDevData::DescribeRegisteredDest: invalid destination Id!" );
646 PDFLinkDestination aLinkDestination
;
647 aLinkDestination
.mRect
= rRect
;
648 aLinkDestination
.mMapMode
= mrOutDev
.GetMapMode();
649 aLinkDestination
.mPageNr
= nPageNr
== -1 ? mnPage
: nPageNr
;
650 aLinkDestination
.mAreaType
= eType
;
651 mpGlobalSyncData
->mFutureDestinations
[ nDestId
] = aLinkDestination
;
653 sal_Int32
PDFExtOutDevData::CreateDest( const tools::Rectangle
& rRect
, sal_Int32 nPageNr
, PDFWriter::DestAreaType eType
)
655 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::CreateDest
);
656 mpGlobalSyncData
->mParaRects
.push_back( rRect
);
657 mpGlobalSyncData
->mParaMapModes
.push_back( mrOutDev
.GetMapMode() );
658 mpGlobalSyncData
->mParaInts
.push_back( nPageNr
== -1 ? mnPage
: nPageNr
);
659 mpGlobalSyncData
->mParaDestAreaTypes
.push_back( eType
);
660 return mpGlobalSyncData
->mCurId
++;
662 sal_Int32
PDFExtOutDevData::CreateLink( const tools::Rectangle
& rRect
, sal_Int32 nPageNr
)
664 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::CreateLink
);
665 mpGlobalSyncData
->mParaRects
.push_back( rRect
);
666 mpGlobalSyncData
->mParaMapModes
.push_back( mrOutDev
.GetMapMode() );
667 mpGlobalSyncData
->mParaInts
.push_back( nPageNr
== -1 ? mnPage
: nPageNr
);
668 return mpGlobalSyncData
->mCurId
++;
671 sal_Int32
PDFExtOutDevData::CreateScreen(const tools::Rectangle
& rRect
, sal_Int32 nPageNr
)
673 mpGlobalSyncData
->mActions
.push_back(PDFExtOutDevDataSync::CreateScreen
);
674 mpGlobalSyncData
->mParaRects
.push_back(rRect
);
675 mpGlobalSyncData
->mParaMapModes
.push_back(mrOutDev
.GetMapMode());
676 mpGlobalSyncData
->mParaInts
.push_back(nPageNr
);
677 return mpGlobalSyncData
->mCurId
++;
680 void PDFExtOutDevData::SetLinkDest( sal_Int32 nLinkId
, sal_Int32 nDestId
)
682 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::SetLinkDest
);
683 mpGlobalSyncData
->mParaInts
.push_back( nLinkId
);
684 mpGlobalSyncData
->mParaInts
.push_back( nDestId
);
686 void PDFExtOutDevData::SetLinkURL( sal_Int32 nLinkId
, const OUString
& rURL
)
688 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::SetLinkURL
);
689 mpGlobalSyncData
->mParaInts
.push_back( nLinkId
);
690 mpGlobalSyncData
->mParaOUStrings
.push_back( rURL
);
693 void PDFExtOutDevData::SetScreenURL(sal_Int32 nScreenId
, const OUString
& rURL
)
695 mpGlobalSyncData
->mActions
.push_back(PDFExtOutDevDataSync::SetScreenURL
);
696 mpGlobalSyncData
->mParaInts
.push_back(nScreenId
);
697 mpGlobalSyncData
->mParaOUStrings
.push_back(rURL
);
700 void PDFExtOutDevData::SetScreenStream(sal_Int32 nScreenId
, const OUString
& rURL
)
702 mpGlobalSyncData
->mActions
.push_back(PDFExtOutDevDataSync::SetScreenStream
);
703 mpGlobalSyncData
->mParaInts
.push_back(nScreenId
);
704 mpGlobalSyncData
->mParaOUStrings
.push_back(rURL
);
707 sal_Int32
PDFExtOutDevData::CreateOutlineItem( sal_Int32 nParent
, const OUString
& rText
, sal_Int32 nDestID
)
710 // Has no parent, it's a chapter / heading 1.
711 maChapterNames
.push_back(rText
);
713 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::CreateOutlineItem
);
714 mpGlobalSyncData
->mParaInts
.push_back( nParent
);
715 mpGlobalSyncData
->mParaOUStrings
.push_back( rText
);
716 mpGlobalSyncData
->mParaInts
.push_back( nDestID
);
717 return mpGlobalSyncData
->mCurId
++;
719 void PDFExtOutDevData::CreateNote( const tools::Rectangle
& rRect
, const PDFNote
& rNote
, sal_Int32 nPageNr
)
721 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::CreateNote
);
722 mpGlobalSyncData
->mParaRects
.push_back( rRect
);
723 mpGlobalSyncData
->mParaMapModes
.push_back( mrOutDev
.GetMapMode() );
724 mpGlobalSyncData
->mParaPDFNotes
.push_back( rNote
);
725 mpGlobalSyncData
->mParaInts
.push_back( nPageNr
== -1 ? mnPage
: nPageNr
);
727 void PDFExtOutDevData::SetPageTransition( PDFWriter::PageTransition eType
, sal_uInt32 nMilliSec
)
729 mpGlobalSyncData
->mActions
.push_back( PDFExtOutDevDataSync::SetPageTransition
);
730 mpGlobalSyncData
->mParaPageTransitions
.push_back( eType
);
731 mpGlobalSyncData
->mParauInts
.push_back( nMilliSec
);
732 mpGlobalSyncData
->mParaInts
.push_back( mnPage
);
735 /* local (page), actions have to be played synchronously to the actions of
736 of the recorded metafile (created by each xRenderable->render()) */
737 sal_Int32
PDFExtOutDevData::BeginStructureElement( PDFWriter::StructElement eType
, const OUString
& rAlias
)
739 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::BeginStructureElement
);
740 mpPageSyncData
->mParaStructElements
.push_back( eType
);
741 mpPageSyncData
->mParaOUStrings
.push_back( rAlias
);
743 sal_Int32 nNewId
= mpGlobalSyncData
->mStructParents
.size();
744 mpGlobalSyncData
->mStructParents
.push_back( mpGlobalSyncData
->mCurrentStructElement
);
745 mpGlobalSyncData
->mCurrentStructElement
= nNewId
;
748 void PDFExtOutDevData::EndStructureElement()
750 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::EndStructureElement
);
751 mpGlobalSyncData
->mCurrentStructElement
= mpGlobalSyncData
->mStructParents
[ mpGlobalSyncData
->mCurrentStructElement
];
753 bool PDFExtOutDevData::SetCurrentStructureElement( sal_Int32 nStructId
)
755 bool bSuccess
= false;
756 if( o3tl::make_unsigned(nStructId
) < mpGlobalSyncData
->mStructParents
.size() )
758 mpGlobalSyncData
->mCurrentStructElement
= nStructId
;
759 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::SetCurrentStructureElement
);
760 mpPageSyncData
->mParaInts
.push_back( nStructId
);
765 sal_Int32
PDFExtOutDevData::GetCurrentStructureElement() const
767 return mpGlobalSyncData
->mCurrentStructElement
;
769 void PDFExtOutDevData::SetStructureAttribute( PDFWriter::StructAttribute eAttr
, PDFWriter::StructAttributeValue eVal
)
771 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::SetStructureAttribute
);
772 mpPageSyncData
->mParaStructAttributes
.push_back( eAttr
);
773 mpPageSyncData
->mParaStructAttributeValues
.push_back( eVal
);
775 void PDFExtOutDevData::SetStructureAttributeNumerical( PDFWriter::StructAttribute eAttr
, sal_Int32 nValue
)
777 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::SetStructureAttributeNumerical
);
778 mpPageSyncData
->mParaStructAttributes
.push_back( eAttr
);
779 mpPageSyncData
->mParaInts
.push_back( nValue
);
781 void PDFExtOutDevData::SetStructureBoundingBox( const tools::Rectangle
& rRect
)
783 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::SetStructureBoundingBox
);
784 mpPageSyncData
->mParaRects
.push_back( rRect
);
786 void PDFExtOutDevData::SetActualText( const OUString
& rText
)
788 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::SetActualText
);
789 mpPageSyncData
->mParaOUStrings
.push_back( rText
);
791 void PDFExtOutDevData::SetAlternateText( const OUString
& rText
)
793 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::SetAlternateText
);
794 mpPageSyncData
->mParaOUStrings
.push_back( rText
);
797 void PDFExtOutDevData::CreateControl( const PDFWriter::AnyWidget
& rControlType
)
799 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::CreateControl
);
801 std::shared_ptr
< PDFWriter::AnyWidget
> pClone( rControlType
.Clone() );
802 mpPageSyncData
->mControls
.push_back( pClone
);
805 void PDFExtOutDevData::BeginGroup()
807 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::BeginGroup
);
810 void PDFExtOutDevData::EndGroup( const Graphic
& rGraphic
,
811 sal_uInt8 nTransparency
,
812 const tools::Rectangle
& rOutputRect
,
813 const tools::Rectangle
& rVisibleOutputRect
)
815 mpPageSyncData
->PushAction( mrOutDev
, PDFExtOutDevDataSync::EndGroupGfxLink
);
816 mpPageSyncData
->mGraphics
.push_back( rGraphic
);
817 mpPageSyncData
->mParaInts
.push_back( nTransparency
);
818 mpPageSyncData
->mParaRects
.push_back( rOutputRect
);
819 mpPageSyncData
->mParaRects
.push_back( rVisibleOutputRect
);
822 // Avoids expensive de-compression and re-compression of large images.
823 bool PDFExtOutDevData::HasAdequateCompression( const Graphic
&rGraphic
,
824 const tools::Rectangle
& rOutputRect
,
825 const tools::Rectangle
& rVisibleOutputRect
) const
827 assert(rGraphic
.IsGfxLink() &&
828 (rGraphic
.GetGfxLink().GetType() == GfxLinkType::NativeJpg
||
829 rGraphic
.GetGfxLink().GetType() == GfxLinkType::NativePng
||
830 rGraphic
.GetGfxLink().GetType() == GfxLinkType::NativePdf
));
832 if (rOutputRect
!= rVisibleOutputRect
)
833 // rOutputRect is the crop rectangle, re-compress cropped image.
836 if (mbReduceImageResolution
)
837 // Reducing resolution was requested, implies that re-compressing is
841 auto nSize
= rGraphic
.GetGfxLink().GetDataSize();
845 GfxLink aLink
= rGraphic
.GetGfxLink();
846 SvMemoryStream
aMemoryStream(const_cast<sal_uInt8
*>(aLink
.GetData()), aLink
.GetDataSize(),
847 StreamMode::READ
| StreamMode::WRITE
);
848 GraphicDescriptor
aDescriptor(aMemoryStream
, nullptr);
849 if (aDescriptor
.Detect(true) && aDescriptor
.GetNumberOfImageComponents() == 4)
850 // 4 means CMYK, which is not handled.
853 const Size aSize
= rGraphic
.GetSizePixel();
855 // small items better off as PNG anyway
856 if ( aSize
.Width() < 32 &&
857 aSize
.Height() < 32 )
860 if (GetIsLosslessCompression())
861 return !GetIsReduceImageResolution();
863 // FIXME: ideally we'd also pre-empt the DPI related scaling too.
864 sal_Int32 nCurrentRatio
= (100 * aSize
.Width() * aSize
.Height() * 4) /
867 static const struct {
870 } aRatios
[] = { // minimum tolerable compression ratios
871 { 100, 400 }, { 95, 700 }, { 90, 1000 }, { 85, 1200 },
872 { 80, 1500 }, { 75, 1700 }
874 sal_Int32 nTargetRatio
= 10000;
875 bool bIsTargetRatioReached
= false;
876 for (auto & rRatio
: aRatios
)
878 if ( mnCompressionQuality
> rRatio
.mnQuality
)
880 bIsTargetRatioReached
= true;
883 nTargetRatio
= rRatio
.mnRatio
;
886 return ((nCurrentRatio
> nTargetRatio
) && bIsTargetRatioReached
);
891 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */