diff options
author | Balazs Varga <balazs.varga.extern@allotropia.de> | 2022-09-23 10:57:09 +0200 |
---|---|---|
committer | Thorsten Behrens <thorsten.behrens@allotropia.de> | 2023-11-19 18:16:49 +0100 |
commit | 3ff6be408d541deb2df6d7f6c6d6ad3138169935 (patch) | |
tree | 3237c01d2544ab19773ad778022d54d4d3b66d8f /sfx2/source | |
parent | 664dca306f5d72fa4ca35c74cdaef47947e1b1fe (diff) |
WASM pdf conversion through emscripten and qt5
Exporting files to pdf and downloading it from the emscripten
virtual memory file system to the local file system with qt5 and emscripten.
What is working:
1. Uploading a file from the local file system to the emscripten memory
with 'Open file dialoge' and then opening it. In the same time export it to pdf.
2. Load an uploaded document with the LibreOffice Kit command:
- lodoc = _libreofficekit_hook(0)
- _doc_postUnoCommand(lodoc, allocateUTF8(".uno:Open"), allocateUTF8(
"{ \"URL\" : { \"type\":\"string\", \"value\":\"file:///android/default-document/{UPLOADED_FILE_NAME}\" }}"), 0)
3. Export the loaded document to pdf with the ExportDirectlyToPDF UI or with the LibreOffice Kit command:
- lodoc = _libreofficekit_hook(0)
- _doc_postUnoCommand(lodoc, allocateUTF8(".uno:ExportDirectToPDF"), allocateUTF8(""), 0)
4. alternatively, you can plant a file in the virtual filesystem prior
to LibreOffice bootstrap, and export headless, via soffice cmdline args
Change-Id: I8f03b0a057155afaa5f1ca0e3e451bb362a99769
Diffstat (limited to 'sfx2/source')
-rw-r--r-- | sfx2/source/dialog/filedlghelper.cxx | 7 | ||||
-rw-r--r-- | sfx2/source/doc/guisaveas.cxx | 47 | ||||
-rw-r--r-- | sfx2/source/doc/objstor.cxx | 73 | ||||
-rw-r--r-- | sfx2/source/doc/objxtor.cxx | 2 |
4 files changed, 125 insertions, 4 deletions
diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx index 96955837c8a6..9a8b938aab23 100644 --- a/sfx2/source/dialog/filedlghelper.cxx +++ b/sfx2/source/dialog/filedlghelper.cxx @@ -1628,7 +1628,12 @@ void FileDialogHelper_Impl::getRealFilter( OUString& _rFilter ) const _rFilter = getCurrentFilterUIName(); if ( _rFilter.isEmpty() ) - _rFilter = maCurFilter; + { + if (isShowFilterExtensionEnabled()) + _rFilter = getFilterName(maCurFilter); + else + _rFilter = maCurFilter; + } if ( !_rFilter.isEmpty() && mpMatcher ) { diff --git a/sfx2/source/doc/guisaveas.cxx b/sfx2/source/doc/guisaveas.cxx index 1c013c4a382b..5b17b2a1b029 100644 --- a/sfx2/source/doc/guisaveas.cxx +++ b/sfx2/source/doc/guisaveas.cxx @@ -1641,10 +1641,53 @@ bool SfxStoringHelper::FinishGUIStoreModel(::comphelper::SequenceAsHashMap::cons if ( aDenyListIter != aModelData.GetMediaDescr().end() ) aDenyListIter->second >>= aDenyList; + bool bWasmPdfExport = false; +#ifdef EMSCRIPTEN + // Do not create file dialoge for direct pdf export, (just a workaround for WASM pdf export now) + // because that is still buggy on the Qt side + if ( nStoreMode & PDFDIRECTEXPORT_REQUESTED ) + { + // preselect a filter for the storing process + ::comphelper::SequenceAsHashMap aFilterPropsHM( aFilterProps ); + + // this is a WASM direct pdf export + const OUString aFilterUIName = aFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ); + if (aFilterUIName == "PDF - Portable Document Format") + { + OUString realfiltername; + const OUString aDocServiceName{ aModelData.GetDocServiceName() }; + if ( aDocServiceName == "com.sun.star.drawing.DrawingDocument" ) + realfiltername = "draw_pdf_Export"; + else if ( aDocServiceName == "com.sun.star.presentation.PresentationDocument" ) + realfiltername = "impress_pdf_Export"; + else if ( aDocServiceName == "com.sun.star.text.TextDocument" ) + realfiltername = "writer_pdf_Export"; + else if ( aDocServiceName == "com.sun.star.sheet.SpreadsheetDocument" ) + realfiltername = "calc_pdf_Export"; + + if (realfiltername.endsWith("pdf_Export")) + { + const OUString aRecommendedDir {aModelData.GetRecommendedDir( aSuggestedDir )}; + OUString aAdjustToType = aFilterPropsHM.getUnpackedValueOrDefault( "Type", OUString() ); + const OUString aRecommendedName {aModelData.GetRecommendedName( aSuggestedName, aAdjustToType )}; + OUString aTempURL = aRecommendedDir + aRecommendedName; + INetURLObject aURL2(aTempURL); + aModelData.GetMediaDescr()[OUString("URL")] <<= aURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + aModelData.GetMediaDescr()[sFilterNameString] <<= realfiltername; + bWasmPdfExport = true; + } + } + } +#endif // EMSCRIPTEN + for (;;) { // in case the dialog is opened a second time the folder should be the same as previously navigated to by the user, not what was handed over by initial parameters - bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, sStandardDir, aDenyList ); + if (!bWasmPdfExport) + bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, sStandardDir, aDenyList ); + else + bUseFilterOptions = true; + if ( nStoreMode == SAVEAS_REQUESTED ) { // in case of saving check filter for possible alien warning @@ -1665,7 +1708,7 @@ bool SfxStoringHelper::FinishGUIStoreModel(::comphelper::SequenceAsHashMap::cons break; } - bDialogUsed = true; + bDialogUsed = !bWasmPdfExport; aFileNameIter = aModelData.GetMediaDescr().find( OUString("URL") ); } else diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx index b39b5d14ee38..4bfb92111037 100644 --- a/sfx2/source/doc/objstor.cxx +++ b/sfx2/source/doc/objstor.cxx @@ -3006,6 +3006,39 @@ bool SfxObjectShell::PreDoSaveAs_Impl(const OUString& rFileName, const OUString& if( bOk ) { +#ifdef EMSCRIPTEN + if (aFilterName.endsWith("pdf_Export")) + { + try + { + sal_Int32 nRead; + Reference<io::XInputStream> aTempInput = pNewFile->GetInputStream(); + sal_Int32 nBufferSize = 32767; + Sequence<sal_Int8> aSequence(nBufferSize); + emscripten::val contentArray = emscripten::val::array(); + + do + { + nRead = aTempInput->readBytes(aSequence, nBufferSize); + if (nRead < nBufferSize) + { + Sequence<sal_Int8> aTempBuf(aSequence.getConstArray(), nRead); + ReadWASMFile(contentArray, nRead, aTempBuf); + } + else + { + ReadWASMFile(contentArray, nRead, aSequence); + } + } while (nRead == nBufferSize); + + WriteWASMFile(contentArray, pNewFile->GetName()); + } + catch (const Exception&) + { + } + } +#endif + if( !bCopyTo ) SetModified( false ); } @@ -3050,6 +3083,46 @@ bool SfxObjectShell::PreDoSaveAs_Impl(const OUString& rFileName, const OUString& return bOk; } +#ifdef EMSCRIPTEN +void SfxObjectShell::ReadWASMFile(emscripten::val& contentArray, sal_Int32 nRead, css::uno::Sequence<sal_Int8>& aContent) +{ + emscripten::val fileContentView = emscripten::val(emscripten::typed_memory_view( + nRead, + reinterpret_cast<const char*>(aContent.getConstArray()))); + emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(nRead); + emscripten::val fileContentCopyView = emscripten::val::global("Uint8Array").new_(fileContentCopy); + fileContentCopyView.call<void>("set", fileContentView); + contentArray.call<void>("push", fileContentCopyView); +} + + +void SfxObjectShell::WriteWASMFile(emscripten::val& contentArray, const OUString& rFileName) +{ + INetURLObject aURL(rFileName); + OUString aNewname = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset); + + emscripten::val document = emscripten::val::global("document"); + emscripten::val window = emscripten::val::global("window"); + + emscripten::val type = emscripten::val::object(); + type.set("type","application/octet-stream"); + emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type); + + emscripten::val contentUrl = window["URL"].call<emscripten::val>("createObjectURL", contentBlob); + emscripten::val contentLink = document.call<emscripten::val>("createElement", std::string("a")); + contentLink.set("href", contentUrl); + contentLink.set("download", aNewname.toUtf8().getStr()); + contentLink.set("style", "display:none"); + + emscripten::val body = document["body"]; + body.call<void>("appendChild", contentLink); + contentLink.call<void>("click"); + body.call<void>("removeChild", contentLink); + + window["URL"].call<emscripten::val>("revokeObjectURL", contentUrl); +} +#endif + bool SfxObjectShell::LoadFrom( SfxMedium& /*rMedium*/ ) { diff --git a/sfx2/source/doc/objxtor.cxx b/sfx2/source/doc/objxtor.cxx index 2fd5df242fcc..5ee43348d0b2 100644 --- a/sfx2/source/doc/objxtor.cxx +++ b/sfx2/source/doc/objxtor.cxx @@ -877,6 +877,7 @@ void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComp if ( _rxComponent == xOldCurrentComp ) // nothing to do return; + rTheCurrentComponent = _rxComponent; // note that "_rxComponent.get() == s_xCurrentComponent.get().get()" is /sufficient/, but not // /required/ for "_rxComponent == s_xCurrentComponent.get()". // In other words, it's still possible that we here do something which is not necessary, @@ -884,7 +885,6 @@ void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComp #if HAVE_FEATURE_SCRIPTING BasicManager* pAppMgr = SfxApplication::GetBasicManager(); - rTheCurrentComponent = _rxComponent; if ( !pAppMgr ) return; |