bump product version to 7.2.5.1
[LibreOffice.git] / svx / source / xml / xmlgrhlp.cxx
blobb911b880339abd1e60ee824e555ded5323812d58
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <com/sun/star/embed/XTransactedObject.hpp>
24 #include <com/sun/star/embed/ElementModes.hpp>
25 #include <com/sun/star/beans/XPropertySet.hpp>
26 #include <com/sun/star/io/NotConnectedException.hpp>
27 #include <com/sun/star/lang/XServiceInfo.hpp>
28 #include <com/sun/star/lang/XInitialization.hpp>
29 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
30 #include <com/sun/star/util/XCancellable.hpp>
31 #include <com/sun/star/embed/XHierarchicalStorageAccess.hpp>
32 #include <comphelper/fileformat.h>
33 #include <comphelper/graphicmimetype.hxx>
34 #include <cppuhelper/compbase.hxx>
35 #include <cppuhelper/implbase.hxx>
36 #include <cppuhelper/supportsservice.hxx>
38 #include <rtl/ref.hxx>
39 #include <unotools/ucbstreamhelper.hxx>
40 #include <unotools/streamwrap.hxx>
41 #include <unotools/tempfile.hxx>
42 #include <unotools/saveopt.hxx>
43 #include <vcl/gfxlink.hxx>
44 #include <vcl/metaact.hxx>
45 #include <tools/zcodec.hxx>
46 #include <tools/diagnose_ex.h>
48 #include <vcl/GraphicObject.hxx>
49 #include <vcl/graphicfilter.hxx>
50 #include <svx/xmlgrhlp.hxx>
51 #include <svx/xmleohlp.hxx>
53 #include <algorithm>
54 #include <memory>
55 #include <string_view>
56 #include <utility>
58 using namespace com::sun::star;
59 using namespace com::sun::star::uno;
60 using namespace com::sun::star::io;
62 namespace com::sun::star::uno { class XComponentContext; }
64 #define XML_GRAPHICSTORAGE_NAME "Pictures"
65 #define XML_GRAPHICOBJECT_URL_BASE "vnd.sun.star.GraphicObject:"
67 namespace {
69 const MetaCommentAction* ImplCheckForEPS( GDIMetaFile const & rMtf )
71 const MetaCommentAction* pComment = nullptr;
73 if ( rMtf.GetActionSize() >= 2
74 && rMtf.GetAction(0)->GetType() == MetaActionType::EPS
75 && rMtf.GetAction(1)->GetType() == MetaActionType::COMMENT
76 && ( static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ))->GetComment() == "EPSReplacementGraphic" ) )
77 pComment = static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ));
79 return pComment;
82 class GraphicInputStream : public cppu::WeakImplHelper<XInputStream>
84 private:
85 virtual sal_Int32 SAL_CALL readBytes(Sequence<sal_Int8> & aData, sal_Int32 nBytesToRead) override;
86 virtual sal_Int32 SAL_CALL readSomeBytes(Sequence<sal_Int8> & aData, sal_Int32 nMaxBytesToRead) override;
87 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
88 virtual sal_Int32 SAL_CALL available() override;
89 virtual void SAL_CALL closeInput() override;
91 private:
92 utl::TempFile maTempFile;
93 Reference<XInputStream> mxStreamWrapper;
95 public:
97 explicit GraphicInputStream(GraphicObject const & raGraphicObject, const OUString & rMimeType);
98 GraphicInputStream(const GraphicInputStream&) = delete;
100 GraphicInputStream& operator=(const GraphicInputStream&) = delete;
102 bool exists() const
104 return mxStreamWrapper.is();
109 GraphicInputStream::GraphicInputStream(GraphicObject const & aGraphicObject, const OUString & rMimeType)
111 maTempFile.EnableKillingFile();
113 if (aGraphicObject.GetType() == GraphicType::NONE)
114 return;
116 std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream(maTempFile.GetURL(), StreamMode::WRITE | StreamMode::TRUNC);
118 if (!pStream)
119 return;
121 const Graphic& aGraphic(aGraphicObject.GetGraphic());
122 const GfxLink aGfxLink(aGraphic.GetGfxLink());
123 bool bRet = false;
125 if (aGfxLink.GetDataSize() && aGfxLink.GetData())
127 if (rMimeType.isEmpty())
129 pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
130 bRet = (pStream->GetError() == ERRCODE_NONE);
132 else
134 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
135 bRet = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType(rMimeType)) == ERRCODE_NONE);
138 else
140 if (aGraphic.GetType() == GraphicType::Bitmap)
142 GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
143 OUString aFormat = rMimeType;
145 if (aGraphic.IsAnimated())
146 aFormat = "image/gif";
147 else if (aFormat.isEmpty())
148 aFormat = "image/png";
150 bRet = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType(aFormat)) == ERRCODE_NONE);
152 else if (rMimeType.isEmpty() && aGraphic.GetType() == GraphicType::GdiMetafile)
154 pStream->SetVersion(SOFFICE_FILEFORMAT_8);
155 pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
156 const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()).Write(*pStream);
157 bRet = (pStream->GetError() == ERRCODE_NONE);
159 else if (!rMimeType.isEmpty())
161 GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
162 bRet = ( rFilter.ExportGraphic( aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType( rMimeType ) ) == ERRCODE_NONE );
166 if (bRet)
168 pStream->Seek( 0 );
169 mxStreamWrapper = new ::utl::OInputStreamWrapper(std::move(pStream));
173 sal_Int32 SAL_CALL GraphicInputStream::readBytes(Sequence<sal_Int8> & rData, sal_Int32 nBytesToRead)
175 if (!mxStreamWrapper.is())
176 throw NotConnectedException();
178 return mxStreamWrapper->readBytes(rData, nBytesToRead);
181 sal_Int32 SAL_CALL GraphicInputStream::readSomeBytes(Sequence<sal_Int8>& rData, sal_Int32 nMaxBytesToRead )
183 if (!mxStreamWrapper.is())
184 throw NotConnectedException() ;
186 return mxStreamWrapper->readSomeBytes(rData, nMaxBytesToRead);
189 void SAL_CALL GraphicInputStream::skipBytes(sal_Int32 nBytesToSkip)
191 if (!mxStreamWrapper.is())
192 throw NotConnectedException();
194 mxStreamWrapper->skipBytes(nBytesToSkip);
197 sal_Int32 SAL_CALL GraphicInputStream::available()
199 if (!mxStreamWrapper.is())
200 throw NotConnectedException();
202 return mxStreamWrapper->available();
205 void SAL_CALL GraphicInputStream::closeInput()
207 if (!mxStreamWrapper.is())
208 throw NotConnectedException();
210 mxStreamWrapper->closeInput();
213 class SvXMLGraphicOutputStream:
214 public cppu::WeakImplHelper<XOutputStream>
216 private:
218 // XOutputStream
219 virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) override;
220 virtual void SAL_CALL flush() override;
221 virtual void SAL_CALL closeOutput() override;
223 private:
225 std::unique_ptr<::utl::TempFile> mpTmp;
226 std::unique_ptr<SvStream> mpOStm;
227 Reference< XOutputStream > mxStmWrapper;
228 std::unique_ptr<GraphicObject> mxGrfObj;
229 bool mbClosed;
231 public:
233 SvXMLGraphicOutputStream();
234 virtual ~SvXMLGraphicOutputStream() override;
235 SvXMLGraphicOutputStream(const SvXMLGraphicOutputStream&) = delete;
236 SvXMLGraphicOutputStream& operator=(const SvXMLGraphicOutputStream&) = delete;
238 bool Exists() const { return mxStmWrapper.is(); }
239 const GraphicObject& GetGraphicObject();
240 Graphic GetGraphic();
243 SvXMLGraphicOutputStream::SvXMLGraphicOutputStream()
244 : mpTmp(new ::utl::TempFile)
245 , mxGrfObj(new GraphicObject)
246 , mbClosed(false)
248 mpTmp->EnableKillingFile();
250 mpOStm = ::utl::UcbStreamHelper::CreateStream( mpTmp->GetURL(), StreamMode::WRITE | StreamMode::TRUNC );
252 if( mpOStm )
253 mxStmWrapper = new ::utl::OOutputStreamWrapper( *mpOStm );
256 SvXMLGraphicOutputStream::~SvXMLGraphicOutputStream()
258 mpTmp.reset();
259 mpOStm.reset();
262 void SAL_CALL SvXMLGraphicOutputStream::writeBytes( const Sequence< sal_Int8 >& rData )
264 if( !mxStmWrapper.is() )
265 throw NotConnectedException() ;
267 mxStmWrapper->writeBytes( rData );
270 void SAL_CALL SvXMLGraphicOutputStream::flush()
272 if( !mxStmWrapper.is() )
273 throw NotConnectedException() ;
275 mxStmWrapper->flush();
278 void SAL_CALL SvXMLGraphicOutputStream::closeOutput()
280 if( !mxStmWrapper.is() )
281 throw NotConnectedException() ;
283 mxStmWrapper->closeOutput();
284 mxStmWrapper.clear();
286 mbClosed = true;
289 Graphic SvXMLGraphicOutputStream::GetGraphic()
291 Graphic aGraphic;
293 if (mbClosed && mxGrfObj->GetType() == GraphicType::NONE && mpOStm)
295 mpOStm->Seek( 0 );
296 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
297 sal_uInt16 nDeterminedFormat = GRFILTER_FORMAT_DONTKNOW;
298 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *mpOStm ,nFormat,&nDeterminedFormat);
300 if (nDeterminedFormat == GRFILTER_FORMAT_DONTKNOW)
302 //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
303 //unzip them and try again
305 sal_uInt8 sFirstBytes[ 2 ];
307 sal_uInt64 nStreamLen = mpOStm->TellEnd();
308 mpOStm->Seek( 0 );
310 if ( nStreamLen == 0 )
312 SvLockBytes* pLockBytes = mpOStm->GetLockBytes();
313 if ( pLockBytes )
314 pLockBytes->SetSynchronMode();
316 nStreamLen = mpOStm->TellEnd();
317 mpOStm->Seek( 0 );
319 if( nStreamLen >= 2 )
321 //read two byte
322 mpOStm->ReadBytes(sFirstBytes, 2);
324 if( sFirstBytes[0] == 0x1f && sFirstBytes[1] == 0x8b )
326 SvMemoryStream aDest;
327 ZCodec aZCodec( 0x8000, 0x8000 );
328 aZCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
329 mpOStm->Seek( 0 );
330 aZCodec.Decompress( *mpOStm, aDest );
332 if (aZCodec.EndCompression())
334 sal_uInt64 nStreamLen_ = aDest.TellEnd();
335 if (nStreamLen_ > 0)
337 aDest.Seek(0);
338 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", aDest ,nFormat,&nDeterminedFormat );
346 if (aGraphic.GetType() != GraphicType::NONE)
348 mpOStm.reset();
349 mpTmp.reset();
351 return aGraphic;
354 const GraphicObject& SvXMLGraphicOutputStream::GetGraphicObject()
356 Graphic aGraphic(GetGraphic());
357 if (aGraphic.GetType() != GraphicType::NONE)
359 mxGrfObj.reset(new GraphicObject(aGraphic));
361 return *mxGrfObj;
366 SvXMLGraphicHelper::SvXMLGraphicHelper(SvXMLGraphicHelperMode eCreateMode)
367 : cppu::WeakComponentImplHelper<document::XGraphicObjectResolver,
368 document::XGraphicStorageHandler,
369 document::XBinaryStreamResolver>(maMutex)
371 Init( nullptr, eCreateMode );
374 SvXMLGraphicHelper::SvXMLGraphicHelper()
375 : cppu::WeakComponentImplHelper<document::XGraphicObjectResolver,
376 document::XGraphicStorageHandler,
377 document::XBinaryStreamResolver>(maMutex)
378 , meCreateMode(SvXMLGraphicHelperMode::Read)
382 SvXMLGraphicHelper::~SvXMLGraphicHelper()
386 void SAL_CALL SvXMLGraphicHelper::disposing()
390 bool SvXMLGraphicHelper::ImplGetStreamNames( const OUString& rURLStr,
391 OUString& rPictureStorageName,
392 OUString& rPictureStreamName )
394 if (rURLStr.isEmpty())
395 return false;
397 const OUString aURLStr {rURLStr.copy(rURLStr.lastIndexOf(':')+1)};
399 if( !aURLStr.isEmpty() && aURLStr.indexOf('/')<0 ) // just one token?
401 rPictureStorageName = XML_GRAPHICSTORAGE_NAME;
402 rPictureStreamName = aURLStr;
404 else
405 SvXMLEmbeddedObjectHelper::splitObjectURL(aURLStr, rPictureStorageName, rPictureStreamName);
407 SAL_WARN_IF(rPictureStreamName.isEmpty(), "svx", "SvXMLGraphicHelper::ImplInsertGraphicURL: invalid scheme: " << rURLStr);
409 return !rPictureStreamName.isEmpty();
412 uno::Reference < embed::XStorage > SvXMLGraphicHelper::ImplGetGraphicStorage( const OUString& rStorageName )
414 uno::Reference < embed::XStorage > xRetStorage;
415 if( mxRootStorage.is() )
419 maCurStorageName = rStorageName;
420 xRetStorage = mxRootStorage->openStorageElement(
421 maCurStorageName,
422 ( SvXMLGraphicHelperMode::Write == meCreateMode )
423 ? embed::ElementModes::READWRITE
424 : embed::ElementModes::READ );
426 catch ( uno::Exception& )
429 //#i43196# try again to open the storage element - this time readonly
430 if(!xRetStorage.is())
434 maCurStorageName = rStorageName;
435 xRetStorage = mxRootStorage->openStorageElement( maCurStorageName, embed::ElementModes::READ );
437 catch ( uno::Exception& )
443 return xRetStorage;
446 SvxGraphicHelperStream_Impl SvXMLGraphicHelper::ImplGetGraphicStream( const OUString& rPictureStorageName,
447 const OUString& rPictureStreamName )
449 SvxGraphicHelperStream_Impl aRet;
450 aRet.xStorage = ImplGetGraphicStorage( rPictureStorageName );
452 sal_Int32 nMode = embed::ElementModes::READ;
453 if (SvXMLGraphicHelperMode::Write == meCreateMode)
455 nMode = embed::ElementModes::READWRITE;
458 if (aRet.xStorage.is())
460 aRet.xStream = aRet.xStorage->openStreamElement( rPictureStreamName, nMode );
462 else if (rPictureStorageName.indexOf('/') != -1)
464 uno::Reference<embed::XHierarchicalStorageAccess> xHierRootStorage(mxRootStorage,
465 uno::UNO_QUERY);
466 if (xHierRootStorage.is())
470 aRet.xStream = xHierRootStorage->openStreamElementByHierarchicalName(
471 rPictureStorageName + "/" + rPictureStreamName, nMode);
472 aRet.xStorage = mxRootStorage;
474 catch (const uno::Exception&)
476 TOOLS_WARN_EXCEPTION("svx",
477 "SvXMLGraphicHelper::ImplGetGraphicStream: failed to open "
478 << rPictureStreamName);
483 if (aRet.xStream.is() && (SvXMLGraphicHelperMode::Write == meCreateMode))
485 uno::Reference<beans::XPropertySet> xProps(aRet.xStream, uno::UNO_QUERY);
486 xProps->setPropertyValue("UseCommonStoragePasswordEncryption", uno::makeAny(true));
489 return aRet;
492 OUString SvXMLGraphicHelper::ImplGetGraphicMimeType( const OUString& rFileName )
494 if( ( rFileName.getLength() >= 4 ) && ( rFileName[ rFileName.getLength() - 4 ] == '.' ) )
496 const OString aExt(OUStringToOString(rFileName.subView(rFileName.getLength() - 3),
497 RTL_TEXTENCODING_ASCII_US));
498 return comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension( aExt );
501 return OUString();
504 Graphic SvXMLGraphicHelper::ImplReadGraphic( const OUString& rPictureStorageName,
505 const OUString& rPictureStreamName )
507 Graphic aReturnGraphic;
508 SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName ) );
509 if (aStream.xStream.is())
511 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
512 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
513 Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(*pStream);
514 if (!aGraphic.IsNone())
515 aReturnGraphic = aGraphic;
516 else
517 rGraphicFilter.ImportGraphic(aReturnGraphic, "", *pStream);
520 return aReturnGraphic;
523 void SvXMLGraphicHelper::Init( const uno::Reference < embed::XStorage >& rXMLStorage,
524 SvXMLGraphicHelperMode eCreateMode,
525 const OUString& rGraphicMimeType )
527 mxRootStorage = rXMLStorage;
528 meCreateMode = eCreateMode;
529 maOutputMimeType = rGraphicMimeType;
532 rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( const uno::Reference < embed::XStorage >& rXMLStorage,
533 SvXMLGraphicHelperMode eCreateMode )
535 rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
536 pThis->Init( rXMLStorage, eCreateMode, OUString() );
538 return pThis;
541 rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode eCreateMode,
542 const OUString& rGraphicMimeType )
544 rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
546 pThis->Init( nullptr, eCreateMode, rGraphicMimeType );
548 return pThis;
551 namespace
554 void splitUserDataFromURL(OUString const & rWholeURL, OUString & rJustURL, OUString & rUserData)
556 sal_Int32 nUser = rWholeURL.indexOf('?');
557 if (nUser >= 0)
559 rJustURL = rWholeURL.copy(0, nUser);
560 nUser++;
561 rUserData = rWholeURL.copy(nUser);
563 else
565 rJustURL = rWholeURL;
569 } // end anonymous namespace
571 // XGraphicObjectResolver
572 OUString SAL_CALL SvXMLGraphicHelper::resolveGraphicObjectURL( const OUString& /*rURL*/ )
574 throw uno::RuntimeException("XGraphicObjectResolver has been removed in LibreOffice 6.1");
577 // XGraphicStorageHandler
578 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphic(OUString const & rURL)
580 osl::MutexGuard aGuard(maMutex);
582 uno::Reference<graphic::XGraphic> xGraphic;
584 OUString aURLOnly;
585 OUString aUserData;
586 splitUserDataFromURL(rURL, aURLOnly, aUserData);
588 auto aIterator = maGraphicObjects.find(aURLOnly);
589 if (aIterator != maGraphicObjects.end())
591 return aIterator->second;
594 OUString aPictureStorageName, aPictureStreamName;
596 if (ImplGetStreamNames(aURLOnly, aPictureStorageName, aPictureStreamName))
598 const GraphicObject aGraphicObject(ImplReadGraphic(aPictureStorageName, aPictureStreamName));
600 if (aGraphicObject.GetType() != GraphicType::NONE)
602 xGraphic = aGraphicObject.GetGraphic().GetXGraphic();
603 maGraphicObjects[aURLOnly] = xGraphic;
607 return xGraphic;
610 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
612 osl::MutexGuard aGuard(maMutex);
614 uno::Reference<graphic::XGraphic> xGraphic;
616 if ((SvXMLGraphicHelperMode::Read == meCreateMode) && rxOutputStream.is())
619 SvXMLGraphicOutputStream* pGraphicOutputStream = static_cast<SvXMLGraphicOutputStream*>(rxOutputStream.get());
620 if (pGraphicOutputStream)
622 xGraphic = pGraphicOutputStream->GetGraphic().GetXGraphic();
625 return xGraphic;
628 OUString SAL_CALL SvXMLGraphicHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
629 OUString & rOutSavedMimeType, OUString const & rRequestName)
631 return implSaveGraphic(rxGraphic, rOutSavedMimeType, rRequestName);
634 OUString SAL_CALL SvXMLGraphicHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
636 OUString aOutMimeType;
637 return implSaveGraphic(rxGraphic, aOutMimeType, std::u16string_view());
640 OUString SvXMLGraphicHelper::implSaveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
641 OUString & rOutSavedMimeType, std::u16string_view rRequestName)
643 Graphic aGraphic(rxGraphic);
645 auto aIterator = maExportGraphics.find(aGraphic);
646 if (aIterator != maExportGraphics.end())
648 auto const & aURLAndMimePair = aIterator->second;
649 rOutSavedMimeType = aURLAndMimePair.second;
650 return aURLAndMimePair.first;
653 GraphicObject aGraphicObject(aGraphic);
655 if (aGraphicObject.GetType() != GraphicType::NONE)
657 const GfxLink aGfxLink(aGraphic.GetGfxLink());
658 OUString aExtension;
659 bool bUseGfxLink = true;
661 if (aGfxLink.GetDataSize())
663 switch (aGfxLink.GetType())
665 case GfxLinkType::EpsBuffer: aExtension = ".eps"; break;
666 case GfxLinkType::NativeGif: aExtension = ".gif"; break;
667 // #i15508# added BMP type for better exports (checked, works)
668 case GfxLinkType::NativeBmp: aExtension = ".bmp"; break;
669 case GfxLinkType::NativeJpg: aExtension = ".jpg"; break;
670 case GfxLinkType::NativePng: aExtension = ".png"; break;
671 case GfxLinkType::NativeTif: aExtension = ".tif"; break;
672 case GfxLinkType::NativeWmf:
673 if (aGfxLink.IsEMF())
674 aExtension = ".emf";
675 else
676 aExtension = ".wmf";
677 break;
678 case GfxLinkType::NativeMet: aExtension = ".met"; break;
679 case GfxLinkType::NativePct: aExtension = ".pct"; break;
680 case GfxLinkType::NativeSvg:
681 // backward-compat kludge: since no released OOo
682 // version to date can handle svg properly, wrap it up
683 // into an svm. slight catch22 here, since strict ODF
684 // conformance _recommends_ svg - then again, most old
685 // ODF consumers are believed to be OOo
686 if (SvtSaveOptions().GetODFSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012
687 || SvtSaveOptions().GetODFSaneDefaultVersion() == SvtSaveOptions::ODFSVER_012_EXT_COMPAT)
689 bUseGfxLink = false;
690 aExtension = ".svm";
692 else
694 aExtension = ".svg";
696 break;
697 case GfxLinkType::NativePdf: aExtension = ".pdf"; break;
699 default:
700 aExtension = ".grf";
701 break;
704 else
706 if (aGraphicObject.GetType() == GraphicType::Bitmap)
708 if (aGraphicObject.IsAnimated())
709 aExtension = ".gif";
710 else
711 aExtension = ".png";
713 else if (aGraphicObject.GetType() == GraphicType::GdiMetafile)
715 // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
716 GDIMetaFile& rMetafile(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
718 if (ImplCheckForEPS(rMetafile))
719 aExtension = ".eps";
720 else
721 aExtension = ".svm";
725 OUString rPictureStreamName;
726 if (!rRequestName.empty())
728 rPictureStreamName = rRequestName + aExtension;
730 else
732 OUString sId = OStringToOUString(aGraphicObject.GetUniqueID(), RTL_TEXTENCODING_ASCII_US);
733 rPictureStreamName = sId + aExtension;
736 SvxGraphicHelperStream_Impl aStream(ImplGetGraphicStream(XML_GRAPHICSTORAGE_NAME, rPictureStreamName));
738 if (aStream.xStream.is())
740 const OUString aMimeType(ImplGetGraphicMimeType(rPictureStreamName));
741 uno::Reference<beans::XPropertySet> xProps(aStream.xStream, uno::UNO_QUERY);
743 // set stream properties (MediaType/Compression)
744 if (!aMimeType.isEmpty())
746 xProps->setPropertyValue("MediaType", uno::Any(aMimeType));
749 // picture formats that actually _do_ benefit from zip
750 // storage compression
751 // .svm pics gets compressed via ZBITMAP old-style stream
752 // option below
753 static const char* aCompressiblePics[] =
755 "image/svg+xml",
756 "image/x-emf",
757 "image/x-wmf",
758 "image/tiff",
759 "image/x-eps",
760 "image/bmp",
761 "image/x-pict"
764 bool bSuccess = false;
766 bool bCompressed = aMimeType.isEmpty();
767 if( !bCompressed )
769 for(const char* p : aCompressiblePics)
771 if( aMimeType.equalsIgnoreAsciiCaseAscii(p) )
773 bCompressed = true;
774 break;
779 xProps->setPropertyValue("Compressed", Any(bCompressed));
781 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
782 if (bUseGfxLink && aGfxLink.GetDataSize() && aGfxLink.GetData())
784 pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
785 rOutSavedMimeType = aMimeType;
786 bSuccess = (pStream->GetError() == ERRCODE_NONE);
788 else
790 if (aGraphic.GetType() == GraphicType::Bitmap)
792 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
793 OUString aFormat;
795 if (aGraphic.IsAnimated())
797 aFormat = "gif";
799 else
801 aFormat = "png";
803 rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(aFormat.toUtf8());
805 bSuccess = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForShortName(aFormat)) == ERRCODE_NONE);
807 else if (aGraphic.GetType() == GraphicType::GdiMetafile)
809 pStream->SetVersion(SOFFICE_FILEFORMAT_8);
810 pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
811 rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension("svm");
813 // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
814 GDIMetaFile& rMtf(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
815 const MetaCommentAction* pComment = ImplCheckForEPS(rMtf);
816 if (pComment)
818 sal_uInt32 nSize = pComment->GetDataSize();
819 const sal_uInt8* pData = pComment->GetData();
820 if (nSize && pData)
821 pStream->WriteBytes(pData, nSize);
823 const MetaEPSAction* pAct = static_cast<const MetaEPSAction*>(rMtf.FirstAction());
824 const GfxLink& rLink = pAct->GetLink();
826 pStream->WriteBytes(rLink.GetData(), rLink.GetDataSize());
828 else
830 rMtf.Write(*pStream);
833 bSuccess = (pStream->GetError() == ERRCODE_NONE);
837 if (!bSuccess)
838 return OUString();
840 uno::Reference<embed::XTransactedObject> xStorage(aStream.xStorage, uno::UNO_QUERY);
841 pStream.reset();
842 aStream.xStream->getOutputStream()->closeOutput();
843 if (xStorage.is())
844 xStorage->commit();
846 OUString aStoragePath = "Pictures/" + rPictureStreamName;
848 // put into cache
849 maExportGraphics[aGraphic] = std::make_pair(aStoragePath, rOutSavedMimeType);
851 return aStoragePath;
855 return OUString();
858 uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
860 Reference<XInputStream> xInputStream;
862 Graphic aGraphic(rxGraphic);
863 GraphicObject aGraphicObject(aGraphic);
865 if (SvXMLGraphicHelperMode::Write == meCreateMode)
867 OUString sMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(OUStringToOString(maOutputMimeType, RTL_TEXTENCODING_ASCII_US));
868 rtl::Reference<GraphicInputStream> pInputStream(new GraphicInputStream(aGraphicObject, sMimeType));
870 // We release the pointer from unique_ptr and assign it to the input stream return type.
871 // In case the stream doesn't exists, unique_ptr will delete the pointer when we go out of scope.
872 if (pInputStream->exists())
873 xInputStream = pInputStream.get();
876 return xInputStream;
879 // XBinaryStreamResolver
880 Reference< XInputStream > SAL_CALL SvXMLGraphicHelper::getInputStream( const OUString& /*rURL*/ )
882 Reference<XInputStream> xRet;
883 return xRet;
886 Reference< XOutputStream > SAL_CALL SvXMLGraphicHelper::createOutputStream()
888 Reference< XOutputStream > xRet;
890 if( SvXMLGraphicHelperMode::Read == meCreateMode )
892 rtl::Reference<SvXMLGraphicOutputStream> pOutputStream(new SvXMLGraphicOutputStream);
894 if( pOutputStream->Exists() )
896 xRet = pOutputStream.get();
897 maGrfStms.push_back( xRet );
901 return xRet;
904 OUString SAL_CALL SvXMLGraphicHelper::resolveOutputStream( const Reference< XOutputStream >& rxBinaryStream )
906 OUString aRet;
908 if( ( SvXMLGraphicHelperMode::Read == meCreateMode ) && rxBinaryStream.is() )
910 if( ::std::find( maGrfStms.begin(), maGrfStms.end(), rxBinaryStream ) != maGrfStms.end() )
912 SvXMLGraphicOutputStream* pOStm = static_cast< SvXMLGraphicOutputStream* >( rxBinaryStream.get() );
914 if( pOStm )
916 const GraphicObject& rGrfObj = pOStm->GetGraphicObject();
917 const OUString aId(OStringToOUString(
918 rGrfObj.GetUniqueID(), RTL_TEXTENCODING_ASCII_US));
920 if( !aId.isEmpty() )
922 aRet = XML_GRAPHICOBJECT_URL_BASE + aId;
928 return aRet;
931 // for instantiation via service manager
932 namespace {
934 namespace impl
936 typedef cppu::WeakComponentImplHelper<lang::XInitialization,
937 document::XGraphicObjectResolver,
938 document::XGraphicStorageHandler,
939 document::XBinaryStreamResolver,
940 lang::XServiceInfo>
941 SvXMLGraphicImportExportHelper_Base;
943 class MutexContainer
945 public:
946 virtual ~MutexContainer();
948 protected:
949 mutable ::osl::Mutex m_aMutex;
952 MutexContainer::~MutexContainer()
955 } // namespace impl
957 class SvXMLGraphicImportExportHelper :
958 public impl::MutexContainer,
959 public impl::SvXMLGraphicImportExportHelper_Base
961 public:
962 explicit SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode );
964 protected:
965 // is called from WeakComponentImplHelper when XComponent::dispose() was
966 // called from outside
967 virtual void SAL_CALL disposing() override;
969 // ____ XInitialization ____
970 // one argument is allowed, which is the XStorage
971 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
973 // ____ XGraphicObjectResolver ____
974 virtual OUString SAL_CALL resolveGraphicObjectURL( const OUString& aURL ) override;
976 // ____ XGraphicStorageHandler ____
977 virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
978 loadGraphic(const OUString& aURL) override;
980 virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
981 loadGraphicFromOutputStream(css::uno::Reference<css::io::XOutputStream> const & rxOutputStream) override;
983 virtual OUString SAL_CALL
984 saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
986 virtual OUString SAL_CALL
987 saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic, OUString & rOutSavedMimeType, OUString const & rRequestName) override;
989 virtual css::uno::Reference<css::io::XInputStream> SAL_CALL
990 createInputStream(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
992 // ____ XBinaryStreamResolver ____
993 virtual Reference< io::XInputStream > SAL_CALL getInputStream( const OUString& aURL ) override;
994 virtual Reference< io::XOutputStream > SAL_CALL createOutputStream() override;
995 virtual OUString SAL_CALL resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream ) override;
997 // ____ XServiceInfo ____
998 virtual OUString SAL_CALL getImplementationName() override;
999 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
1000 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
1002 private:
1003 SvXMLGraphicHelperMode m_eGraphicHelperMode;
1004 Reference< XGraphicObjectResolver > m_xGraphicObjectResolver;
1005 Reference< XGraphicStorageHandler > m_xGraphicStorageHandler;
1006 Reference< XBinaryStreamResolver > m_xBinaryStreamResolver;
1009 SvXMLGraphicImportExportHelper::SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode ) :
1010 impl::SvXMLGraphicImportExportHelper_Base( m_aMutex ),
1011 m_eGraphicHelperMode( eMode )
1014 void SAL_CALL SvXMLGraphicImportExportHelper::disposing()
1016 Reference< XComponent > xComp( m_xGraphicObjectResolver, UNO_QUERY );
1017 OSL_ASSERT( xComp.is());
1018 if( xComp.is())
1019 xComp->dispose();
1020 // m_xBinaryStreamResolver and m_xGraphicStorageHandler are a reference to the same object,
1021 // don't call dispose() again
1024 // ____ XInitialization ____
1025 void SAL_CALL SvXMLGraphicImportExportHelper::initialize(
1026 const Sequence< Any >& aArguments )
1028 Reference< embed::XStorage > xStorage;
1029 if( aArguments.hasElements() )
1030 aArguments[0] >>= xStorage;
1032 rtl::Reference<SvXMLGraphicHelper> pHelper( SvXMLGraphicHelper::Create( xStorage, m_eGraphicHelperMode ));
1033 m_xGraphicObjectResolver = pHelper;
1034 m_xGraphicStorageHandler = pHelper;
1035 m_xBinaryStreamResolver = pHelper;
1038 // ____ XGraphicObjectResolver ____
1039 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveGraphicObjectURL( const OUString& aURL )
1041 return m_xGraphicObjectResolver->resolveGraphicObjectURL( aURL );
1044 // ____ XGraphicStorageHandler ____
1045 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphic(OUString const & rURL)
1047 return m_xGraphicStorageHandler->loadGraphic(rURL);
1050 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
1052 return m_xGraphicStorageHandler->loadGraphicFromOutputStream(rxOutputStream);
1055 OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
1057 return m_xGraphicStorageHandler->saveGraphic(rxGraphic);
1060 OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
1061 OUString & rOutSavedMimeType, OUString const & rRequestName)
1063 return m_xGraphicStorageHandler->saveGraphicByName(rxGraphic, rOutSavedMimeType, rRequestName);
1066 uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicImportExportHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
1068 return m_xGraphicStorageHandler->createInputStream(rxGraphic);
1071 // ____ XBinaryStreamResolver ____
1072 Reference< io::XInputStream > SAL_CALL SvXMLGraphicImportExportHelper::getInputStream( const OUString& aURL )
1074 return m_xBinaryStreamResolver->getInputStream( aURL );
1076 Reference< io::XOutputStream > SAL_CALL SvXMLGraphicImportExportHelper::createOutputStream()
1078 return m_xBinaryStreamResolver->createOutputStream();
1080 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream )
1082 return m_xBinaryStreamResolver->resolveOutputStream( aBinaryStream );
1085 // ____ XServiceInfo ____
1086 OUString SAL_CALL SvXMLGraphicImportExportHelper::getImplementationName()
1088 if( m_eGraphicHelperMode == SvXMLGraphicHelperMode::Read )
1089 return "com.sun.star.comp.Svx.GraphicImportHelper";
1090 return "com.sun.star.comp.Svx.GraphicExportHelper";
1093 sal_Bool SAL_CALL SvXMLGraphicImportExportHelper::supportsService( const OUString& ServiceName )
1095 return cppu::supportsService(this, ServiceName);
1098 Sequence< OUString > SAL_CALL SvXMLGraphicImportExportHelper::getSupportedServiceNames()
1100 return { "com.sun.star.document.GraphicObjectResolver",
1101 "com.sun.star.document.GraphicStorageHandler",
1102 "com.sun.star.document.BinaryStreamResolver" };
1107 /** Create this with createInstanceWithArguments. service name
1108 "com.sun.star.comp.Svx.GraphicImportHelper", one argument which is the
1109 XStorage. Without arguments no helper class is created. With an empty
1110 argument the helper class is created and initialized like in the CTOR to
1111 SvXMLGraphicHelper that only gets the create mode.
1113 You should call dispose after you no longer need this component.
1115 uses eCreateMode == SvXMLGraphicHelperMode::Read, bDirect == sal_True in
1116 SvXMLGraphicHelper
1118 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1119 com_sun_star_comp_Svx_GraphicImportHelper_get_implementation(
1120 css::uno::XComponentContext *,
1121 css::uno::Sequence<css::uno::Any> const &)
1123 return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Read));
1126 /** Create this with createInstanceWithArguments. service name
1127 "com.sun.star.comp.Svx.GraphicExportHelper", one argument which is the
1128 XStorage. Without arguments no helper class is created. With an empty
1129 argument the helper class is created and initialized like in the CTOR to
1130 SvXMLGraphicHelper that only gets the create mode
1132 To write the Pictures stream, you have to call dispose at this component.
1133 Make sure you call dispose before you commit the parent storage.
1135 uses eCreateMode == SvXMLGraphicHelperMode::Write, bDirect == sal_True in
1136 SvXMLGraphicHelper
1138 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1139 com_sun_star_comp_Svx_GraphicExportHelper_get_implementation(
1140 css::uno::XComponentContext *,
1141 css::uno::Sequence<css::uno::Any> const &)
1143 return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Write));
1146 namespace svx {
1148 void DropUnusedNamedItems(css::uno::Reference<css::uno::XInterface> const& xModel)
1150 uno::Reference<lang::XMultiServiceFactory> const xModelFactory(xModel, uno::UNO_QUERY);
1151 assert(xModelFactory.is());
1154 uno::Reference<util::XCancellable> const xGradient(
1155 xModelFactory->createInstance("com.sun.star.drawing.GradientTable"),
1156 uno::UNO_QUERY );
1157 if (xGradient.is())
1159 xGradient->cancel();
1162 uno::Reference<util::XCancellable> const xHatch(
1163 xModelFactory->createInstance("com.sun.star.drawing.HatchTable"),
1164 uno::UNO_QUERY );
1165 if (xHatch.is())
1167 xHatch->cancel();
1170 uno::Reference<util::XCancellable> const xBitmap(
1171 xModelFactory->createInstance("com.sun.star.drawing.BitmapTable"),
1172 uno::UNO_QUERY );
1173 if (xBitmap.is())
1175 xBitmap->cancel();
1178 uno::Reference<util::XCancellable> const xTransGradient(
1179 xModelFactory->createInstance("com.sun.star.drawing.TransparencyGradientTable"),
1180 uno::UNO_QUERY );
1181 if (xTransGradient.is())
1183 xTransGradient->cancel();
1186 uno::Reference<util::XCancellable> const xMarker(
1187 xModelFactory->createInstance("com.sun.star.drawing.MarkerTable"),
1188 uno::UNO_QUERY );
1189 if (xMarker.is())
1191 xMarker->cancel();
1194 uno::Reference<util::XCancellable> const xDashes(
1195 xModelFactory->createInstance("com.sun.star.drawing.DashTable"),
1196 uno::UNO_QUERY );
1197 if (xDashes.is())
1199 xDashes->cancel();
1202 catch (const Exception&)
1204 TOOLS_WARN_EXCEPTION("svx", "dropUnusedNamedItems(): exception during clearing of unused named items");
1208 } // namespace svx
1210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */