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 .
22 #include <tools/UnitConversion.hxx>
23 #include <vcl/graph.hxx>
24 #include <vcl/vectorgraphicdata.hxx>
27 #include <editeng/eeitem.hxx>
28 #include <editeng/fhgtitem.hxx>
29 #include <editeng/wghtitem.hxx>
30 #include <editeng/postitem.hxx>
31 #include <editeng/udlnitem.hxx>
32 #include <editeng/crossedoutitem.hxx>
33 #include <editeng/shdditem.hxx>
34 #include <svx/xlnclit.hxx>
35 #include <svx/xlncapit.hxx>
36 #include <svx/xlnwtit.hxx>
37 #include <svx/xflclit.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <editeng/wrlmitem.hxx>
40 #include <editeng/contouritem.hxx>
41 #include <editeng/colritem.hxx>
42 #include <vcl/metric.hxx>
43 #include <editeng/charscaleitem.hxx>
44 #include <svx/sdtditm.hxx>
45 #include <svx/sdtagitm.hxx>
46 #include <svx/sdtfsitm.hxx>
47 #include <svx/svdmodel.hxx>
48 #include <svx/svdpage.hxx>
49 #include <svx/svdobj.hxx>
50 #include <svx/svdotext.hxx>
51 #include <svx/svdorect.hxx>
52 #include <svx/svdograf.hxx>
53 #include <svx/svdopath.hxx>
54 #include <svx/svdetc.hxx>
55 #include <svl/itemset.hxx>
56 #include <basegfx/polygon/b2dpolygon.hxx>
57 #include <tools/helpers.hxx>
58 #include <basegfx/matrix/b2dhommatrix.hxx>
59 #include <basegfx/matrix/b2dhommatrixtools.hxx>
60 #include <svx/xlinjoit.hxx>
61 #include <svx/xlndsit.hxx>
62 #include <basegfx/polygon/b2dpolygonclipper.hxx>
63 #include <svx/xbtmpit.hxx>
64 #include <svx/xfillit0.hxx>
65 #include <svx/xflbmtit.hxx>
66 #include <svx/xflbstit.hxx>
67 #include <svx/xlineit0.hxx>
68 #include <basegfx/polygon/b2dpolypolygontools.hxx>
69 #include <svx/svditer.hxx>
70 #include <svx/svdogrp.hxx>
71 #include <vcl/dibtools.hxx>
72 #include <sal/log.hxx>
73 #include <osl/diagnose.h>
75 using namespace com::sun::star
;
77 ImpSdrPdfImport::ImpSdrPdfImport(SdrModel
& rModel
, SdrLayerID nLay
, const tools::Rectangle
& rRect
,
78 Graphic
const& rGraphic
)
79 : mpVD(VclPtr
<VirtualDevice
>::Create())
85 , maDash(css::drawing::DashStyle_RECT
, 0, 0, 0, 0, 0)
94 , mbLastObjWasPolyWithoutLine(false)
99 , mpPDFium(vcl::pdf::PDFiumLibrary::get())
101 mpVD
->EnableOutput(false);
102 mpVD
->SetLineColor();
103 mpVD
->SetFillColor();
104 maOldLineColor
.SetRed(mpVD
->GetLineColor().GetRed() + 1);
105 mpLineAttr
= std::make_unique
<SfxItemSetFixed
<XATTR_LINE_FIRST
, XATTR_LINE_LAST
>>(
106 rModel
.GetItemPool());
107 mpFillAttr
= std::make_unique
<SfxItemSetFixed
<XATTR_FILL_FIRST
, XATTR_FILL_LAST
>>(
108 rModel
.GetItemPool());
110 = std::make_unique
<SfxItemSetFixed
<EE_ITEMS_START
, EE_ITEMS_END
>>(rModel
.GetItemPool());
114 // Load the buffer using pdfium.
115 auto const& rVectorGraphicData
= rGraphic
.getVectorGraphicData();
116 auto* pData
= rVectorGraphicData
->getBinaryDataContainer().getData();
117 sal_Int32 nSize
= rVectorGraphicData
->getBinaryDataContainer().getSize();
118 mpPdfDocument
= mpPDFium
? mpPDFium
->openDocument(pData
, nSize
, OString()) : nullptr;
122 mnPageCount
= mpPdfDocument
->getPageCount();
125 ImpSdrPdfImport::~ImpSdrPdfImport() = default;
127 void ImpSdrPdfImport::DoObjects(SvdProgressInfo
* pProgrInfo
, sal_uInt32
* pActionsToReport
,
130 const int nPageCount
= mpPdfDocument
->getPageCount();
131 if (!(nPageCount
> 0 && nPageIndex
>= 0 && nPageIndex
< nPageCount
))
135 auto pPdfPage
= mpPdfDocument
->openPage(nPageIndex
);
139 basegfx::B2DSize dPageSize
= mpPdfDocument
->getPageSize(nPageIndex
);
141 SetupPageScale(dPageSize
.getWidth(), dPageSize
.getHeight());
143 // Load the page text to extract it when we get text elements.
144 auto pTextPage
= pPdfPage
->getTextPage();
146 const int nPageObjectCount
= pPdfPage
->getObjectCount();
148 pProgrInfo
->SetActionCount(nPageObjectCount
);
150 for (int nPageObjectIndex
= 0; nPageObjectIndex
< nPageObjectCount
; ++nPageObjectIndex
)
152 auto pPageObject
= pPdfPage
->getObject(nPageObjectIndex
);
153 ImportPdfObject(pPageObject
, pTextPage
, nPageObjectIndex
);
154 if (pProgrInfo
&& pActionsToReport
)
156 (*pActionsToReport
)++;
158 if (*pActionsToReport
>= 16)
160 if (!pProgrInfo
->ReportActions(*pActionsToReport
))
163 *pActionsToReport
= 0;
169 void ImpSdrPdfImport::SetupPageScale(const double dPageWidth
, const double dPageHeight
)
171 mfScaleX
= mfScaleY
= 1.0;
173 // Store the page dimensions in Points.
174 mdPageHeightPts
= dPageHeight
;
176 Size
aPageSize(convertPointToMm100(dPageWidth
), convertPointToMm100(dPageHeight
));
178 if (aPageSize
.Width() && aPageSize
.Height() && (!maScaleRect
.IsEmpty()))
180 maOfs
= maScaleRect
.TopLeft();
182 if (aPageSize
.Width() != (maScaleRect
.GetWidth() - 1))
184 mfScaleX
= static_cast<double>(maScaleRect
.GetWidth() - 1)
185 / static_cast<double>(aPageSize
.Width());
188 if (aPageSize
.Height() != (maScaleRect
.GetHeight() - 1))
190 mfScaleY
= static_cast<double>(maScaleRect
.GetHeight() - 1)
191 / static_cast<double>(aPageSize
.Height());
195 mbMov
= maOfs
.X() != 0 || maOfs
.Y() != 0;
197 maScaleX
= Fraction(1, 1);
198 maScaleY
= Fraction(1, 1);
200 if (aPageSize
.Width() != (maScaleRect
.GetWidth() - 1))
202 maScaleX
= Fraction(maScaleRect
.GetWidth() - 1, aPageSize
.Width());
206 if (aPageSize
.Height() != (maScaleRect
.GetHeight() - 1))
208 maScaleY
= Fraction(maScaleRect
.GetHeight() - 1, aPageSize
.Height());
213 size_t ImpSdrPdfImport::DoImport(SdrObjList
& rOL
, size_t nInsPos
, int nPageNumber
,
214 SvdProgressInfo
* pProgrInfo
)
216 sal_uInt32
nActionsToReport(0);
219 DoObjects(pProgrInfo
, &nActionsToReport
, nPageNumber
);
223 pProgrInfo
->ReportActions(nActionsToReport
);
224 nActionsToReport
= 0;
230 // To calculate the progress meter, we use GetActionSize()*3.
231 // However, maTmpList has a lower entry count limit than GetActionSize(),
232 // so the actions that were assumed were too much have to be re-added.
233 // nActionsToReport = (rMtf.GetActionSize() - maTmpList.size()) * 2;
235 // announce all currently unannounced rescales
238 pProgrInfo
->ReportRescales(nActionsToReport
);
239 pProgrInfo
->SetInsertCount(maTmpList
.size());
242 nActionsToReport
= 0;
244 // insert all objects cached in aTmpList now into rOL from nInsPos
245 nInsPos
= std::min(nInsPos
, rOL
.GetObjCount());
247 for (rtl::Reference
<SdrObject
>& pObj
: maTmpList
)
249 rOL
.NbcInsertObject(pObj
.get(), nInsPos
);
256 if (nActionsToReport
>= 32) // update all 32 actions
258 pProgrInfo
->ReportInserts(nActionsToReport
);
259 nActionsToReport
= 0;
264 // report all remaining inserts for the last time
267 pProgrInfo
->ReportInserts(nActionsToReport
);
270 return maTmpList
.size();
273 void ImpSdrPdfImport::SetAttributes(SdrObject
* pObj
, bool bForceTextAttr
)
277 bool bLine(!bForceTextAttr
);
278 bool bFill(!pObj
|| (pObj
->IsClosedObj() && !bForceTextAttr
));
279 bool bText(bForceTextAttr
|| (pObj
&& pObj
->GetOutlinerParaObject()));
285 mpLineAttr
->Put(XLineWidthItem(mnLineWidth
));
289 mpLineAttr
->Put(XLineWidthItem(0));
292 maOldLineColor
= mpVD
->GetLineColor();
294 if (mpVD
->IsLineColor())
296 mpLineAttr
->Put(XLineStyleItem(drawing::LineStyle_SOLID
)); //TODO support dashed lines.
297 mpLineAttr
->Put(XLineColorItem(OUString(), mpVD
->GetLineColor()));
301 mpLineAttr
->Put(XLineStyleItem(drawing::LineStyle_NONE
));
304 mpLineAttr
->Put(XLineJointItem(css::drawing::LineJoint_NONE
));
306 // Add LineCap support
307 mpLineAttr
->Put(XLineCapItem(gaLineCap
));
309 if (((maDash
.GetDots() && maDash
.GetDotLen())
310 || (maDash
.GetDashes() && maDash
.GetDashLen()))
311 && maDash
.GetDistance())
313 mpLineAttr
->Put(XLineDashItem(OUString(), maDash
));
317 mpLineAttr
->Put(XLineDashItem(OUString(), XDash(css::drawing::DashStyle_RECT
)));
327 if (mpVD
->IsFillColor())
329 mpFillAttr
->Put(XFillStyleItem(drawing::FillStyle_SOLID
));
330 mpFillAttr
->Put(XFillColorItem(OUString(), mpVD
->GetFillColor()));
334 mpFillAttr
->Put(XFillStyleItem(drawing::FillStyle_NONE
));
342 if (bText
&& mbFntDirty
)
344 vcl::Font
aFnt(mpVD
->GetFont());
345 const sal_uInt32
nHeight(FRound(aFnt
.GetFontSize().Height() * mfScaleY
));
347 mpTextAttr
->Put(SvxFontItem(aFnt
.GetFamilyType(), aFnt
.GetFamilyName(), aFnt
.GetStyleName(),
348 aFnt
.GetPitch(), aFnt
.GetCharSet(), EE_CHAR_FONTINFO
));
349 mpTextAttr
->Put(SvxFontItem(aFnt
.GetFamilyType(), aFnt
.GetFamilyName(), aFnt
.GetStyleName(),
350 aFnt
.GetPitch(), aFnt
.GetCharSet(), EE_CHAR_FONTINFO_CJK
));
351 mpTextAttr
->Put(SvxFontItem(aFnt
.GetFamilyType(), aFnt
.GetFamilyName(), aFnt
.GetStyleName(),
352 aFnt
.GetPitch(), aFnt
.GetCharSet(), EE_CHAR_FONTINFO_CTL
));
353 mpTextAttr
->Put(SvxPostureItem(aFnt
.GetItalic(), EE_CHAR_ITALIC
));
354 mpTextAttr
->Put(SvxWeightItem(aFnt
.GetWeight(), EE_CHAR_WEIGHT
));
355 mpTextAttr
->Put(SvxFontHeightItem(nHeight
, 100, EE_CHAR_FONTHEIGHT
));
356 mpTextAttr
->Put(SvxFontHeightItem(nHeight
, 100, EE_CHAR_FONTHEIGHT_CJK
));
357 mpTextAttr
->Put(SvxFontHeightItem(nHeight
, 100, EE_CHAR_FONTHEIGHT_CTL
));
358 mpTextAttr
->Put(SvxCharScaleWidthItem(100, EE_CHAR_FONTWIDTH
));
359 mpTextAttr
->Put(SvxUnderlineItem(aFnt
.GetUnderline(), EE_CHAR_UNDERLINE
));
360 mpTextAttr
->Put(SvxOverlineItem(aFnt
.GetOverline(), EE_CHAR_OVERLINE
));
361 mpTextAttr
->Put(SvxCrossedOutItem(aFnt
.GetStrikeout(), EE_CHAR_STRIKEOUT
));
362 mpTextAttr
->Put(SvxShadowedItem(aFnt
.IsShadow(), EE_CHAR_SHADOW
));
364 // #i118485# Setting this item leads to problems (written #i118498# for this)
365 // mpTextAttr->Put(SvxAutoKernItem(aFnt.IsKerning(), EE_CHAR_KERNING));
367 mpTextAttr
->Put(SvxWordLineModeItem(aFnt
.IsWordLineMode(), EE_CHAR_WLM
));
368 mpTextAttr
->Put(SvxContourItem(aFnt
.IsOutline(), EE_CHAR_OUTLINE
));
369 mpTextAttr
->Put(SvxColorItem(mpVD
->GetTextColor(), EE_CHAR_COLOR
));
370 //... svxfont textitem svditext
377 pObj
->SetLayer(mnLayer
);
381 pObj
->SetMergedItemSet(*mpLineAttr
);
386 pObj
->SetMergedItemSet(*mpFillAttr
);
391 pObj
->SetMergedItemSet(*mpTextAttr
);
392 pObj
->SetMergedItem(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT
));
396 void ImpSdrPdfImport::InsertObj(SdrObject
* pObj1
, bool bScale
)
398 rtl::Reference
<SdrObject
> pObj
= pObj1
;
399 if (bScale
&& !maScaleRect
.IsEmpty())
403 pObj
->NbcResize(Point(), maScaleX
, maScaleY
);
408 pObj
->NbcMove(Size(maOfs
.X(), maOfs
.Y()));
414 const basegfx::B2DPolyPolygon
aPoly(pObj
->TakeXorPoly());
415 const basegfx::B2DRange
aOldRange(aPoly
.getB2DRange());
416 const SdrLayerID
aOldLayer(pObj
->GetLayer());
417 const SfxItemSet
aOldItemSet(pObj
->GetMergedItemSet());
418 const SdrGrafObj
* pSdrGrafObj
= dynamic_cast<SdrGrafObj
*>(pObj
.get());
419 const SdrTextObj
* pSdrTextObj
= DynCastSdrTextObj(pObj
.get());
421 if (pSdrTextObj
&& pSdrTextObj
->HasText())
423 // all text objects are created from ImportText and have no line or fill attributes, so
424 // it is okay to concentrate on the text itself
427 const basegfx::B2DPolyPolygon
aTextContour(pSdrTextObj
->TakeContour());
428 const basegfx::B2DRange
aTextRange(aTextContour
.getB2DRange());
429 const basegfx::B2DRange
aClipRange(maClip
.getB2DRange());
431 // no overlap -> completely outside
432 if (!aClipRange
.overlaps(aTextRange
))
438 // when the clip is a rectangle fast check for inside is possible
439 if (basegfx::utils::isRectangle(maClip
) && aClipRange
.isInside(aTextRange
))
441 // completely inside ClipRect
445 // here text needs to be clipped; to do so, convert to SdrObjects with polygons
446 // and add these recursively. Delete original object, do not add in this run
447 rtl::Reference
<SdrObject
> pConverted
= pSdrTextObj
->ConvertToPolyObj(true, true);
451 // recursively add created conversion; per definition this shall not
452 // contain further SdrTextObjs. Visit only non-group objects
453 SdrObjListIter
aIter(*pConverted
, SdrIterMode::DeepNoGroups
);
455 // work with clones; the created conversion may contain group objects
456 // and when working with the original objects the loop itself could
457 // break and the cleanup later would be pretty complicated (only delete group
458 // objects, are these empty, ...?)
459 while (aIter
.IsMore())
461 SdrObject
* pCandidate
= aIter
.Next();
462 OSL_ENSURE(pCandidate
&& dynamic_cast<SdrObjGroup
*>(pCandidate
) == nullptr,
463 "SdrObjListIter with SdrIterMode::DeepNoGroups error (!)");
464 rtl::Reference
<SdrObject
> pNewClone(
465 pCandidate
->CloneSdrObject(pCandidate
->getSdrModelFromSdrObject()));
469 InsertObj(pNewClone
.get(), false);
473 OSL_ENSURE(false, "SdrObject::Clone() failed (!)");
487 aBitmapEx
= pSdrGrafObj
->GetGraphic().GetBitmapEx();
492 if (!aOldRange
.isEmpty())
494 // clip against ClipRegion
495 const basegfx::B2DPolyPolygon
aNewPoly(basegfx::utils::clipPolyPolygonOnPolyPolygon(
496 aPoly
, maClip
, true, !aPoly
.isClosed()));
497 const basegfx::B2DRange
aNewRange(aNewPoly
.getB2DRange());
499 if (!aNewRange
.isEmpty())
501 pObj
= new SdrPathObj(
502 *mpModel
, aNewPoly
.isClosed() ? SdrObjKind::Polygon
: SdrObjKind::PolyLine
,
505 pObj
->SetLayer(aOldLayer
);
506 pObj
->SetMergedItemSet(aOldItemSet
);
508 if (!aBitmapEx
.IsEmpty())
510 // aNewRange is inside of aOldRange and defines which part of aBitmapEx is used
511 const double fScaleX(aBitmapEx
.GetSizePixel().Width()
512 / (aOldRange
.getWidth() ? aOldRange
.getWidth() : 1.0));
513 const double fScaleY(
514 aBitmapEx
.GetSizePixel().Height()
515 / (aOldRange
.getHeight() ? aOldRange
.getHeight() : 1.0));
516 basegfx::B2DRange
aPixel(aNewRange
);
517 basegfx::B2DHomMatrix aTrans
;
519 aTrans
.translate(-aOldRange
.getMinX(), -aOldRange
.getMinY());
520 aTrans
.scale(fScaleX
, fScaleY
);
521 aPixel
.transform(aTrans
);
523 const Size
aOrigSizePixel(aBitmapEx
.GetSizePixel());
524 const Point
aClipTopLeft(
525 basegfx::fround(floor(std::max(0.0, aPixel
.getMinX()))),
526 basegfx::fround(floor(std::max(0.0, aPixel
.getMinY()))));
527 const Size
aClipSize(
528 basegfx::fround(ceil(std::min(
529 static_cast<double>(aOrigSizePixel
.Width()), aPixel
.getWidth()))),
531 ceil(std::min(static_cast<double>(aOrigSizePixel
.Height()),
532 aPixel
.getHeight()))));
533 const BitmapEx
aClippedBitmap(aBitmapEx
, aClipTopLeft
, aClipSize
);
535 pObj
->SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP
));
536 pObj
->SetMergedItem(XFillBitmapItem(OUString(), Graphic(aClippedBitmap
)));
537 pObj
->SetMergedItem(XFillBmpTileItem(false));
538 pObj
->SetMergedItem(XFillBmpStretchItem(true));
548 // #i111954# check object for visibility
549 // used are SdrPathObj, SdrRectObj, SdrCircObj, SdrGrafObj
550 bool bVisible(false);
552 if (pObj
->HasLineStyle())
557 if (!bVisible
&& pObj
->HasFillStyle())
564 SdrTextObj
* pTextObj
= DynCastSdrTextObj(pObj
.get());
566 if (pTextObj
&& pTextObj
->HasText())
574 SdrGrafObj
* pGrafObj
= dynamic_cast<SdrGrafObj
*>(pObj
.get());
578 // this may be refined to check if the graphic really is visible. It
579 // is here to ensure that graphic objects without fill, line and text
587 maTmpList
.push_back(pObj
);
589 if (dynamic_cast<SdrPathObj
*>(pObj
.get()))
591 const bool bClosed(pObj
->IsClosedObj());
593 mbLastObjWasPolyWithoutLine
= mbNoLine
&& bClosed
;
597 mbLastObjWasPolyWithoutLine
= false;
602 bool ImpSdrPdfImport::CheckLastPolyLineAndFillMerge(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
604 // #i73407# reformulation to use new B2DPolygon classes
605 if (mbLastObjWasPolyWithoutLine
)
607 SdrObject
* pTmpObj
= !maTmpList
.empty() ? maTmpList
[maTmpList
.size() - 1].get() : nullptr;
608 SdrPathObj
* pLastPoly
= dynamic_cast<SdrPathObj
*>(pTmpObj
);
612 if (pLastPoly
->GetPathPoly() == rPolyPolygon
)
614 SetAttributes(nullptr);
616 if (!mbNoLine
&& mbNoFill
)
618 pLastPoly
->SetMergedItemSet(*mpLineAttr
);
629 void ImpSdrPdfImport::checkClip()
631 if (mpVD
->IsClipRegion())
633 maClip
= mpVD
->GetClipRegion().GetAsB2DPolyPolygon();
637 const basegfx::B2DHomMatrix
aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(
638 mfScaleX
, mfScaleY
, maOfs
.X(), maOfs
.Y()));
640 maClip
.transform(aTransform
);
645 bool ImpSdrPdfImport::isClip() const { return !maClip
.getB2DRange().isEmpty(); }
646 void ImpSdrPdfImport::ImportPdfObject(
647 std::unique_ptr
<vcl::pdf::PDFiumPageObject
> const& pPageObject
,
648 std::unique_ptr
<vcl::pdf::PDFiumTextPage
> const& pTextPage
, int nPageObjectIndex
)
653 const vcl::pdf::PDFPageObjectType ePageObjectType
= pPageObject
->getType();
654 switch (ePageObjectType
)
656 case vcl::pdf::PDFPageObjectType::Text
:
657 ImportText(pPageObject
, pTextPage
, nPageObjectIndex
);
659 case vcl::pdf::PDFPageObjectType::Path
:
660 ImportPath(pPageObject
, nPageObjectIndex
);
662 case vcl::pdf::PDFPageObjectType::Image
:
663 ImportImage(pPageObject
, nPageObjectIndex
);
665 case vcl::pdf::PDFPageObjectType::Shading
:
666 SAL_WARN("sd.filter", "Got page object SHADING: " << nPageObjectIndex
);
668 case vcl::pdf::PDFPageObjectType::Form
:
669 ImportForm(pPageObject
, pTextPage
, nPageObjectIndex
);
672 SAL_WARN("sd.filter", "Unknown PDF page object #" << nPageObjectIndex
<< " of type: "
673 << static_cast<int>(ePageObjectType
));
678 void ImpSdrPdfImport::ImportForm(std::unique_ptr
<vcl::pdf::PDFiumPageObject
> const& pPageObject
,
679 std::unique_ptr
<vcl::pdf::PDFiumTextPage
> const& pTextPage
,
680 int /*nPageObjectIndex*/)
682 // Get the form matrix to perform correct translation/scaling of the form sub-objects.
683 const basegfx::B2DHomMatrix aOldMatrix
= maCurrentMatrix
;
685 maCurrentMatrix
= pPageObject
->getMatrix();
687 const int nCount
= pPageObject
->getFormObjectCount();
688 for (int nIndex
= 0; nIndex
< nCount
; ++nIndex
)
690 auto pFormObject
= pPageObject
->getFormObject(nIndex
);
692 ImportPdfObject(pFormObject
, pTextPage
, -1);
695 // Restore the old one.
696 maCurrentMatrix
= aOldMatrix
;
699 void ImpSdrPdfImport::ImportText(std::unique_ptr
<vcl::pdf::PDFiumPageObject
> const& pPageObject
,
700 std::unique_ptr
<vcl::pdf::PDFiumTextPage
> const& pTextPage
,
701 int /*nPageObjectIndex*/)
703 basegfx::B2DRectangle aTextRect
= pPageObject
->getBounds();
704 basegfx::B2DHomMatrix aMatrix
= pPageObject
->getMatrix();
706 basegfx::B2DHomMatrix
aTextMatrix(maCurrentMatrix
);
708 aTextRect
*= aTextMatrix
;
709 const tools::Rectangle aRect
= PointsToLogic(aTextRect
.getMinX(), aTextRect
.getMaxX(),
710 aTextRect
.getMinY(), aTextRect
.getMaxY());
712 OUString sText
= pPageObject
->getText(pTextPage
);
714 const double dFontSize
= pPageObject
->getFontSize();
715 double dFontSizeH
= fabs(std::hypot(aMatrix
.a(), aMatrix
.c()) * dFontSize
);
716 double dFontSizeV
= fabs(std::hypot(aMatrix
.b(), aMatrix
.d()) * dFontSize
);
718 dFontSizeH
= convertPointToMm100(dFontSizeH
);
719 dFontSizeV
= convertPointToMm100(dFontSizeV
);
721 const Size
aFontSize(dFontSizeH
, dFontSizeV
);
722 vcl::Font aFnt
= mpVD
->GetFont();
723 if (aFontSize
!= aFnt
.GetFontSize())
725 aFnt
.SetFontSize(aFontSize
);
730 OUString sFontName
= pPageObject
->getFontName();
731 if (!sFontName
.isEmpty() && sFontName
!= aFnt
.GetFamilyName())
733 aFnt
.SetFamilyName(sFontName
);
738 Color
aTextColor(COL_TRANSPARENT
);
741 switch (pPageObject
->getTextRenderMode())
743 case vcl::pdf::PDFTextRenderMode::Fill
:
744 case vcl::pdf::PDFTextRenderMode::FillClip
:
745 case vcl::pdf::PDFTextRenderMode::FillStroke
:
746 case vcl::pdf::PDFTextRenderMode::FillStrokeClip
:
749 case vcl::pdf::PDFTextRenderMode::Stroke
:
750 case vcl::pdf::PDFTextRenderMode::StrokeClip
:
751 case vcl::pdf::PDFTextRenderMode::Unknown
:
753 case vcl::pdf::PDFTextRenderMode::Invisible
:
754 case vcl::pdf::PDFTextRenderMode::Clip
:
760 Color aColor
= bFill
? pPageObject
->getFillColor() : pPageObject
->getStrokeColor();
761 if (aColor
!= COL_TRANSPARENT
)
762 aTextColor
= aColor
.GetRGBColor();
765 if (aTextColor
!= mpVD
->GetTextColor())
767 mpVD
->SetTextColor(aTextColor
);
771 InsertTextObject(aRect
.TopLeft(), aRect
.GetSize(), sText
);
774 void ImpSdrPdfImport::InsertTextObject(const Point
& rPos
, const Size
& rSize
, const OUString
& rStr
)
776 // calc text box size, add 5% to make it fit safely
778 FontMetric
aFontMetric(mpVD
->GetFontMetric());
779 vcl::Font
aFont(mpVD
->GetFont());
780 TextAlign
eAlignment(aFont
.GetAlignment());
782 // sal_Int32 nTextWidth = static_cast<sal_Int32>(mpVD->GetTextWidth(rStr) * mfScaleX);
783 sal_Int32 nTextHeight
= static_cast<sal_Int32
>(mpVD
->GetTextHeight() * mfScaleY
);
785 Point
aPosition(FRound(rPos
.X() * mfScaleX
+ maOfs
.X()),
786 FRound(rPos
.Y() * mfScaleY
+ maOfs
.Y()));
787 Size
aSize(FRound(rSize
.Width() * mfScaleX
), FRound(rSize
.Height() * mfScaleY
));
789 if (eAlignment
== ALIGN_BASELINE
)
790 aPosition
.AdjustY(-FRound(aFontMetric
.GetAscent() * mfScaleY
));
791 else if (eAlignment
== ALIGN_BOTTOM
)
792 aPosition
.AdjustY(-nTextHeight
);
794 tools::Rectangle
aTextRect(aPosition
, aSize
);
795 rtl::Reference
<SdrRectObj
> pText
= new SdrRectObj(*mpModel
, SdrObjKind::Text
, aTextRect
);
797 pText
->SetMergedItem(makeSdrTextUpperDistItem(0));
798 pText
->SetMergedItem(makeSdrTextLowerDistItem(0));
799 pText
->SetMergedItem(makeSdrTextRightDistItem(0));
800 pText
->SetMergedItem(makeSdrTextLeftDistItem(0));
802 if (aFont
.GetAverageFontWidth())
804 pText
->ClearMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH
);
805 pText
->SetMergedItem(makeSdrTextAutoGrowHeightItem(false));
806 // don't let the margins eat the space needed for the text
807 pText
->SetMergedItem(SdrTextFitToSizeTypeItem(drawing::TextFitToSizeType_ALLLINES
));
811 pText
->SetMergedItem(makeSdrTextAutoGrowWidthItem(true));
814 pText
->SetLayer(mnLayer
);
815 pText
->NbcSetText(rStr
);
816 SetAttributes(pText
.get(), true);
817 pText
->SetSnapRect(aTextRect
);
819 if (!aFont
.IsTransparent())
821 SfxItemSetFixed
<XATTR_FILL_FIRST
, XATTR_FILL_LAST
> aAttr(*mpFillAttr
->GetPool());
822 aAttr
.Put(XFillStyleItem(drawing::FillStyle_SOLID
));
823 aAttr
.Put(XFillColorItem(OUString(), aFont
.GetFillColor()));
824 pText
->SetMergedItemSet(aAttr
);
826 Degree100 nAngle
= to
<Degree100
>(aFont
.GetOrientation());
828 pText
->SdrAttrObj::NbcRotate(aPosition
, nAngle
);
829 InsertObj(pText
.get(), false);
832 void ImpSdrPdfImport::MapScaling()
834 const size_t nCount(maTmpList
.size());
835 const MapMode
& rMap
= mpVD
->GetMapMode();
836 Point
aMapOrg(rMap
.GetOrigin());
837 bool bMov2(aMapOrg
.X() != 0 || aMapOrg
.Y() != 0);
841 for (size_t i
= mnMapScalingOfs
; i
< nCount
; i
++)
843 SdrObject
* pObj
= maTmpList
[i
].get();
845 pObj
->NbcMove(Size(aMapOrg
.X(), aMapOrg
.Y()));
849 mnMapScalingOfs
= nCount
;
852 void ImpSdrPdfImport::ImportImage(std::unique_ptr
<vcl::pdf::PDFiumPageObject
> const& pPageObject
,
853 int /*nPageObjectIndex*/)
855 std::unique_ptr
<vcl::pdf::PDFiumBitmap
> bitmap
= pPageObject
->getImageBitmap();
858 SAL_WARN("sd.filter", "Failed to get IMAGE");
862 const vcl::pdf::PDFBitmapType format
= bitmap
->getFormat();
863 if (format
== vcl::pdf::PDFBitmapType::Unknown
)
865 SAL_WARN("sd.filter", "Failed to get IMAGE format");
869 const unsigned char* pBuf
= bitmap
->getBuffer();
870 const int nWidth
= bitmap
->getWidth();
871 const int nHeight
= bitmap
->getHeight();
872 const int nStride
= bitmap
->getStride();
873 BitmapEx
aBitmap(Size(nWidth
, nHeight
), vcl::PixelFormat::N24_BPP
);
877 case vcl::pdf::PDFBitmapType::BGR
:
878 ReadRawDIB(aBitmap
, pBuf
, ScanlineFormat::N24BitTcBgr
, nHeight
, nStride
);
880 case vcl::pdf::PDFBitmapType::BGRx
:
881 ReadRawDIB(aBitmap
, pBuf
, ScanlineFormat::N32BitTcRgba
, nHeight
, nStride
);
883 case vcl::pdf::PDFBitmapType::BGRA
:
884 ReadRawDIB(aBitmap
, pBuf
, ScanlineFormat::N32BitTcBgra
, nHeight
, nStride
);
887 SAL_WARN("sd.filter", "Got IMAGE width: " << nWidth
<< ", height: " << nHeight
888 << ", stride: " << nStride
889 << ", format: " << static_cast<int>(format
));
893 basegfx::B2DRectangle aBounds
= pPageObject
->getBounds();
894 float left
= aBounds
.getMinX();
896 float bottom
= aBounds
.getMinY();
897 float right
= aBounds
.getMaxX();
899 float top
= aBounds
.getMaxY();
900 tools::Rectangle aRect
= PointsToLogic(left
, right
, top
, bottom
);
901 aRect
.AdjustRight(1);
902 aRect
.AdjustBottom(1);
904 rtl::Reference
<SdrGrafObj
> pGraf
= new SdrGrafObj(*mpModel
, Graphic(aBitmap
), aRect
);
906 // This action is not creating line and fill, set directly, do not use SetAttributes(..)
907 pGraf
->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE
));
908 pGraf
->SetMergedItem(XFillStyleItem(drawing::FillStyle_NONE
));
909 InsertObj(pGraf
.get());
912 void ImpSdrPdfImport::ImportPath(std::unique_ptr
<vcl::pdf::PDFiumPageObject
> const& pPageObject
,
913 int /*nPageObjectIndex*/)
915 auto aPathMatrix
= pPageObject
->getMatrix();
917 aPathMatrix
*= maCurrentMatrix
;
919 basegfx::B2DPolyPolygon aPolyPoly
;
920 basegfx::B2DPolygon aPoly
;
921 std::vector
<basegfx::B2DPoint
> aBezier
;
923 const int nSegments
= pPageObject
->getPathSegmentCount();
924 for (int nSegmentIndex
= 0; nSegmentIndex
< nSegments
; ++nSegmentIndex
)
926 auto pPathSegment
= pPageObject
->getPathSegment(nSegmentIndex
);
927 if (pPathSegment
!= nullptr)
929 basegfx::B2DPoint aB2DPoint
= pPathSegment
->getPoint();
930 aB2DPoint
*= aPathMatrix
;
932 const bool bClose
= pPathSegment
->isClosed();
934 aPoly
.setClosed(bClose
); // TODO: Review
936 Point aPoint
= PointsToLogic(aB2DPoint
.getX(), aB2DPoint
.getY());
937 aB2DPoint
.setX(aPoint
.X());
938 aB2DPoint
.setY(aPoint
.Y());
940 const vcl::pdf::PDFSegmentType eSegmentType
= pPathSegment
->getType();
941 switch (eSegmentType
)
943 case vcl::pdf::PDFSegmentType::Lineto
:
944 aPoly
.append(aB2DPoint
);
947 case vcl::pdf::PDFSegmentType::Bezierto
:
948 aBezier
.emplace_back(aB2DPoint
.getX(), aB2DPoint
.getY());
949 if (aBezier
.size() == 3)
951 aPoly
.appendBezierSegment(aBezier
[0], aBezier
[1], aBezier
[2]);
956 case vcl::pdf::PDFSegmentType::Moveto
:
958 if (aPoly
.count() > 0)
960 aPolyPoly
.append(aPoly
, 1);
964 aPoly
.append(aB2DPoint
);
967 case vcl::pdf::PDFSegmentType::Unknown
:
969 SAL_WARN("sd.filter", "Unknown path segment type in PDF: "
970 << static_cast<int>(eSegmentType
));
976 if (aBezier
.size() == 3)
978 aPoly
.appendBezierSegment(aBezier
[0], aBezier
[1], aBezier
[2]);
982 if (aPoly
.count() > 0)
984 aPolyPoly
.append(aPoly
, 1);
988 const basegfx::B2DHomMatrix
aTransform(
989 basegfx::utils::createScaleTranslateB2DHomMatrix(mfScaleX
, mfScaleY
, maOfs
.X(), maOfs
.Y()));
990 aPolyPoly
.transform(aTransform
);
992 float fWidth
= pPageObject
->getStrokeWidth();
993 const double dWidth
= 0.5 * fabs(std::hypot(aPathMatrix
.a(), aPathMatrix
.c()) * fWidth
);
994 mnLineWidth
= convertPointToMm100(dWidth
);
996 vcl::pdf::PDFFillMode nFillMode
= vcl::pdf::PDFFillMode::Alternate
;
997 bool bStroke
= true; // Assume we have to draw, unless told otherwise.
998 if (pPageObject
->getDrawMode(nFillMode
, bStroke
))
1000 if (nFillMode
== vcl::pdf::PDFFillMode::Alternate
)
1001 mpVD
->SetDrawMode(DrawModeFlags::Default
);
1002 else if (nFillMode
== vcl::pdf::PDFFillMode::Winding
)
1003 mpVD
->SetDrawMode(DrawModeFlags::Default
);
1005 mpVD
->SetDrawMode(DrawModeFlags::NoFill
);
1008 mpVD
->SetFillColor(pPageObject
->getFillColor());
1012 mpVD
->SetLineColor(pPageObject
->getStrokeColor());
1015 mpVD
->SetLineColor(COL_TRANSPARENT
);
1017 if (!mbLastObjWasPolyWithoutLine
|| !CheckLastPolyLineAndFillMerge(aPolyPoly
))
1019 rtl::Reference
<SdrPathObj
> pPath
1020 = new SdrPathObj(*mpModel
, SdrObjKind::Polygon
, std::move(aPolyPoly
));
1021 SetAttributes(pPath
.get());
1022 InsertObj(pPath
.get(), false);
1026 Point
ImpSdrPdfImport::PointsToLogic(double x
, double y
) const
1028 y
= correctVertOrigin(y
);
1030 Point
aPos(convertPointToMm100(x
), convertPointToMm100(y
));
1034 tools::Rectangle
ImpSdrPdfImport::PointsToLogic(double left
, double right
, double top
,
1035 double bottom
) const
1037 top
= correctVertOrigin(top
);
1038 bottom
= correctVertOrigin(bottom
);
1040 Point
aPos(convertPointToMm100(left
), convertPointToMm100(top
));
1041 Size
aSize(convertPointToMm100(right
- left
), convertPointToMm100(bottom
- top
));
1043 return tools::Rectangle(aPos
, aSize
);
1046 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */