bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / gdi / pdfextoutdevdata.cxx
blob96a77a15d94dc1c9b786b183169c14bddb2a2d02
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
34 #include <memory>
35 #include <map>
37 namespace vcl
39 namespace {
41 struct PDFExtOutDevDataSync
43 enum Action{ CreateNamedDest,
44 CreateDest,
45 CreateLink,
46 CreateScreen,
47 SetLinkDest,
48 SetLinkURL,
49 SetScreenURL,
50 SetScreenStream,
51 RegisterDest,
52 CreateOutlineItem,
53 CreateNote,
54 SetPageTransition,
56 BeginStructureElement,
57 EndStructureElement,
58 SetCurrentStructureElement,
59 SetStructureAttribute,
60 SetStructureAttributeNumerical,
61 SetStructureBoundingBox,
62 SetActualText,
63 SetAlternateText,
64 CreateControl,
65 BeginGroup,
66 EndGroupGfxLink
69 sal_uInt32 nIdx;
70 Action eAct;
73 struct PDFLinkDestination
75 tools::Rectangle mRect;
76 MapMode mMapMode;
77 sal_Int32 mPageNr;
78 PDFWriter::DestAreaType mAreaType;
83 struct GlobalSyncData
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 );
99 sal_Int32 mCurId;
100 std::vector< sal_Int32 > mParaIds;
101 std::vector< sal_Int32 > mStructIdMap;
103 sal_Int32 mCurrentStructElement;
104 std::vector< sal_Int32 > mStructParents;
105 GlobalSyncData() :
106 mCurId ( 0 ),
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
123 if( nLinkId >= 0 )
125 if ( o3tl::make_unsigned(nLinkId) < mParaIds.size() )
126 nLinkId = mParaIds[ nLinkId ];
127 else
128 nLinkId = -1;
130 SAL_WARN_IF( nLinkId < 0, "vcl", "unmapped id in GlobalSyncData" );
133 return nLinkId;
136 sal_Int32 GlobalSyncData::GetMappedStructId( sal_Int32 nStructId )
138 if ( o3tl::make_unsigned(nStructId) < mStructIdMap.size() )
139 nStructId = mStructIdMap[ nStructId ];
140 else
141 nStructId = -1;
143 SAL_WARN_IF( nStructId < 0, "vcl", "unmapped structure id in GlobalSyncData" );
145 return nStructId;
148 void GlobalSyncData::PlayGlobalActions( PDFWriter& rWriter )
150 for (auto const& action : mActions)
152 switch (action)
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();
164 rWriter.Pop();
166 break;
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();
176 rWriter.Pop();
178 break;
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();
189 rWriter.Pop();
191 break;
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();
200 rWriter.Pop();
202 break;
203 case PDFExtOutDevDataSync::SetLinkDest :
205 sal_Int32 nLinkId = GetMappedId();
206 sal_Int32 nDestId = GetMappedId();
207 rWriter.SetLinkDest( nLinkId, nDestId );
209 break;
210 case PDFExtOutDevDataSync::SetLinkURL :
212 sal_Int32 nLinkId = GetMappedId();
213 rWriter.SetLinkURL( nLinkId, mParaOUStrings.front() );
214 mParaOUStrings.pop_front();
216 break;
217 case PDFExtOutDevDataSync::SetScreenURL:
219 sal_Int32 nScreenId = GetMappedId();
220 rWriter.SetScreenURL(nScreenId, mParaOUStrings.front());
221 mParaOUStrings.pop_front();
223 break;
224 case PDFExtOutDevDataSync::SetScreenStream:
226 sal_Int32 nScreenId = GetMappedId();
227 rWriter.SetScreenStream(nScreenId, mParaOUStrings.front());
228 mParaOUStrings.pop_front();
230 break;
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 ) );
243 rWriter.Pop();
245 break;
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();
253 break;
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();
264 break;
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();
272 break;
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:
284 break;
289 struct PageSyncData
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 > >
301 mControls;
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;
321 aSync.eAct = eAct;
322 if ( pMtf )
323 aSync.nIdx = pMtf->GetActionSize();
324 else
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 )
330 bool bRet = false;
331 if ( !mActions.empty() && ( mActions.front().nIdx == rCurGDIMtfAction ) )
333 bRet = true;
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 );
345 break;
346 case PDFExtOutDevDataSync::EndStructureElement :
348 rWriter.EndStructureElement();
350 break;
351 case PDFExtOutDevDataSync::SetCurrentStructureElement:
353 rWriter.SetCurrentStructureElement( mpGlobalData->GetMappedStructId( mParaInts.front() ) );
354 mParaInts.pop_front();
356 break;
357 case PDFExtOutDevDataSync::SetStructureAttribute :
359 rWriter.SetStructureAttribute( mParaStructAttributes.front(), mParaStructAttributeValues.front() );
360 mParaStructAttributeValues.pop_front();
361 mParaStructAttributes.pop_front();
363 break;
364 case PDFExtOutDevDataSync::SetStructureAttributeNumerical :
366 rWriter.SetStructureAttributeNumerical( mParaStructAttributes.front(), mParaInts.front() );
367 mParaStructAttributes.pop_front();
368 mParaInts.pop_front();
370 break;
371 case PDFExtOutDevDataSync::SetStructureBoundingBox :
373 rWriter.SetStructureBoundingBox( mParaRects.front() );
374 mParaRects.pop_front();
376 break;
377 case PDFExtOutDevDataSync::SetActualText :
379 rWriter.SetActualText( mParaOUStrings.front() );
380 mParaOUStrings.pop_front();
382 break;
383 case PDFExtOutDevDataSync::SetAlternateText :
385 rWriter.SetAlternateText( mParaOUStrings.front() );
386 mParaOUStrings.pop_front();
388 break;
389 case PDFExtOutDevDataSync::CreateControl:
391 std::shared_ptr< PDFWriter::AnyWidget > pControl( mControls.front() );
392 SAL_WARN_IF( !pControl, "vcl", "PageSyncData::PlaySyncPageAct: invalid widget!" );
393 if ( pControl )
394 rWriter.CreateControl( *pControl );
395 mControls.pop_front();
397 break;
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;
425 break;
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 )
448 rWriter.Push();
449 basegfx::B2DPolyPolygon aRect( basegfx::utils::createPolygonFromRect(
450 vcl::unotools::b2DRectangleFromRectangle(aVisibleOutputRect) ) );
451 rWriter.SetClipRegion( aRect);
454 AlphaMask aAlphaMask;
455 if (nTransparency)
457 aAlphaMask = AlphaMask(aGraphic.GetSizePixel());
458 aAlphaMask.Erase(nTransparency);
461 SvMemoryStream aTmp;
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 )
489 rWriter.Pop();
491 mbGroupIgnoreGDIMtfActions = false;
493 mCurrentGraphic.Clear();
495 break;
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:
508 break;
511 else if ( mbGroupIgnoreGDIMtfActions )
513 rCurGDIMtfAction++;
514 bRet = true;
516 return bRet;
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 ),
532 mnPage ( -1 ),
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 )
552 maDocLocale = rLoc;
554 void PDFExtOutDevData::SetCurrentPageNumber( const sal_Int32 nPage )
556 mnPage = 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
622 //--->i56629
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++;
634 //<---i56629
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 );
641 return 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 )
709 if (nParent == -1)
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 );
742 // need a global id
743 sal_Int32 nNewId = mpGlobalSyncData->mStructParents.size();
744 mpGlobalSyncData->mStructParents.push_back( mpGlobalSyncData->mCurrentStructElement );
745 mpGlobalSyncData->mCurrentStructElement = nNewId;
746 return 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 );
761 bSuccess = true;
763 return bSuccess;
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.
834 return false;
836 if (mbReduceImageResolution)
837 // Reducing resolution was requested, implies that re-compressing is
838 // wanted.
839 return false;
841 auto nSize = rGraphic.GetGfxLink().GetDataSize();
842 if (nSize == 0)
843 return false;
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.
851 return false;
853 const Size aSize = rGraphic.GetSizePixel();
855 // small items better off as PNG anyway
856 if ( aSize.Width() < 32 &&
857 aSize.Height() < 32 )
858 return false;
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) /
865 nSize;
867 static const struct {
868 sal_Int32 mnQuality;
869 sal_Int32 mnRatio;
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;
881 break;
883 nTargetRatio = rRatio.mnRatio;
886 return ((nCurrentRatio > nTargetRatio) && bIsTargetRatioReached);
891 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */