external/pdfium/UnpackedTarball_pdfium.mk | 1 external/pdfium/extractpatterns.patch | 183 ++++++++++++++++++++++++++++++ include/vcl/filter/PDFiumLibrary.hxx | 6 sd/qa/unit/data/pdf/pattern-fill.pdf |binary sd/qa/unit/data/pdf/pattern-stroke.pdf |binary sd/qa/unit/export-tests.cxx | 42 ++++++ svx/source/inc/svdpdf.hxx | 12 + svx/source/svdraw/svdpdf.cxx | 91 ++++++++++++-- vcl/source/pdf/PDFiumLibrary.cxx | 34 +++++ 9 files changed, 354 insertions(+), 15 deletions(-)
New commits: commit 0a5a3cb93308973d38a37b6ec983ecd6b57c748e Author: Caolán McNamara <[email protected]> AuthorDate: Thu Oct 16 16:06:38 2025 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Tue Oct 21 08:50:11 2025 +0200 extract fill/stroke patterns as bitmaps We can apply fill patterns as tiled bitmap fill. For strokes/text-color apply center color of pattern as the color to use. Change-Id: I123184d19363c0f0e0a2988108efdb71ff3d34f4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192552 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/external/pdfium/UnpackedTarball_pdfium.mk b/external/pdfium/UnpackedTarball_pdfium.mk index b86756f35743..8da991373c8c 100644 --- a/external/pdfium/UnpackedTarball_pdfium.mk +++ b/external/pdfium/UnpackedTarball_pdfium.mk @@ -24,6 +24,7 @@ pdfium_patches += tounicodeinfo.patch.1 # TODO, attempt upstream pdfium_patches += ofz451333752.patch +pdfium_patches += extractpatterns.patch $(eval $(call gb_UnpackedTarball_UnpackedTarball,pdfium)) diff --git a/external/pdfium/extractpatterns.patch b/external/pdfium/extractpatterns.patch new file mode 100644 index 000000000000..f742c30d949b --- /dev/null +++ b/external/pdfium/extractpatterns.patch @@ -0,0 +1,183 @@ +--- core/fpdfapi/page/cpdf_pattern.h 2025-10-17 15:44:08.393532043 +0100 ++++ core/fpdfapi/page/cpdf_pattern.h 2025-10-17 15:44:12.020459390 +0100 +@@ -26,6 +26,7 @@ + virtual CPDF_ShadingPattern* AsShadingPattern(); + + const CFX_Matrix& pattern_to_form() const { return m_Pattern2Form; } ++ RetainPtr<CPDF_Object> pattern_obj() const { return m_pPatternObj; } + + protected: + CPDF_Pattern(CPDF_Document* pDoc, +@@ -35,7 +36,6 @@ + + // All the getters that return pointers return non-NULL pointers. + CPDF_Document* document() const { return m_pDocument; } +- RetainPtr<CPDF_Object> pattern_obj() const { return m_pPatternObj; } + const CFX_Matrix& parent_matrix() const { return m_ParentMatrix; } + + void SetPatternToFormMatrix(); +--- fpdfsdk/fpdf_edittext.cpp 2025-10-17 15:44:08.410532151 +0100 ++++ fpdfsdk/fpdf_edittext.cpp 2025-10-17 15:55:18.804847559 +0100 +@@ -13,6 +13,9 @@ + #include "core/fpdfapi/font/cpdf_cidfont.h" + #include "core/fpdfapi/font/cpdf_font.h" + #include "core/fpdfapi/page/cpdf_docpagedata.h" ++#include "core/fpdfapi/page/cpdf_form.h" ++#include "core/fpdfapi/page/cpdf_pathobject.h" ++#include "core/fpdfapi/page/cpdf_tilingpattern.h" + #include "core/fpdfapi/page/cpdf_textobject.h" + #include "core/fpdfapi/page/cpdf_textstate.h" + #include "core/fpdfapi/parser/cpdf_array.h" +@@ -834,6 +835,108 @@ + return FPDFBitmapFromCFXDIBitmap(result_bitmap.Leak()); + } + ++FPDF_BITMAP ++FPDFPageObj_GetRenderedPattern(CPDF_Pattern& pattern, ++ CPDF_Document& doc, ++ CPDF_PageObject& pageObj, ++ CPDF_Page* optional_page) { ++ CPDF_TilingPattern* pTilingPattern = pattern.AsTilingPattern(); ++ if (!pTilingPattern) ++ return nullptr; ++ const std::unique_ptr<CPDF_Form> pPatternForm = pTilingPattern->Load(&pageObj); ++ if (!pPatternForm) ++ return nullptr; ++ RetainPtr<const CPDF_Dictionary> pDict = pattern.pattern_obj()->GetDict(); ++ CFX_FloatRect pattern_bbox = pDict->GetRectFor("BBox"); ++ ++ // `rect` has to use integer values. Round up as needed. ++ const FX_RECT rect = pattern_bbox.GetOuterRect(); ++ if (rect.IsEmpty()) ++ return nullptr; ++ ++ auto result_bitmap = pdfium::MakeRetain<CFX_DIBitmap>(); ++ if (!result_bitmap->Create(rect.Width(), rect.Height(), ++ FXDIB_Format::kBgra)) { ++ return nullptr; ++ } ++ CFX_FloatRect cell_bbox = pattern.pattern_to_form().TransformRect(pattern_bbox); ++ CFX_FloatRect bitmap_rect(0.0f, 0.0f, rect.Width(), rect.Height()); ++ CFX_Matrix mtPattern2Bitmap; ++ mtPattern2Bitmap.MatchRect(bitmap_rect, cell_bbox); ++ ++ CFX_DefaultRenderDevice bitmap_device; ++ bitmap_device.AttachWithBackdropAndGroupKnockout( ++ result_bitmap, /*pBackdropBitmap=*/nullptr, /*bGroupKnockout=*/true); ++ ++ CPDF_RenderOptions options; ++ if (!pTilingPattern->colored()) ++ options.SetColorMode(CPDF_RenderOptions::kAlpha); ++ options.GetOptions().bForceHalftone = true; ++ ++ CPDF_RenderContext context(&doc, nullptr, nullptr); ++ context.AppendLayer(pPatternForm.get(), mtPattern2Bitmap); ++ context.Render(&bitmap_device, nullptr, &options, nullptr); ++ ++ CHECK(!result_bitmap->IsPremultiplied()); ++ ++ // Caller takes ownership. ++ return FPDFBitmapFromCFXDIBitmap(result_bitmap.Leak()); ++} ++ ++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV ++FPDFPageObj_GetRenderedStrokePattern(FPDF_DOCUMENT document, ++ FPDF_PAGE page, ++ FPDF_PAGEOBJECT page_object) { ++ CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document); ++ if (!doc) ++ return nullptr; ++ ++ CPDF_Page* optional_page = CPDFPageFromFPDFPage(page); ++ if (optional_page && optional_page->GetDocument() != doc) ++ return nullptr; ++ ++ CPDF_PageObject* object = CPDFPageObjectFromFPDFPageObject(page_object); ++ if (!object) ++ return nullptr; ++ ++ const CPDF_Color* stroke = object->color_state().GetStrokeColor(); ++ if (!stroke || !stroke->IsPattern()) ++ return nullptr; ++ ++ RetainPtr<CPDF_Pattern> pattern = stroke->GetPattern(); ++ if (!pattern) ++ return nullptr; ++ ++ return FPDFPageObj_GetRenderedPattern(*pattern, *doc, *object, optional_page); ++} ++ ++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV ++FPDFPageObj_GetRenderedFillPattern(FPDF_DOCUMENT document, ++ FPDF_PAGE page, ++ FPDF_PAGEOBJECT page_object) { ++ CPDF_Document* doc = CPDFDocumentFromFPDFDocument(document); ++ if (!doc) ++ return nullptr; ++ ++ CPDF_Page* optional_page = CPDFPageFromFPDFPage(page); ++ if (optional_page && optional_page->GetDocument() != doc) ++ return nullptr; ++ ++ CPDF_PageObject* object = CPDFPageObjectFromFPDFPageObject(page_object); ++ if (!object) ++ return nullptr; ++ ++ const CPDF_Color* fill = object->color_state().GetFillColor(); ++ if (!fill || !fill->IsPattern()) ++ return nullptr; ++ ++ RetainPtr<CPDF_Pattern> pattern = fill->GetPattern(); ++ if (!pattern) ++ return nullptr; ++ ++ return FPDFPageObj_GetRenderedPattern(*pattern, *doc, *object, optional_page); ++} ++ + FPDF_EXPORT void FPDF_CALLCONV FPDFFont_Close(FPDF_FONT font) { + // Take back ownership from caller and release. + RetainPtr<CPDF_Font>().Unleak(CPDFFontFromFPDFFont(font)); +--- public/fpdf_edit.h 2025-10-17 15:44:08.415888612 +0100 ++++ public/fpdf_edit.h 2025-10-17 15:44:12.022555158 +0100 +@@ -1417,6 +1417,41 @@ + float scale); + + // Experimental API. ++// Get a bitmap rasterization of the stroke pattern of |page object|. ++// To render correctly, the caller must provide the |document| associated with ++// |page_object|. If there is a |page| associated with |page_object|, the ++// caller should provide that as well. The returned bitmap will be owned by ++// the caller, and FPDFBitmap_Destroy() must be called on the returned bitmap ++// when it is no longer needed. ++// ++// document - handle to a document associated with |page_object|. ++// page - handle to an optional page associated with |page_object|. ++// page_object - handle to a page object. ++// ++// Returns the bitmap or NULL if the stroke is not a pattern or on failure. ++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV ++FPDFPageObj_GetRenderedStrokePattern(FPDF_DOCUMENT document, ++ FPDF_PAGE page, ++ FPDF_PAGEOBJECT page_object); ++ ++// Get a bitmap rasterization of the fill pattern of |page object|. ++// To render correctly, the caller must provide the |document| associated with ++// |page_object|. If there is a |page| associated with |page_object|, the ++// caller should provide that as well. The returned bitmap will be owned by ++// the caller, and FPDFBitmap_Destroy() must be called on the returned bitmap ++// when it is no longer needed. ++// ++// document - handle to a document associated with |page_object|. ++// page - handle to an optional page associated with |page_object|. ++// page_object - handle to a page object. ++// ++// Returns the bitmap or NULL if the fill is not a pattern or on failure. ++FPDF_EXPORT FPDF_BITMAP FPDF_CALLCONV ++FPDFPageObj_GetRenderedFillPattern(FPDF_DOCUMENT document, ++ FPDF_PAGE page, ++ FPDF_PAGEOBJECT page_object); ++ ++// Experimental API. + // Get the font of a text object. + // + // text - the handle to the text object. diff --git a/include/vcl/filter/PDFiumLibrary.hxx b/include/vcl/filter/PDFiumLibrary.hxx index be1f4866ec7f..4665172068d0 100644 --- a/include/vcl/filter/PDFiumLibrary.hxx +++ b/include/vcl/filter/PDFiumLibrary.hxx @@ -165,8 +165,14 @@ public: virtual bool getFontProperties(FontWeight& weight) = 0; virtual PDFTextRenderMode getTextRenderMode() = 0; virtual Color getFillColor() = 0; + virtual std::unique_ptr<PDFiumBitmap> getRenderedFillPattern(PDFiumDocument& rDoc, + PDFiumPage& rPage) + = 0; virtual Color getStrokeColor() = 0; virtual double getStrokeWidth() = 0; + virtual std::unique_ptr<PDFiumBitmap> getRenderedStrokePattern(PDFiumDocument& rDoc, + PDFiumPage& rPage) + = 0; // Path virtual int getPathSegmentCount() = 0; virtual std::unique_ptr<PDFiumPathSegment> getPathSegment(int index) = 0; diff --git a/sd/qa/unit/data/pdf/pattern-fill.pdf b/sd/qa/unit/data/pdf/pattern-fill.pdf new file mode 100644 index 000000000000..d5c4f0acebf9 Binary files /dev/null and b/sd/qa/unit/data/pdf/pattern-fill.pdf differ diff --git a/sd/qa/unit/data/pdf/pattern-stroke.pdf b/sd/qa/unit/data/pdf/pattern-stroke.pdf new file mode 100644 index 000000000000..ce26b39e295c Binary files /dev/null and b/sd/qa/unit/data/pdf/pattern-stroke.pdf differ diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx index 753b6e0e365f..13b97f0bf33b 100644 --- a/sd/qa/unit/export-tests.cxx +++ b/sd/qa/unit/export-tests.cxx @@ -1223,6 +1223,48 @@ CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfEmbeddedFonts) "and @loext:font-style='normal']/office:binary-data"); } +CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfPatternStroke) +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + return; + UsePdfium aGuard; + + loadFromFile(u"pdf/pattern-stroke.pdf"); + + setFilterOptions("{\"DecomposePDF\":{\"type\":\"boolean\",\"value\":\"true\"}}"); + save(u"OpenDocument Drawing Flat XML"_ustr); + + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + + // ensure the stroke color is this redish color, and not gray which is what it + // defaults to if the stroke pattern isn't taken into account. + assertXPath(pXmlDoc, "/office:document/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties[@svg:stroke-color='#ed1b2d']"); +} + +CPPUNIT_TEST_FIXTURE(SdExportTest, testExplodedPdfPatternFill) +{ + auto pPdfium = vcl::pdf::PDFiumLibrary::get(); + if (!pPdfium) + return; + UsePdfium aGuard; + + loadFromFile(u"pdf/pattern-fill.pdf"); + + setFilterOptions("{\"DecomposePDF\":{\"type\":\"boolean\",\"value\":\"true\"}}"); + save(u"OpenDocument Drawing Flat XML"_ustr); + + xmlDocUniquePtr pXmlDoc = parseExportedFile(); + + // ensure the stroke color is this redish color, and not gray which is what it + // defaults to if the stroke pattern isn't taken into account. + assertXPath(pXmlDoc, "/office:document/office:automatic-styles/style:style[@style:name='gr1']/" + "style:graphic-properties[@style:repeat='repeat' and " + "@draw:fill-image-width='1.27cm' and @draw:fill-image-height='1.27cm' and " + "@draw:fill-image-name='Bitmap_20_1']"); +} + CPPUNIT_TEST_FIXTURE(SdExportTest, testEmbeddedText) { createSdDrawDoc("objectwithtext.fodg"); diff --git a/svx/source/inc/svdpdf.hxx b/svx/source/inc/svdpdf.hxx index fbea79b404fb..73d43ebee2fb 100644 --- a/svx/source/inc/svdpdf.hxx +++ b/svx/source/inc/svdpdf.hxx @@ -109,6 +109,8 @@ class ImpSdrPdfImport final sal_Int32 mnLineWidth; static constexpr css::drawing::LineCap gaLineCap = css::drawing::LineCap_BUTT; XDash maDash; + std::optional<Color> moFillColor; + std::optional<BitmapEx> moFillPattern; bool mbMov; bool mbSize; @@ -147,17 +149,25 @@ class ImpSdrPdfImport final void checkClip(); bool isClip() const; + Color getStrokeColor(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage); + Color getFillColor(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage); + void ImportPdfObject(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int nPageObjectIndex); void ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int nPageObjectIndex); void ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, int nPageObjectIndex); void ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, - int nPageObjectIndex); + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, int nPageObjectIndex); void ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int nPageObjectIndex); void InsertTextObject(const Point& rPos, const Size& rSize, const OUString& rStr, diff --git a/svx/source/svdraw/svdpdf.cxx b/svx/source/svdraw/svdpdf.cxx index 629f770c1d3a..4d1bf340573e 100644 --- a/svx/source/svdraw/svdpdf.cxx +++ b/svx/source/svdraw/svdpdf.cxx @@ -32,6 +32,7 @@ #include <editeng/udlnitem.hxx> #include <editeng/crossedoutitem.hxx> #include <editeng/shdditem.hxx> +#include <svx/xflbmsxy.hxx> #include <svx/xlnclit.hxx> #include <svx/xlncapit.hxx> #include <svx/xlnwtit.hxx> @@ -128,7 +129,6 @@ ImpSdrPdfImport::ImpSdrPdfImport(SdrModel& rModel, SdrLayerID nLay, const tools: mpVD->SetMapMode(MapMode(MapUnit::Map100thMM)); mpVD->EnableOutput(false); mpVD->SetLineColor(); - mpVD->SetFillColor(); // Get TextBounds relative to baseline vcl::Font aFnt = mpVD->GetFont(); @@ -379,7 +379,7 @@ void ImpSdrPdfImport::DoObjects(SvdProgressInfo* pProgrInfo, sal_uInt32* pAction for (int nPageObjectIndex = 0; nPageObjectIndex < nPageObjectCount; ++nPageObjectIndex) { auto pPageObject = pPdfPage->getObject(nPageObjectIndex); - ImportPdfObject(pPageObject, pTextPage, nPageObjectIndex); + ImportPdfObject(pPageObject, pPdfPage, pTextPage, nPageObjectIndex); if (pProgrInfo && pActionsToReport) { (*pActionsToReport)++; @@ -552,10 +552,29 @@ void ImpSdrPdfImport::SetAttributes(SdrObject* pObj, bool bForceTextAttr) if (bFill) { - if (mpVD->IsFillColor()) + bool doFill + = mpVD->GetDrawMode() != DrawModeFlags::NoFill && (moFillColor || moFillPattern); + if (doFill && moFillColor) + doFill = !moFillColor->IsTransparent(); + if (doFill) { - mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID)); - mpFillAttr->Put(XFillColorItem(OUString(), mpVD->GetFillColor())); + if (moFillColor) + { + mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_SOLID)); + mpFillAttr->Put(XFillColorItem(OUString(), *moFillColor)); + } + else + { + assert(moFillPattern && "pattern should exist"); + mpFillAttr->Put(XFillStyleItem(drawing::FillStyle_BITMAP)); + mpFillAttr->Put(XFillBitmapItem(OUString(), Graphic(*moFillPattern))); + mpFillAttr->Put(XFillBmpStretchItem(false)); + mpFillAttr->Put(XFillBmpTileItem(true)); + mpFillAttr->Put( + XFillBmpSizeXItem(convertPointToMm100(moFillPattern->GetSizePixel().Width()))); + mpFillAttr->Put( + XFillBmpSizeYItem(convertPointToMm100(moFillPattern->GetSizePixel().Height()))); + } } else { @@ -874,6 +893,7 @@ void ImpSdrPdfImport::checkClip() bool ImpSdrPdfImport::isClip() const { return !maClip.getB2DRange().isEmpty(); } void ImpSdrPdfImport::ImportPdfObject( std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int nPageObjectIndex) { if (!pPageObject) @@ -883,10 +903,10 @@ void ImpSdrPdfImport::ImportPdfObject( switch (ePageObjectType) { case vcl::pdf::PDFPageObjectType::Text: - ImportText(pPageObject, pTextPage, nPageObjectIndex); + ImportText(pPageObject, pPage, pTextPage, nPageObjectIndex); break; case vcl::pdf::PDFPageObjectType::Path: - ImportPath(pPageObject, nPageObjectIndex); + ImportPath(pPageObject, pPage, nPageObjectIndex); break; case vcl::pdf::PDFPageObjectType::Image: ImportImage(pPageObject, nPageObjectIndex); @@ -895,7 +915,7 @@ void ImpSdrPdfImport::ImportPdfObject( SAL_WARN("sd.filter", "Got page object SHADING: " << nPageObjectIndex); break; case vcl::pdf::PDFPageObjectType::Form: - ImportForm(pPageObject, pTextPage, nPageObjectIndex); + ImportForm(pPageObject, pPage, pTextPage, nPageObjectIndex); break; default: SAL_WARN("sd.filter", "Unknown PDF page object #" << nPageObjectIndex << " of type: " @@ -905,6 +925,7 @@ void ImpSdrPdfImport::ImportPdfObject( } void ImpSdrPdfImport::ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int /*nPageObjectIndex*/) { @@ -918,7 +939,7 @@ void ImpSdrPdfImport::ImportForm(std::unique_ptr<vcl::pdf::PDFiumPageObject> con { auto pFormObject = pPageObject->getFormObject(nIndex); - ImportPdfObject(pFormObject, pTextPage, -1); + ImportPdfObject(pFormObject, pPage, pTextPage, -1); } // Restore the old one. @@ -1754,7 +1775,39 @@ EmbeddedFontInfo ImpSdrPdfImport::convertToOTF(SubSetInfo& rSubSetInfo, const OU #endif +// There isn't, as far as I know, a way to stroke with a pattern at the moment, +// so extract some sensible color if this is a stroke pattern +Color ImpSdrPdfImport::getStrokeColor( + std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage) +{ + if (std::unique_ptr<vcl::pdf::PDFiumBitmap> bitmap + = pPageObject->getRenderedStrokePattern(*mpPdfDocument, *pPage)) + { + BitmapEx aBitmap(bitmap->createBitmapFromBuffer()); + return aBitmap.GetPixelColor(aBitmap.GetSizePixel().Width() / 2, + aBitmap.GetSizePixel().Height() / 2); + } + return pPageObject->getStrokeColor(); +} + +// Typically for a fill pattern you want to use some pattern fill equivalent +// but if that's not possible then this fallback can be useful +Color ImpSdrPdfImport::getFillColor(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage) +{ + if (std::unique_ptr<vcl::pdf::PDFiumBitmap> bitmap + = pPageObject->getRenderedFillPattern(*mpPdfDocument, *pPage)) + { + BitmapEx aBitmap(bitmap->createBitmapFromBuffer()); + return aBitmap.GetPixelColor(aBitmap.GetSizePixel().Width() / 2, + aBitmap.GetSizePixel().Height() / 2); + } + return pPageObject->getFillColor(); +} + void ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, std::unique_ptr<vcl::pdf::PDFiumTextPage> const& pTextPage, int /*nPageObjectIndex*/) { @@ -1844,7 +1897,8 @@ void ImpSdrPdfImport::ImportText(std::unique_ptr<vcl::pdf::PDFiumPageObject> con } if (bUse) { - Color aColor = bFill ? pPageObject->getFillColor() : pPageObject->getStrokeColor(); + Color aColor + = bFill ? getFillColor(pPageObject, pPage) : getStrokeColor(pPageObject, pPage); if (aColor != COL_TRANSPARENT) aTextColor = aColor.GetRGBColor(); } @@ -1979,6 +2033,7 @@ void ImpSdrPdfImport::ImportImage(std::unique_ptr<vcl::pdf::PDFiumPageObject> co } void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> const& pPageObject, + std::unique_ptr<vcl::pdf::PDFiumPage> const& pPage, int /*nPageObjectIndex*/) { auto aPathMatrix = pPageObject->getMatrix(); @@ -2074,12 +2129,20 @@ void ImpSdrPdfImport::ImportPath(std::unique_ptr<vcl::pdf::PDFiumPageObject> con mpVD->SetDrawMode(DrawModeFlags::NoFill); } - mpVD->SetFillColor(pPageObject->getFillColor()); - - if (bStroke) + if (std::unique_ptr<vcl::pdf::PDFiumBitmap> bitmap + = pPageObject->getRenderedFillPattern(*mpPdfDocument, *pPage)) { - mpVD->SetLineColor(pPageObject->getStrokeColor()); + moFillPattern = bitmap->createBitmapFromBuffer(); + moFillColor.reset(); } + else + { + moFillColor = pPageObject->getFillColor(); + moFillPattern.reset(); + } + + if (bStroke) + mpVD->SetLineColor(getStrokeColor(pPageObject, pPage)); else mpVD->SetLineColor(COL_TRANSPARENT); diff --git a/vcl/source/pdf/PDFiumLibrary.cxx b/vcl/source/pdf/PDFiumLibrary.cxx index 1307cf12795c..cb2ff7f377a5 100644 --- a/vcl/source/pdf/PDFiumLibrary.cxx +++ b/vcl/source/pdf/PDFiumLibrary.cxx @@ -426,8 +426,12 @@ public: bool getFontProperties(FontWeight& weight) override; PDFTextRenderMode getTextRenderMode() override; Color getFillColor() override; + std::unique_ptr<PDFiumBitmap> getRenderedFillPattern(PDFiumDocument& rDoc, + PDFiumPage& rPage) override; Color getStrokeColor() override; double getStrokeWidth() override; + std::unique_ptr<PDFiumBitmap> getRenderedStrokePattern(PDFiumDocument& rDoc, + PDFiumPage& rPage) override; // Path int getPathSegmentCount() override; std::unique_ptr<PDFiumPathSegment> getPathSegment(int index) override; @@ -1362,6 +1366,36 @@ std::unique_ptr<PDFiumBitmap> PDFiumPageObjectImpl::getImageBitmap() return pPDFiumBitmap; } +std::unique_ptr<PDFiumBitmap> PDFiumPageObjectImpl::getRenderedStrokePattern(PDFiumDocument& rDoc, + PDFiumPage& rPage) +{ + auto& rDocImpl = static_cast<PDFiumDocumentImpl&>(rDoc); + auto& rPageImpl = static_cast<PDFiumPageImpl&>(rPage); + std::unique_ptr<PDFiumBitmap> pPDFiumBitmap; + FPDF_BITMAP pBitmap = FPDFPageObj_GetRenderedStrokePattern( + rDocImpl.getPointer(), rPageImpl.getPointer(), mpPageObject); + if (pBitmap) + { + pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pBitmap); + } + return pPDFiumBitmap; +} + +std::unique_ptr<PDFiumBitmap> PDFiumPageObjectImpl::getRenderedFillPattern(PDFiumDocument& rDoc, + PDFiumPage& rPage) +{ + auto& rDocImpl = static_cast<PDFiumDocumentImpl&>(rDoc); + auto& rPageImpl = static_cast<PDFiumPageImpl&>(rPage); + std::unique_ptr<PDFiumBitmap> pPDFiumBitmap; + FPDF_BITMAP pBitmap = FPDFPageObj_GetRenderedFillPattern(rDocImpl.getPointer(), + rPageImpl.getPointer(), mpPageObject); + if (pBitmap) + { + pPDFiumBitmap = std::make_unique<PDFiumBitmapImpl>(pBitmap); + } + return pPDFiumBitmap; +} + bool PDFiumPageObjectImpl::getDrawMode(PDFFillMode& rFillMode, bool& rStroke) { auto nFillMode = static_cast<int>(rFillMode);
