summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter/source/pdf/pdfexport.cxx32
-rw-r--r--include/vcl/pdfwriter.hxx18
-rw-r--r--vcl/inc/pdf/pdfwriter_impl.hxx33
-rw-r--r--vcl/source/gdi/pdfwriter.cxx4
-rw-r--r--vcl/source/gdi/pdfwriter_impl.cxx266
5 files changed, 194 insertions, 159 deletions
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx
index 338463f184f8..7e710dabd928 100644
--- a/filter/source/pdf/pdfexport.cxx
+++ b/filter/source/pdf/pdfexport.cxx
@@ -27,6 +27,7 @@
#include <vcl/canvastools.hxx>
#include <vcl/mapmod.hxx>
#include <vcl/gdimtf.hxx>
+#include <rtl/ustring.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/string.hxx>
@@ -312,19 +313,16 @@ void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream )
if( !xStore.is() )
return;
- Sequence< beans::PropertyValue > aArgs( 2 + (m_aPreparedPassword.hasElements() ? 1 : 0) );
- aArgs.getArray()[0].Name = "FilterName";
- aArgs.getArray()[1].Name = "OutputStream";
- aArgs.getArray()[1].Value <<= xStream;
- if( m_aPreparedPassword.hasElements() )
- {
- aArgs.getArray()[2].Name = "EncryptionData";
- aArgs.getArray()[2].Value <<= m_aPreparedPassword;
- }
+ std::vector<beans::PropertyValue> aArgs {
+ comphelper::makePropertyValue("FilterName", OUString()),
+ comphelper::makePropertyValue("OutputStream", xStream),
+ };
+ if (m_aPreparedPassword.hasElements())
+ aArgs.push_back(comphelper::makePropertyValue("EncryptionData", m_aPreparedPassword));
try
{
- xStore->storeToURL( "private:stream", aArgs );
+ xStore->storeToURL("private:stream", comphelper::containerToSequence(aArgs));
}
catch( const IOException& )
{
@@ -927,9 +925,17 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >&
// export stream
// get mimetype
OUString aSrcMimetype = getMimetypeForDocument( mxContext, mxSrcDoc );
- aPDFWriter.AddStream( aSrcMimetype,
- new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword )
- );
+ OUString aExt;
+ if (aSrcMimetype == "application/vnd.oasis.opendocument.text")
+ aExt = ".odt";
+ else if (aSrcMimetype == "application/vnd.oasis.opendocument.presentation")
+ aExt = ".odp";
+ else if (aSrcMimetype == "application/vnd.oasis.opendocument.spreadsheet")
+ aExt = ".ods";
+ else if (aSrcMimetype == "application/vnd.oasis.opendocument.graphics")
+ aExt = ".odg";
+ std::unique_ptr<vcl::PDFOutputStream> pStream(new PDFExportStreamDoc(mxSrcDoc, aPreparedPermissionPassword));
+ aPDFWriter.AddAttachedFile("Original" + aExt, aSrcMimetype, std::move(pStream));
}
if ( pOut )
diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx
index f98f2c231261..80b71237138e 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -1193,24 +1193,24 @@ The following structure describes the permissions used in PDF security
*/
sal_Int32 CreateControl( const AnyWidget& rControlType );
- /** Inserts an additional stream to the PDF file
+ /** Attaches an additional file to the PDF file
- This function adds an arbitrary stream to the produced PDF file. May be called
- any time before Emit(). The stream will be written during
- Emit by calling the PDFOutputStream Object's write
- method. After the call the PDFOutputStream will be deleted.
+ This function adds an arbitrary stream that represents an attached file
+ in the PDF file.
- All additional streams and their mimetypes will be entered into an array
- in the trailer dictionary.
+ This also adds an additional stream array entry (with the mimetype) in
+ the trailer dictionary for backwards compatibility.
+
+ @param rFileName
+ the filename of the additional file as presented in the stream
@param rMimeType
the mimetype of the stream
@param pStream
the interface to the additional stream
-
*/
- void AddStream( const OUString& rMimeType, PDFOutputStream* pStream );
+ void AddAttachedFile(OUString const& rFileName, const OUString& rMimeType, std::unique_ptr<PDFOutputStream> pStream);
/// Write rString as a PDF hex string into rBuffer.
static void AppendUnicodeTextString(const OUString& rString, OStringBuffer& rBuffer);
diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx
index ea7c3d3462ab..5f6abd7bca82 100644
--- a/vcl/inc/pdf/pdfwriter_impl.hxx
+++ b/vcl/inc/pdf/pdfwriter_impl.hxx
@@ -440,8 +440,10 @@ struct PDFEmbeddedFile
{
/// ID of the file.
sal_Int32 m_nObject;
+ OUString m_aSubType;
/// Contents of the file.
BinaryDataContainer m_aDataContainer;
+ std::unique_ptr<PDFOutputStream> m_pStream;
PDFEmbeddedFile()
: m_nObject(0)
@@ -673,7 +675,15 @@ struct GraphicsState
enum class Mode { DEFAULT, NOWRITE };
-}
+struct PDFDocumentAttachedFile
+{
+ OUString maFilename;
+ OUString maMimeType;
+ sal_Int32 mnEmbeddedFileObjectId;
+ sal_Int32 mnObjectId;
+};
+
+} // end pdf namespace
class PDFWriterImpl final : public VirtualDevice, public PDFObjectContainer
{
@@ -728,6 +738,9 @@ private:
std::vector<PDFScreen> m_aScreens;
/// Contains embedded files.
std::vector<PDFEmbeddedFile> m_aEmbeddedFiles;
+
+ std::vector<PDFDocumentAttachedFile> m_aDocumentAttachedFiles;
+
/* makes correctly encoded for export to PDF URLS
*/
css::uno::Reference< css::util::XURLTransformer > m_xTrans;
@@ -810,11 +823,20 @@ private:
std::unique_ptr<ZCodec> m_pCodec;
std::unique_ptr<SvMemoryStream> m_pMemStream;
- std::vector< PDFAddStream > m_aAdditionalStreams;
std::set< PDFWriter::ErrorCode > m_aErrors;
::comphelper::Hash m_DocDigest;
+ sal_uInt64 getCurrentFilePosition()
+ {
+ sal_uInt64 nPosition{};
+ if (osl::File::E_None != m_aFile.getPos(nPosition))
+ {
+ m_aFile.close();
+ m_bOpen = false;
+ }
+ return nPosition;
+ }
/*
variables for PDF security
i12626
@@ -1317,8 +1339,11 @@ public:
// controls
sal_Int32 createControl( const PDFWriter::AnyWidget& rControl, sal_Int32 nPageNr = -1 );
- // additional streams
- void addStream( const OUString& rMimeType, PDFOutputStream* pStream );
+ // attached file
+ void addDocumentAttachedFile(OUString const& rFileName, OUString const& rMimeType, std::unique_ptr<PDFOutputStream> rStream);
+
+ sal_Int32 addEmbeddedFile(BinaryDataContainer const & rDataContainer);
+ sal_Int32 addEmbeddedFile(std::unique_ptr<PDFOutputStream> rStream, OUString const& rMimeType);
// helper: eventually begin marked content sequence and
// emit a comment in debug case
diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx
index 294d071db154..7d53f45c4699 100644
--- a/vcl/source/gdi/pdfwriter.cxx
+++ b/vcl/source/gdi/pdfwriter.cxx
@@ -443,9 +443,9 @@ PDFOutputStream::~PDFOutputStream()
{
}
-void PDFWriter::AddStream( const OUString& rMimeType, PDFOutputStream* pStream )
+void PDFWriter::AddAttachedFile(OUString const& rFileName, OUString const& rMimeType, std::unique_ptr<PDFOutputStream> pStream)
{
- xImplementation->addStream( rMimeType, pStream );
+ xImplementation->addDocumentAttachedFile(rFileName, rMimeType, std::move(pStream));
}
std::set< PDFWriter::ErrorCode > const & PDFWriter::GetErrors() const
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index e0f868d5d926..2a87f8cb4e23 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -3423,6 +3423,35 @@ bool PDFWriterImpl::appendDest( sal_Int32 nDestID, OStringBuffer& rBuffer )
return true;
}
+void PDFWriterImpl::addDocumentAttachedFile(OUString const& rFileName, OUString const& rMimeType, std::unique_ptr<PDFOutputStream> rStream)
+{
+ sal_Int32 nObjectID = addEmbeddedFile(std::move(rStream), rMimeType);
+ auto& rAttachedFile = m_aDocumentAttachedFiles.emplace_back();
+ rAttachedFile.maFilename = rFileName;
+ rAttachedFile.maMimeType = rMimeType;
+ rAttachedFile.mnEmbeddedFileObjectId = nObjectID;
+ rAttachedFile.mnObjectId = createObject();
+}
+
+sal_Int32 PDFWriterImpl::addEmbeddedFile(std::unique_ptr<PDFOutputStream> rStream, OUString const& rMimeType)
+{
+ sal_Int32 aObjectID = createObject();
+ auto& rEmbedded = m_aEmbeddedFiles.emplace_back();
+ rEmbedded.m_nObject = aObjectID;
+ rEmbedded.m_aSubType = rMimeType;
+ rEmbedded.m_pStream = std::move(rStream);
+ return aObjectID;
+}
+
+sal_Int32 PDFWriterImpl::addEmbeddedFile(BinaryDataContainer const & rDataContainer)
+{
+ sal_Int32 aObjectID = createObject();
+ m_aEmbeddedFiles.emplace_back();
+ m_aEmbeddedFiles.back().m_nObject = aObjectID;
+ m_aEmbeddedFiles.back().m_aDataContainer = rDataContainer;
+ return aObjectID;
+}
+
bool PDFWriterImpl::emitScreenAnnotations()
{
int nAnnots = m_aScreens.size();
@@ -4871,26 +4900,81 @@ bool PDFWriterImpl::emitAnnotations()
return true;
}
+class PDFStreamIf : public cppu::WeakImplHelper< css::io::XOutputStream >
+{
+ VclPtr<PDFWriterImpl> m_pWriter;
+ bool m_bWrite;
+ public:
+ explicit PDFStreamIf( PDFWriterImpl* pWriter ) : m_pWriter( pWriter ), m_bWrite( true ) {}
+
+ virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& aData ) override
+ {
+ if( m_bWrite && aData.hasElements() )
+ {
+ sal_Int32 nBytes = aData.getLength();
+ m_pWriter->writeBuffer( aData.getConstArray(), nBytes );
+ }
+ }
+ virtual void SAL_CALL flush() override {}
+ virtual void SAL_CALL closeOutput() override
+ {
+ m_bWrite = false;
+ }
+};
+
bool PDFWriterImpl::emitEmbeddedFiles()
{
- for (const auto& rEmbeddedFile : m_aEmbeddedFiles)
+ for (auto& rEmbeddedFile : m_aEmbeddedFiles)
{
if (!updateObject(rEmbeddedFile.m_nObject))
continue;
+ sal_Int32 nSizeObject = createObject();
+
OStringBuffer aLine;
aLine.append(rEmbeddedFile.m_nObject);
aLine.append(" 0 obj\n");
- aLine.append("<< /Type /EmbeddedFile /Length ");
- aLine.append(static_cast<sal_Int64>(rEmbeddedFile.m_aDataContainer.getSize()));
- aLine.append(" >>\nstream\n");
+ aLine.append("<< /Type /EmbeddedFile");
+ if (!rEmbeddedFile.m_aSubType.isEmpty())
+ {
+ aLine.append("/Subtype /");
+ appendName(rEmbeddedFile.m_aSubType, aLine);
+ }
+ aLine.append(" /Length ");
+ appendObjectReference(nSizeObject, aLine);
+ aLine.append(">>\nstream\n");
+ checkAndEnableStreamEncryption(rEmbeddedFile.m_nObject);
CHECK_RETURN(writeBuffer(aLine.getStr(), aLine.getLength()));
+ disableStreamEncryption();
aLine.setLength(0);
- CHECK_RETURN(writeBuffer(rEmbeddedFile.m_aDataContainer.getData(), rEmbeddedFile.m_aDataContainer.getSize()));
-
+ sal_Int64 nSize{};
+ if (!rEmbeddedFile.m_aDataContainer.isEmpty())
+ {
+ nSize = rEmbeddedFile.m_aDataContainer.getSize();
+ CHECK_RETURN(writeBuffer(rEmbeddedFile.m_aDataContainer.getData(), rEmbeddedFile.m_aDataContainer.getSize()));
+ }
+ else if (rEmbeddedFile.m_pStream)
+ {
+ sal_uInt64 nBegin = getCurrentFilePosition();
+ css::uno::Reference<css::io::XOutputStream> xStream(new PDFStreamIf(this));
+ rEmbeddedFile.m_pStream->write(xStream);
+ rEmbeddedFile.m_pStream.reset();
+ xStream.clear();
+ nSize = sal_Int64(getCurrentFilePosition() - nBegin);
+ }
aLine.append("\nendstream\nendobj\n\n");
CHECK_RETURN(writeBuffer(aLine.getStr(), aLine.getLength()));
+ aLine.setLength(0);
+
+ if (!updateObject(nSizeObject))
+ return false;
+ aLine.append(nSizeObject);
+ aLine.append(" 0 obj\n");
+ aLine.append(nSize);
+ aLine.append("\nendobj\n\n");
+ if (!writeBuffer(aLine.getStr(), aLine.getLength()))
+ return false;
}
return true;
}
@@ -5001,6 +5085,25 @@ bool PDFWriterImpl::emitCatalog()
CHECK_RETURN( emitAnnotations() );
CHECK_RETURN( emitEmbeddedFiles() );
+ // emit attached files
+ for (auto & rAttachedFile : m_aDocumentAttachedFiles)
+ {
+ if (!updateObject(rAttachedFile.mnObjectId))
+ return false;
+ aLine.setLength( 0 );
+
+ appendObjectID(rAttachedFile.mnObjectId, aLine);
+ aLine.append("<</Type/Filespec /F");
+ aLine.append('<');
+ PDFWriter::AppendUnicodeTextString(rAttachedFile.maFilename, aLine);
+ aLine.append('>');
+ aLine.append(" /EF <</F ");
+ appendObjectReference(rAttachedFile.mnEmbeddedFileObjectId, aLine);
+ aLine.append(">>");
+ aLine.append(">>\nendobj\n\n");
+ CHECK_RETURN( writeBuffer( aLine.getStr(), aLine.getLength() ) );
+ }
+
// emit Catalog
m_nCatalogObject = createObject();
if( ! updateObject( m_nCatalogObject ) )
@@ -5020,6 +5123,22 @@ bool PDFWriterImpl::emitCatalog()
aLine.append( " 0 R\n" );
}
+ if (!m_aDocumentAttachedFiles.empty())
+ {
+ aLine.append("/Names ");
+ aLine.append("<</EmbeddedFiles <</Names [");
+ for (auto & rAttachedFile : m_aDocumentAttachedFiles)
+ {
+ aLine.append('<');
+ PDFWriter::AppendUnicodeTextString(rAttachedFile.maFilename, aLine);
+ aLine.append('>');
+ aLine.append(' ');
+ appendObjectReference(rAttachedFile.mnObjectId, aLine);
+ }
+ aLine.append("]>>>>");
+ aLine.append("\n" );
+ }
+
if( m_aContext.PageLayout != PDFWriter::DefaultLayout )
switch( m_aContext.PageLayout )
{
@@ -5797,19 +5916,21 @@ bool PDFWriterImpl::emitTrailer()
aLine.append( aDocChecksum );
aLine.append( "\n" );
}
- if( !m_aAdditionalStreams.empty() )
+
+ if (!m_aDocumentAttachedFiles.empty())
{
aLine.append( "/AdditionalStreams [" );
- for(const PDFAddStream & rAdditionalStream : m_aAdditionalStreams)
+ for (auto const& rAttachedFile : m_aDocumentAttachedFiles)
{
aLine.append( "/" );
- appendName( rAdditionalStream.m_aMimeType, aLine );
- aLine.append( " " );
- aLine.append( rAdditionalStream.m_nStreamObject );
- aLine.append( " 0 R\n" );
+ appendName(rAttachedFile.maMimeType, aLine);
+ aLine.append(" ");
+ appendObjectReference(rAttachedFile.mnEmbeddedFileObjectId, aLine);
+ aLine.append("\n");
}
aLine.append( "]\n" );
}
+
aLine.append( ">>\n"
"startxref\n" );
aLine.append( static_cast<sal_Int64>(nXRefOffset) );
@@ -5927,104 +6048,6 @@ void PDFWriterImpl::sortWidgets()
// FIXME: implement tab order in structure tree for PDF 1.5
}
-class PDFStreamIf :
- public cppu::WeakImplHelper< css::io::XOutputStream >
-{
- VclPtr<PDFWriterImpl> m_pWriter;
- bool m_bWrite;
- public:
- explicit PDFStreamIf( PDFWriterImpl* pWriter ) : m_pWriter( pWriter ), m_bWrite( true ) {}
-
- virtual void SAL_CALL writeBytes( const css::uno::Sequence< sal_Int8 >& aData ) override;
- virtual void SAL_CALL flush() override;
- virtual void SAL_CALL closeOutput() override;
-};
-
-void SAL_CALL PDFStreamIf::writeBytes( const css::uno::Sequence< sal_Int8 >& aData )
-{
- if( m_bWrite && aData.hasElements() )
- {
- sal_Int32 nBytes = aData.getLength();
- m_pWriter->writeBuffer( aData.getConstArray(), nBytes );
- }
-}
-
-void SAL_CALL PDFStreamIf::flush()
-{
-}
-
-void SAL_CALL PDFStreamIf::closeOutput()
-{
- m_bWrite = false;
-}
-
-bool PDFWriterImpl::emitAdditionalStreams()
-{
- unsigned int nStreams = m_aAdditionalStreams.size();
- for( unsigned int i = 0; i < nStreams; i++ )
- {
- PDFAddStream& rStream = m_aAdditionalStreams[i];
- rStream.m_nStreamObject = createObject();
- sal_Int32 nSizeObject = createObject();
-
- if( ! updateObject( rStream.m_nStreamObject ) )
- return false;
-
- OStringBuffer aLine;
- aLine.append( rStream.m_nStreamObject );
- aLine.append( " 0 obj\n<</Length " );
- aLine.append( nSizeObject );
- aLine.append( " 0 R" );
- if( rStream.m_bCompress )
- aLine.append( "/Filter/FlateDecode" );
- aLine.append( ">>\nstream\n" );
- if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
- return false;
- sal_uInt64 nBeginStreamPos = 0, nEndStreamPos = 0;
- if( osl::File::E_None != m_aFile.getPos(nBeginStreamPos) )
- {
- m_aFile.close();
- m_bOpen = false;
- }
- if( rStream.m_bCompress )
- beginCompression();
-
- checkAndEnableStreamEncryption( rStream.m_nStreamObject );
- css::uno::Reference< css::io::XOutputStream > xStream( new PDFStreamIf( this ) );
- assert(rStream.m_pStream);
- if (!rStream.m_pStream)
- return false;
- rStream.m_pStream->write( xStream );
- xStream.clear();
- delete rStream.m_pStream;
- rStream.m_pStream = nullptr;
- disableStreamEncryption();
-
- if( rStream.m_bCompress )
- endCompression();
-
- if (osl::File::E_None != m_aFile.getPos(nEndStreamPos))
- {
- m_aFile.close();
- m_bOpen = false;
- return false;
- }
- if( ! writeBuffer( "\nendstream\nendobj\n\n", 19 ) )
- return false ;
- // emit stream length object
- if( ! updateObject( nSizeObject ) )
- return false;
- aLine.setLength( 0 );
- aLine.append( nSizeObject );
- aLine.append( " 0 obj\n" );
- aLine.append( static_cast<sal_Int64>(nEndStreamPos-nBeginStreamPos) );
- aLine.append( "\nendobj\n\n" );
- if( ! writeBuffer( aLine.getStr(), aLine.getLength() ) )
- return false;
- }
- return true;
-}
-
bool PDFWriterImpl::emit()
{
endPage();
@@ -6043,9 +6066,6 @@ bool PDFWriterImpl::emit()
}
#endif
- // emit additional streams
- CHECK_RETURN( emitAdditionalStreams() );
-
// emit catalog
CHECK_RETURN( emitCatalog() );
@@ -9461,10 +9481,8 @@ void PDFWriterImpl::createEmbeddedFile(const Graphic& rGraphic, ReferenceXObject
if (m_aContext.UseReferenceXObject)
{
// Store the original PDF data as an embedded file.
- m_aEmbeddedFiles.emplace_back();
- m_aEmbeddedFiles.back().m_nObject = createObject();
- m_aEmbeddedFiles.back().m_aDataContainer = rDataContainer;
- rEmit.m_nEmbeddedObject = m_aEmbeddedFiles.back().m_nObject;
+ auto nObjectID = addEmbeddedFile(rDataContainer);
+ rEmit.m_nEmbeddedObject = nObjectID;
}
else
{
@@ -11493,20 +11511,6 @@ sal_Int32 PDFWriterImpl::createControl( const PDFWriter::AnyWidget& rControl, sa
return nNewWidget;
}
-void PDFWriterImpl::addStream( const OUString& rMimeType, PDFOutputStream* pStream )
-{
- if( pStream )
- {
- m_aAdditionalStreams.emplace_back( );
- PDFAddStream& rStream = m_aAdditionalStreams.back();
- rStream.m_aMimeType = !rMimeType.isEmpty()
- ? rMimeType
- : OUString( "application/octet-stream" );
- rStream.m_pStream = pStream;
- rStream.m_bCompress = false;
- }
-}
-
void PDFWriterImpl::MARK( const char* pString )
{
beginStructureElementMCSeq();