vcl: allow for overriding the default PDF rendering resolution
[LibreOffice.git] / sdext / source / pdfimport / pdfiadaptor.cxx
blob4d12474f0edf43d414df6dbbd673c40c66025405
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
21 #include "pdfiadaptor.hxx"
22 #include "filterdet.hxx"
23 #include <saxemitter.hxx>
24 #include <odfemitter.hxx>
25 #include "inc/wrapper.hxx"
26 #include <pdfiprocessor.hxx>
28 #include <osl/file.h>
29 #include <sal/log.hxx>
31 #include <cppuhelper/supportsservice.hxx>
32 #include <com/sun/star/lang/IllegalArgumentException.hpp>
33 #include <com/sun/star/lang/XMultiComponentFactory.hpp>
34 #include <com/sun/star/io/XSeekable.hpp>
35 #include <tools/diagnose_ex.h>
37 #include <memory>
39 using namespace com::sun::star;
42 namespace pdfi
45 PDFIHybridAdaptor::PDFIHybridAdaptor( const uno::Reference< uno::XComponentContext >& xContext ) :
46 PDFIHybridAdaptorBase( m_aMutex ),
47 m_xContext( xContext ),
48 m_xModel()
52 // XFilter
53 sal_Bool SAL_CALL PDFIHybridAdaptor::filter( const uno::Sequence< beans::PropertyValue >& rFilterData )
55 bool bRet = false;
56 if( m_xModel.is() )
58 uno::Reference< io::XStream > xSubStream;
59 OUString aPwd;
60 const beans::PropertyValue* pAttribs = rFilterData.getConstArray();
61 sal_Int32 nAttribs = rFilterData.getLength();
62 sal_Int32 nPwPos = -1;
63 for( sal_Int32 i = 0; i < nAttribs; i++ )
65 SAL_INFO("sdext.pdfimport", "filter: Attrib: " << pAttribs[i].Name
66 << " = " << (pAttribs[i].Value.has<OUString>()
67 ? pAttribs[i].Value.get<OUString>()
68 : OUString("<no string>"))
69 << "\n");
70 if ( pAttribs[i].Name == "EmbeddedSubstream" )
71 pAttribs[i].Value >>= xSubStream;
72 else if ( pAttribs[i].Name == "Password" )
74 nPwPos = i;
75 pAttribs[i].Value >>= aPwd;
78 bool bAddPwdProp = false;
79 if( ! xSubStream.is() )
81 uno::Reference< io::XInputStream > xInput;
82 auto pAttr = std::find_if(rFilterData.begin(), rFilterData.end(),
83 [](const beans::PropertyValue& rAttr) { return rAttr.Name == "InputStream"; });
84 if (pAttr != rFilterData.end())
85 pAttr->Value >>= xInput;
86 if( xInput.is() )
88 // TODO(P2): extracting hybrid substream twice - once during detection, second time here
89 uno::Reference< io::XSeekable > xSeek( xInput, uno::UNO_QUERY );
90 if( xSeek.is() )
91 xSeek->seek( 0 );
92 oslFileHandle aFile = nullptr;
93 sal_uInt64 nWritten = 0;
94 OUString aURL;
95 if( osl_createTempFile( nullptr, &aFile, &aURL.pData ) == osl_File_E_None )
97 SAL_INFO("sdext.pdfimport", "created temp file " << aURL);
98 const sal_Int32 nBufSize = 4096;
99 uno::Sequence<sal_Int8> aBuf(nBufSize);
100 // copy the bytes
101 sal_Int32 nBytes;
104 nBytes = xInput->readBytes( aBuf, nBufSize );
105 if( nBytes > 0 )
107 osl_writeFile( aFile, aBuf.getConstArray(), nBytes, &nWritten );
108 if( static_cast<sal_Int32>(nWritten) != nBytes )
110 xInput.clear();
111 break;
114 } while( nBytes == nBufSize );
115 osl_closeFile( aFile );
116 if( xInput.is() )
118 OUString aEmbedMimetype;
119 OUString aOrgPwd( aPwd );
120 xSubStream = getAdditionalStream( aURL, aEmbedMimetype, aPwd, m_xContext, rFilterData, true );
121 if( aOrgPwd != aPwd )
122 bAddPwdProp = true;
124 osl_removeFile( aURL.pData );
126 else
127 xSubStream.clear();
130 if( xSubStream.is() )
132 uno::Sequence< uno::Any > aArgs( 2 );
133 aArgs[0] <<= m_xModel;
134 aArgs[1] <<= xSubStream;
136 SAL_INFO("sdext.pdfimport", "try to instantiate subfilter" );
137 uno::Reference< document::XFilter > xSubFilter;
138 try {
139 xSubFilter.set(
140 m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
141 "com.sun.star.document.OwnSubFilter",
142 aArgs,
143 m_xContext ),
144 uno::UNO_QUERY );
146 catch(const uno::Exception&)
148 TOOLS_INFO_EXCEPTION("sdext.pdfimport", "subfilter");
151 SAL_INFO("sdext.pdfimport", "subfilter: " << xSubFilter.get() );
152 if( xSubFilter.is() )
154 if( bAddPwdProp )
156 uno::Sequence<beans::PropertyValue> aFilterData( rFilterData );
157 if( nPwPos == -1 )
159 nPwPos = aFilterData.getLength();
160 aFilterData.realloc( nPwPos+1 );
161 aFilterData[nPwPos].Name = "Password";
163 aFilterData[nPwPos].Value <<= aPwd;
164 bRet = xSubFilter->filter( aFilterData );
166 else
167 bRet = xSubFilter->filter( rFilterData );
170 else
171 SAL_INFO("sdext.pdfimport", "PDFIAdaptor::filter: no embedded substream set" );
173 else
174 SAL_INFO("sdext.pdfimport", "PDFIAdaptor::filter: no model set" );
176 return bRet;
179 void SAL_CALL PDFIHybridAdaptor::cancel()
183 //XImporter
184 void SAL_CALL PDFIHybridAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument )
186 SAL_INFO("sdext.pdfimport", "PDFIAdaptor::setTargetDocument" );
187 m_xModel.set( xDocument, uno::UNO_QUERY );
188 if( xDocument.is() && ! m_xModel.is() )
189 throw lang::IllegalArgumentException();
192 OUString PDFIHybridAdaptor::getImplementationName()
194 return "org.libreoffice.comp.documents.HybridPDFImport";
197 sal_Bool PDFIHybridAdaptor::supportsService(OUString const & ServiceName)
199 return cppu::supportsService(this, ServiceName);
202 css::uno::Sequence<OUString> PDFIHybridAdaptor::getSupportedServiceNames()
204 return css::uno::Sequence<OUString>{"com.sun.star.document.ImportFilter"};
207 PDFIRawAdaptor::PDFIRawAdaptor( OUString const & implementationName, const uno::Reference< uno::XComponentContext >& xContext ) :
208 PDFIAdaptorBase( m_aMutex ),
209 m_implementationName(implementationName),
210 m_xContext( xContext ),
211 m_xModel(),
212 m_pVisitorFactory()
216 void PDFIRawAdaptor::setTreeVisitorFactory(const TreeVisitorFactorySharedPtr& rVisitorFactory)
218 m_pVisitorFactory = rVisitorFactory;
221 bool PDFIRawAdaptor::parse( const uno::Reference<io::XInputStream>& xInput,
222 const uno::Reference<task::XInteractionHandler>& xIHdl,
223 const OUString& rPwd,
224 const uno::Reference<task::XStatusIndicator>& xStatus,
225 const XmlEmitterSharedPtr& rEmitter,
226 const OUString& rURL,
227 const OUString& rFilterOptions )
229 // container for metaformat
230 std::shared_ptr<PDFIProcessor> pSink(
231 new PDFIProcessor(xStatus, m_xContext));
233 bool bSuccess=false;
235 if( xInput.is() )
236 bSuccess = xpdf_ImportFromStream( xInput, pSink, xIHdl,
237 rPwd, m_xContext, rFilterOptions );
238 else
239 bSuccess = xpdf_ImportFromFile( rURL, pSink, xIHdl,
240 rPwd, m_xContext, rFilterOptions );
242 if( bSuccess )
243 pSink->emit(*rEmitter,*m_pVisitorFactory);
245 return bSuccess;
248 bool PDFIRawAdaptor::odfConvert( const OUString& rURL,
249 const uno::Reference<io::XOutputStream>& xOutput,
250 const uno::Reference<task::XStatusIndicator>& xStatus )
252 XmlEmitterSharedPtr pEmitter = createOdfEmitter(xOutput);
253 const bool bSuccess = parse(uno::Reference<io::XInputStream>(),
254 uno::Reference<task::XInteractionHandler>(),
255 OUString(),
256 xStatus,pEmitter,rURL, "");
258 // tell input stream that it is no longer needed
259 xOutput->closeOutput();
261 return bSuccess;
264 // XImportFilter
265 sal_Bool SAL_CALL PDFIRawAdaptor::importer( const uno::Sequence< beans::PropertyValue >& rSourceData,
266 const uno::Reference< xml::sax::XDocumentHandler >& rHdl,
267 const uno::Sequence< OUString >& /*rUserData*/ )
269 // get the InputStream carrying the PDF content
270 uno::Reference< io::XInputStream > xInput;
271 uno::Reference< task::XStatusIndicator > xStatus;
272 uno::Reference< task::XInteractionHandler > xInteractionHandler;
273 OUString aURL;
274 OUString aPwd;
275 OUString aFilterOptions;
276 for( const beans::PropertyValue& rAttrib : rSourceData )
278 SAL_INFO("sdext.pdfimport", "importer Attrib: " << rAttrib.Name );
279 if ( rAttrib.Name == "InputStream" )
280 rAttrib.Value >>= xInput;
281 else if ( rAttrib.Name == "URL" )
282 rAttrib.Value >>= aURL;
283 else if ( rAttrib.Name == "StatusIndicator" )
284 rAttrib.Value >>= xStatus;
285 else if ( rAttrib.Name == "InteractionHandler" )
286 rAttrib.Value >>= xInteractionHandler;
287 else if ( rAttrib.Name == "Password" )
288 rAttrib.Value >>= aPwd;
289 else if ( rAttrib.Name == "FilterOptions" )
290 rAttrib.Value >>= aFilterOptions;
292 if( !xInput.is() )
293 return false;
295 XmlEmitterSharedPtr pEmitter = createSaxEmitter(rHdl);
296 const bool bSuccess = parse(xInput, xInteractionHandler,
297 aPwd, xStatus, pEmitter, aURL, aFilterOptions);
299 // tell input stream that it is no longer needed
300 xInput->closeInput();
301 xInput.clear();
303 return bSuccess;
306 //XImporter
307 void SAL_CALL PDFIRawAdaptor::setTargetDocument( const uno::Reference< lang::XComponent >& xDocument )
309 SAL_INFO("sdext.pdfimport", "PDFIAdaptor::setTargetDocument" );
310 m_xModel.set( xDocument, uno::UNO_QUERY );
311 if( xDocument.is() && ! m_xModel.is() )
312 throw lang::IllegalArgumentException();
315 OUString PDFIRawAdaptor::getImplementationName()
317 return m_implementationName;
320 sal_Bool PDFIRawAdaptor::supportsService(OUString const & ServiceName)
322 return cppu::supportsService(this, ServiceName);
325 css::uno::Sequence<OUString> PDFIRawAdaptor::getSupportedServiceNames()
327 return css::uno::Sequence<OUString>{"com.sun.star.document.ImportFilter"};
332 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */