summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--svx/source/xml/xmlgrhlp.cxx15
-rw-r--r--vcl/qa/cppunit/pdfexport/pdfexport.cxx7
-rw-r--r--vcl/source/filter/ipdf/pdfread.cxx107
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx32
4 files changed, 123 insertions, 38 deletions
diff --git a/svx/source/xml/xmlgrhlp.cxx b/svx/source/xml/xmlgrhlp.cxx
index 04b92711aa69..3946bb94c3c0 100644
--- a/svx/source/xml/xmlgrhlp.cxx
+++ b/svx/source/xml/xmlgrhlp.cxx
@@ -555,7 +555,20 @@ bool SvXMLGraphicHelper::ImplWriteGraphic( const OUString& rPictureStorageName,
std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream( aStream.xStream ));
if( bUseGfxLink && aGfxLink.GetDataSize() && aGfxLink.GetData() )
- pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
+ {
+ const uno::Sequence<sal_Int8>& rPdfData = aGraphic.getPdfData();
+ if (rPdfData.hasElements())
+ {
+ // The graphic has PDF data attached to it, use that.
+ // vcl::ImportPDF() possibly downgraded the PDF data from a
+ // higher PDF version, while aGfxLink still contains the
+ // original data provided by the user.
+ pStream->WriteBytes(rPdfData.getConstArray(), rPdfData.getLength());
+ bRet = (pStream->GetError() == 0);
+ }
+ else
+ pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
+ }
else
{
if( aGraphic.GetType() == GraphicType::Bitmap )
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 1b9eaf153d2c..76cad0f2a9af 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -383,10 +383,9 @@ void PdfExportTest::testTdf106972Pdf17()
vcl::filter::PDFObjectElement* pXObject = pXObjects->LookupObject(pXObjects->GetItems().begin()->first);
CPPUNIT_ASSERT(pXObject);
- // This failed, the "image" had resources; that typically means we tried to
- // preserve the original PDF markup here; which is not OK till our default
- // output is PDF 1.4, and this bugdoc has PDF 1.7 data.
- CPPUNIT_ASSERT(!pXObject->Lookup("Resources"));
+ // Assert that we now attempt to preserve the original PDF data, even if
+ // the original input was PDF >= 1.4.
+ CPPUNIT_ASSERT(pXObject->Lookup("Resources"));
}
void PdfExportTest::testTdf107013()
diff --git a/vcl/source/filter/ipdf/pdfread.cxx b/vcl/source/filter/ipdf/pdfread.cxx
index b2f68d02b07e..f1a7e2b52a17 100644
--- a/vcl/source/filter/ipdf/pdfread.cxx
+++ b/vcl/source/filter/ipdf/pdfread.cxx
@@ -14,6 +14,7 @@
#if HAVE_FEATURE_PDFIUM
#include <fpdfview.h>
#include <fpdf_edit.h>
+#include <fpdf_save.h>
#endif
#include <vcl/bitmapaccess.hxx>
@@ -25,6 +26,29 @@ namespace
#if HAVE_FEATURE_PDFIUM
+/// Callback class to be used with FPDF_SaveWithVersion().
+struct CompatibleWriter : public FPDF_FILEWRITE
+{
+public:
+ CompatibleWriter();
+ static int WriteBlockCallback(FPDF_FILEWRITE* pFileWrite, const void* pData, unsigned long nSize);
+
+ SvMemoryStream m_aStream;
+};
+
+CompatibleWriter::CompatibleWriter()
+{
+ FPDF_FILEWRITE::version = 1;
+ FPDF_FILEWRITE::WriteBlock = CompatibleWriter::WriteBlockCallback;
+}
+
+int CompatibleWriter::WriteBlockCallback(FPDF_FILEWRITE* pFileWrite, const void* pData, unsigned long nSize)
+{
+ auto pImpl = static_cast<CompatibleWriter*>(pFileWrite);
+ pImpl->m_aStream.WriteBytes(pData, nSize);
+ return 1;
+}
+
/// Convert to inch, then assume 96 DPI.
double pointToPixel(double fPoint)
{
@@ -88,6 +112,70 @@ bool generatePreview(SvStream& rStream, Graphic& rGraphic)
return true;
}
+
+/// Decide if PDF data is old enough to be compatible.
+bool isCompatible(SvStream& rInStream)
+{
+ // %PDF-x.y
+ sal_uInt8 aFirstBytes[8];
+ rInStream.Seek(STREAM_SEEK_TO_BEGIN);
+ sal_uLong nRead = rInStream.ReadBytes(aFirstBytes, 8);
+ if (nRead < 8)
+ return false;
+
+ if ((aFirstBytes[0] != '%' || aFirstBytes[1] != 'P' || aFirstBytes[2] != 'D' || aFirstBytes[3] != 'F' || aFirstBytes[4] != '-'))
+ return false;
+
+ sal_Int32 nMajor = OString(aFirstBytes[5]).toInt32();
+ sal_Int32 nMinor = OString(aFirstBytes[7]).toInt32();
+ if (nMajor > 1 || (nMajor == 1 && nMinor > 4))
+ return false;
+
+ return true;
+}
+
+/// 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)
+{
+ bool bCompatible = isCompatible(rInStream);
+ rInStream.Seek(STREAM_SEEK_TO_BEGIN);
+ if (bCompatible)
+ // Not converting.
+ rOutStream.WriteStream(rInStream);
+ else
+ {
+ // Downconvert to PDF-1.4.
+ FPDF_LIBRARY_CONFIG aConfig;
+ aConfig.version = 2;
+ aConfig.m_pUserFontPaths = nullptr;
+ aConfig.m_pIsolate = nullptr;
+ aConfig.m_v8EmbedderSlot = 0;
+ FPDF_InitLibraryWithConfig(&aConfig);
+
+ // Read input into a buffer.
+ SvMemoryStream aInBuffer;
+ aInBuffer.WriteStream(rInStream);
+
+ // Load the buffer using pdfium.
+ FPDF_DOCUMENT pPdfDocument = FPDF_LoadMemDocument(aInBuffer.GetData(), aInBuffer.GetSize(), /*password=*/nullptr);
+ if (!pPdfDocument)
+ return false;
+
+ CompatibleWriter aWriter;
+ // 14 means PDF-1.4.
+ if (!FPDF_SaveWithVersion(pPdfDocument, &aWriter, 0, 14))
+ return false;
+
+ FPDF_CloseDocument(pPdfDocument);
+ FPDF_DestroyLibrary();
+
+ aWriter.m_aStream.Seek(STREAM_SEEK_TO_BEGIN);
+ rOutStream.WriteStream(aWriter.m_aStream);
+ }
+
+ return rOutStream.good();
+}
#else
bool generatePreview(SvStream& rStream, Graphic& rGraphic)
{
@@ -96,6 +184,13 @@ bool generatePreview(SvStream& rStream, Graphic& rGraphic)
return true;
}
+
+bool getCompatibleStream(SvStream& rInStream, SvStream& rOutStream)
+{
+ rInStream.Seek(STREAM_SEEK_TO_BEGIN);
+ rOutStream.WriteStream(rInStream);
+ return rOutStream.good();
+}
#endif // HAVE_FEATURE_PDFIUM
}
@@ -110,10 +205,14 @@ bool ImportPDF(SvStream& rStream, Graphic& rGraphic)
return false;
// Save the original PDF stream for later use.
- rStream.Seek(STREAM_SEEK_TO_END);
- uno::Sequence<sal_Int8> aPdfData(rStream.Tell());
- rStream.Seek(STREAM_SEEK_TO_BEGIN);
- rStream.ReadBytes(aPdfData.getArray(), aPdfData.getLength());
+ SvMemoryStream aMemoryStream;
+ if (!getCompatibleStream(rStream, aMemoryStream))
+ return false;
+
+ aMemoryStream.Seek(STREAM_SEEK_TO_END);
+ uno::Sequence<sal_Int8> aPdfData(aMemoryStream.Tell());
+ aMemoryStream.Seek(STREAM_SEEK_TO_BEGIN);
+ aMemoryStream.ReadBytes(aPdfData.getArray(), aPdfData.getLength());
rGraphic.setPdfData(aPdfData);
return true;
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index f05c94e78e32..4c7542de2bfa 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -676,32 +676,6 @@ static void appendDestinationName( const OUString& rString, OStringBuffer& rBuff
}
}
-/// Decide if rGraphic has PDF data that is possible to embed in our output.
-static bool hasPdfData(const Graphic& rGraphic, bool bUseReferenceXObject)
-{
- const css::uno::Sequence<sal_Int8>& rData = rGraphic.getPdfData();
-
- if (rData.getLength() < 8)
- return false;
-
- if (rData[0] != '%' || rData[1] != 'P' || rData[2] != 'D' || rData[3] != 'F' || rData[4] != '-')
- // Unexpected header.
- return false;
-
- if (bUseReferenceXObject)
- // This is possible for all versions.
- return true;
-
- sal_Int32 nMajor = OString(rData[5]).toInt32();
- sal_Int32 nMinor = OString(rData[7]).toInt32();
-
- if (nMajor > 1 || (nMajor == 1 && nMinor > 4))
- // This is PDF-1.5 or newer, can't embed into PDF-1.4.
- return false;
-
- return true;
-}
-
void PDFWriter::AppendUnicodeTextString(const OUString& rString, OStringBuffer& rBuffer)
{
rBuffer.append( "FEFF" );
@@ -11648,7 +11622,7 @@ void PDFWriterImpl::createEmbeddedFile(const Graphic& rGraphic, ReferenceXObject
// no pdf data.
rEmit.m_nBitmapObject = nBitmapObject;
- if (!hasPdfData(rGraphic, m_aContext.UseReferenceXObject))
+ if (!rGraphic.getPdfData().hasElements())
return;
if (m_aContext.UseReferenceXObject)
@@ -11717,7 +11691,7 @@ void PDFWriterImpl::drawJPGBitmap( SvStream& rDCTData, bool bIsTrueColor, const
{
m_aJPGs.emplace( m_aJPGs.begin() );
JPGEmit& rEmit = m_aJPGs.front();
- if (!hasPdfData(rGraphic, m_aContext.UseReferenceXObject) || m_aContext.UseReferenceXObject)
+ if (!rGraphic.getPdfData().hasElements() || m_aContext.UseReferenceXObject)
rEmit.m_nObject = createObject();
rEmit.m_aID = aID;
rEmit.m_pStream.reset( pStream );
@@ -11829,7 +11803,7 @@ const PDFWriterImpl::BitmapEmit& PDFWriterImpl::createBitmapEmit( const BitmapEx
m_aBitmaps.push_front( BitmapEmit() );
m_aBitmaps.front().m_aID = aID;
m_aBitmaps.front().m_aBitmap = aBitmap;
- if (!hasPdfData(rGraphic, m_aContext.UseReferenceXObject) || m_aContext.UseReferenceXObject)
+ if (!rGraphic.getPdfData().hasElements() || m_aContext.UseReferenceXObject)
m_aBitmaps.front().m_nObject = createObject();
createEmbeddedFile(rGraphic, m_aBitmaps.front().m_aReferenceXObject, m_aBitmaps.front().m_nObject);
it = m_aBitmaps.begin();