include/vcl/pdfread.hxx | 43 ++++++++++++++++----------------- vcl/inc/pdf/pdfcompat.hxx | 9 ++++-- vcl/source/filter/graphicfilter.cxx | 3 +- vcl/source/filter/ipdf/pdfcompat.cxx | 32 ++++++++++++++++-------- vcl/source/filter/ipdf/pdfdocument.cxx | 4 ++- vcl/source/filter/ipdf/pdfread.cxx | 24 +++++------------- 6 files changed, 61 insertions(+), 54 deletions(-)
New commits: commit 72efc1d55d546dee49f732432299810f6be5529c Author: Dr. David Alan Gilbert <d...@treblig.org> AuthorDate: Sun May 25 16:17:02 2025 +0100 Commit: David Gilbert <d...@treblig.org> CommitDate: Fri Jun 13 22:05:47 2025 +0200 tdf#162826: ipdf: Route bEncrypted up Route the bEncrypted flag up from createBinaryDataContainer into ImportPDF and to readPDF. Flatten out importPdfVectorGraphicData as we go. (For some reason, clang-format is insisting on reformatting an unrelated block of text underneath my change; shrug) Change-Id: Ie964ace8a13232da27ef7b3a9c8b9d893a2abcc1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185758 Tested-by: Jenkins Reviewed-by: David Gilbert <freedesk...@treblig.org> diff --git a/include/vcl/pdfread.hxx b/include/vcl/pdfread.hxx index 8bd116b9f3b7..73bb0a8a05a4 100644 --- a/include/vcl/pdfread.hxx +++ b/include/vcl/pdfread.hxx @@ -29,28 +29,29 @@ VCL_DLLPUBLIC size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<BitmapEx>& rBitmaps, size_t nFirstPage = 0, int nPages = 1, const basegfx::B2DTuple* pSizeHint = nullptr); -/// Imports a PDF stream as a VectorGraphicData. -VCL_DLLPUBLIC bool importPdfVectorGraphicData( - SvStream& rStream, std::shared_ptr<VectorGraphicData>& rVectorGraphicData, - sal_Int32 nPageIndex = -1, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler = nullptr); - -/// Imports a PDF stream into rGraphic. VCL_DLLPUBLIC bool -ImportPDF(SvStream& rStream, Graphic& rGraphic, sal_Int32 nPageIndex = -1, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler = nullptr); - -// When inserting a PDF file as an image or pasting PDF data from the clipboard, at least on a -// Retina iMac, the resulting rendered image does not look sharp without this surprisingly large -// extra scaling factor. Exact reasons unknown. And it isn't enough to have it be just 2 (which is -// the actual Retina factor on my iMac). Possibly the fuzziness is related to what Pdfium uses to -// render text. - -// Also, look at CountDPIScaleFactor() in vcl/source/window/window.cxx. The GetDPIScaleFactor() API -// lies on macOS even more than it does on other platforms, it claims that the DPI scale factor is -// always 1. But in fact most Macs nowadays have a HiDPI ("Retina") display. But we can't just "fix" -// things by making GetDPIScaleFactor() always return 2 on macOS, even if that wouldn't be any more -// wrong, because that then causes other regressions that I have no time to look into now. +ImportPDF(SvStream& rStream, Graphic& rGraphic, sal_Int32 nPageIndex, + const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler, + bool& bEncrypted); + +inline bool ImportPDF(SvStream& rStream, Graphic& rGraphic) +{ + bool bEncrypted; + + return ImportPDF(rStream, rGraphic, -1, nullptr, bEncrypted); +} + + // When inserting a PDF file as an image or pasting PDF data from the clipboard, at least on a + // Retina iMac, the resulting rendered image does not look sharp without this surprisingly large + // extra scaling factor. Exact reasons unknown. And it isn't enough to have it be just 2 (which is + // the actual Retina factor on my iMac). Possibly the fuzziness is related to what Pdfium uses to + // render text. + + // Also, look at CountDPIScaleFactor() in vcl/source/window/window.cxx. The GetDPIScaleFactor() API + // lies on macOS even more than it does on other platforms, it claims that the DPI scale factor is + // always 1. But in fact most Macs nowadays have a HiDPI ("Retina") display. But we can't just "fix" + // things by making GetDPIScaleFactor() always return 2 on macOS, even if that wouldn't be any more + // wrong, because that then causes other regressions that I have no time to look into now. #ifdef MACOSX constexpr int PDF_INSERT_MAGIC_SCALE_FACTOR = 8; diff --git a/vcl/inc/pdf/pdfcompat.hxx b/vcl/inc/pdf/pdfcompat.hxx index 395d8ba6d8ba..4cce2a12b0df 100644 --- a/vcl/inc/pdf/pdfcompat.hxx +++ b/vcl/inc/pdf/pdfcompat.hxx @@ -42,7 +42,7 @@ bool getCompatibleStream( bool& bEncrypted); BinaryDataContainer createBinaryDataContainer( - SvStream& rStream, + SvStream& rStream, bool& bEncrypted, const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler = nullptr); } // end of vcl::filter::ipdf namespace diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx index 2f2ca2fb1be7..9e8e604354c7 100644 --- a/vcl/source/filter/graphicfilter.cxx +++ b/vcl/source/filter/graphicfilter.cxx @@ -1139,7 +1139,8 @@ ErrCode GraphicFilter::readPDF( SvStream& rStream, Graphic& rGraphic, GfxLinkType& rLinkType, sal_Int32 nPageIndex, const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler) { - if (vcl::ImportPDF(rStream, rGraphic, nPageIndex, xInteractionHandler)) + bool bEncrypted; + if (vcl::ImportPDF(rStream, rGraphic, nPageIndex, xInteractionHandler, bEncrypted)) { rLinkType = GfxLinkType::NativePdf; return ERRCODE_NONE; diff --git a/vcl/source/filter/ipdf/pdfcompat.cxx b/vcl/source/filter/ipdf/pdfcompat.cxx index ed224d844c2a..57e53fdb76d0 100644 --- a/vcl/source/filter/ipdf/pdfcompat.cxx +++ b/vcl/source/filter/ipdf/pdfcompat.cxx @@ -136,10 +136,9 @@ bool getCompatibleStream( } BinaryDataContainer createBinaryDataContainer( - SvStream& rStream, + SvStream& rStream, bool& bEncrypted, const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler) { - bool bEncrypted; // Save the original PDF stream for later use. SvMemoryStream aMemoryStream; if (!getCompatibleStream(rStream, aMemoryStream, xInteractionHandler, bEncrypted)) diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx index 574c53e959b7..74df41923217 100644 --- a/vcl/source/filter/ipdf/pdfread.cxx +++ b/vcl/source/filter/ipdf/pdfread.cxx @@ -101,30 +101,19 @@ size_t RenderPDFBitmaps(const void* pBuffer, int nSize, std::vector<BitmapEx>& r return rBitmaps.size(); } -bool importPdfVectorGraphicData( - SvStream& rStream, std::shared_ptr<VectorGraphicData>& rVectorGraphicData, sal_Int32 nPageIndex, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler) +bool ImportPDF(SvStream& rStream, Graphic& rGraphic, sal_Int32 nPageIndex, + const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler, + bool& bEncrypted) { BinaryDataContainer aDataContainer - = vcl::pdf::createBinaryDataContainer(rStream, xInteractionHandler); + = vcl::pdf::createBinaryDataContainer(rStream, bEncrypted, xInteractionHandler); if (aDataContainer.isEmpty()) { SAL_WARN("vcl.filter", "ImportPDF: empty PDF data array"); return false; } - - rVectorGraphicData = std::make_shared<VectorGraphicData>( + std::shared_ptr<VectorGraphicData> pVectorGraphicData = std::make_shared<VectorGraphicData>( aDataContainer, VectorGraphicDataType::Pdf, nPageIndex); - - return true; -} - -bool ImportPDF(SvStream& rStream, Graphic& rGraphic, sal_Int32 nPageIndex, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler) -{ - std::shared_ptr<VectorGraphicData> pVectorGraphicData; - if (!importPdfVectorGraphicData(rStream, pVectorGraphicData, nPageIndex, xInteractionHandler)) - return false; rGraphic = Graphic(pVectorGraphicData); return true; } @@ -354,9 +343,10 @@ size_t ImportPDFUnloaded(const OUString& rURL, std::vector<PDFGraphicResult>& rG { std::unique_ptr<SvStream> xStream( ::utl::UcbStreamHelper::CreateStream(rURL, StreamMode::READ | StreamMode::SHARE_DENYNONE)); + bool bEncrypted; // Save the original PDF stream for later use. - BinaryDataContainer aDataContainer = vcl::pdf::createBinaryDataContainer(*xStream); + BinaryDataContainer aDataContainer = vcl::pdf::createBinaryDataContainer(*xStream, bEncrypted); if (aDataContainer.isEmpty()) return 0; commit bb8fccd3655dca712d6dd414cc274861bd7b0462 Author: Dr. David Alan Gilbert <d...@treblig.org> AuthorDate: Sun May 25 14:30:37 2025 +0100 Commit: David Gilbert <d...@treblig.org> CommitDate: Fri Jun 13 22:05:36 2025 +0200 tdf#162826: ipdf: Convert for encrypted, correctly versioned, files convertToHighestSupported downconverts PDFs to a magical 1.6 version due to some historic bug; it's also used in a corner of the ipdf vector convert to force a conversion on a buggy input file. Use it to also force a conversion in the encrypted case even if the input was of the expected version. Pass up a flag to indicate if the file was encrypted. Change-Id: I3a8d17851349157ec5b8e7d9a2548c1a21a198a7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185757 Reviewed-by: David Gilbert <freedesk...@treblig.org> Tested-by: Jenkins diff --git a/vcl/inc/pdf/pdfcompat.hxx b/vcl/inc/pdf/pdfcompat.hxx index 35634f6982a9..395d8ba6d8ba 100644 --- a/vcl/inc/pdf/pdfcompat.hxx +++ b/vcl/inc/pdf/pdfcompat.hxx @@ -28,15 +28,18 @@ bool isCompatible(SvStream& rInStream); /// Converts to highest supported format version (currently 1.6). /// Usually used to deal with missing referenced objects in the /// source pdf stream. +/// The conversion takes place if either the stream is encrypted, or 'bForce' is true bool convertToHighestSupported( SvStream& rInStream, SvStream& rOutStream, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler = nullptr); + const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler, bool bForce, + bool& bEncrypted); /// Takes care of transparently downgrading the version of the PDF stream in /// case it's too new for our PDF export. bool getCompatibleStream( SvStream& rInStream, SvStream& rOutStream, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler); + const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler, + bool& bEncrypted); BinaryDataContainer createBinaryDataContainer( SvStream& rStream, diff --git a/vcl/source/filter/ipdf/pdfcompat.cxx b/vcl/source/filter/ipdf/pdfcompat.cxx index 50a9010a4917..ed224d844c2a 100644 --- a/vcl/source/filter/ipdf/pdfcompat.cxx +++ b/vcl/source/filter/ipdf/pdfcompat.cxx @@ -39,14 +39,16 @@ bool isCompatible(SvStream& rInStream) /// Converts to highest supported format version (1.6). /// Usually used to deal with missing referenced objects in source /// pdf stream. - +/// The conversion takes place if either the stream is encrypted, or 'bForce' is true bool convertToHighestSupported( SvStream& rInStream, SvStream& rOutStream, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler) + const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler, bool bForce, + bool& bEncrypted) { sal_uInt64 nPos = STREAM_SEEK_TO_BEGIN; sal_uInt64 nSize = STREAM_SEEK_TO_END; rInStream.Seek(nPos); + bEncrypted = false; // Convert to PDF-1.6. auto pPdfium = vcl::pdf::PDFiumLibrary::get(); if (!pPdfium) @@ -83,6 +85,7 @@ bool convertToHighestSupported( } // We don't have a filename for the GUI here + bEncrypted = true; bAgain = vcl::pdf::getPassword(xInteractionHandler, aPassword, !bAgain, u"PDF"_ustr); SAL_INFO("vcl.filter", "convertToHighestSupported pass result: " << bAgain); if (!bAgain) @@ -102,9 +105,14 @@ bool convertToHighestSupported( } while (bAgain); aSaved.Seek(STREAM_SEEK_TO_BEGIN); - SAL_INFO("vcl.filter", "convertToHighestSupported do write"); - rOutStream.WriteStream(aSaved); + if (bEncrypted || bForce) + { + SAL_INFO("vcl.filter", "convertToHighestSupported do write"); + rOutStream.WriteStream(aSaved); + } + SAL_INFO("vcl.filter", + "convertToHighestSupported exit: encrypted: " << bEncrypted << " force: " << bForce); return rOutStream.good(); } @@ -112,15 +120,17 @@ bool convertToHighestSupported( /// case it's too new for our PDF export. bool getCompatibleStream( SvStream& rInStream, SvStream& rOutStream, - const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler) + const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler, + bool& bEncrypted) { bool bCompatible = isCompatible(rInStream); + + // This will convert if either the file is encrypted, or !bCompatible + convertToHighestSupported(rInStream, rOutStream, xInteractionHandler, !bCompatible, bEncrypted); rInStream.Seek(STREAM_SEEK_TO_BEGIN); - if (bCompatible) - // Not converting. + if (bCompatible && !bEncrypted) + // Just pass the original through rOutStream.WriteStream(rInStream, STREAM_SEEK_TO_END); - else - convertToHighestSupported(rInStream, rOutStream, xInteractionHandler); return rOutStream.good(); } @@ -129,9 +139,10 @@ BinaryDataContainer createBinaryDataContainer( SvStream& rStream, const css::uno::Reference<css::task::XInteractionHandler>& xInteractionHandler) { + bool bEncrypted; // Save the original PDF stream for later use. SvMemoryStream aMemoryStream; - if (!getCompatibleStream(rStream, aMemoryStream, xInteractionHandler)) + if (!getCompatibleStream(rStream, aMemoryStream, xInteractionHandler, bEncrypted)) return {}; const sal_uInt64 nStreamLength = aMemoryStream.TellEnd(); diff --git a/vcl/source/filter/ipdf/pdfdocument.cxx b/vcl/source/filter/ipdf/pdfdocument.cxx index 0b7c01a56ac1..270248f533d9 100644 --- a/vcl/source/filter/ipdf/pdfdocument.cxx +++ b/vcl/source/filter/ipdf/pdfdocument.cxx @@ -1384,7 +1384,9 @@ bool PDFDocument::ReadWithPossibleFixup(SvStream& rStream) // Read failed, try a roundtrip through pdfium and then retry. rStream.Seek(0); SvMemoryStream aStandardizedStream; - vcl::pdf::convertToHighestSupported(rStream, aStandardizedStream); + bool bEncrypted; + vcl::pdf::convertToHighestSupported(rStream, aStandardizedStream, nullptr, true /* force */, + bEncrypted); return Read(aStandardizedStream); }