Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / xml / xmlgrhlp.cxx
blobb9082b6325c29670bc882effacbc6f02de72ce7f
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 <comphelper/fileformat.h>
30 #include <comphelper/graphicmimetype.hxx>
31 #include <cppuhelper/compbase.hxx>
32 #include <cppuhelper/implbase.hxx>
33 #include <cppuhelper/supportsservice.hxx>
35 #include <rtl/ref.hxx>
36 #include <unotools/ucbstreamhelper.hxx>
37 #include <unotools/streamwrap.hxx>
38 #include <unotools/tempfile.hxx>
39 #include <unotools/saveopt.hxx>
40 #include <vcl/gfxlink.hxx>
41 #include <vcl/metaact.hxx>
42 #include <tools/zcodec.hxx>
44 #include <vcl/GraphicObject.hxx>
45 #include <vcl/graphicfilter.hxx>
46 #include <svx/xmlgrhlp.hxx>
47 #include <svx/xmleohlp.hxx>
49 #include <algorithm>
50 #include <memory>
51 #include <utility>
53 using namespace com::sun::star;
54 using namespace com::sun::star::uno;
55 using namespace com::sun::star::io;
57 namespace com::sun::star::uno { class XComponentContext; }
59 #define XML_GRAPHICSTORAGE_NAME "Pictures"
60 #define XML_GRAPHICOBJECT_URL_BASE "vnd.sun.star.GraphicObject:"
62 namespace {
64 const MetaCommentAction* ImplCheckForEPS( GDIMetaFile const & rMtf )
66 const MetaCommentAction* pComment = nullptr;
68 if ( rMtf.GetActionSize() >= 2
69 && rMtf.GetAction(0)->GetType() == MetaActionType::EPS
70 && rMtf.GetAction(1)->GetType() == MetaActionType::COMMENT
71 && ( static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ))->GetComment() == "EPSReplacementGraphic" ) )
72 pComment = static_cast<const MetaCommentAction*>(rMtf.GetAction( 1 ));
74 return pComment;
77 class GraphicInputStream : public cppu::WeakImplHelper<XInputStream>
79 private:
80 virtual sal_Int32 SAL_CALL readBytes(Sequence<sal_Int8> & aData, sal_Int32 nBytesToRead) override;
81 virtual sal_Int32 SAL_CALL readSomeBytes(Sequence<sal_Int8> & aData, sal_Int32 nMaxBytesToRead) override;
82 virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
83 virtual sal_Int32 SAL_CALL available() override;
84 virtual void SAL_CALL closeInput() override;
86 private:
87 utl::TempFile maTempFile;
88 Reference<XInputStream> mxStreamWrapper;
90 public:
92 explicit GraphicInputStream(GraphicObject const & raGraphicObject, const OUString & rMimeType);
93 GraphicInputStream(const GraphicInputStream&) = delete;
95 GraphicInputStream& operator=(const GraphicInputStream&) = delete;
97 bool exists() const
99 return mxStreamWrapper.is();
104 GraphicInputStream::GraphicInputStream(GraphicObject const & aGraphicObject, const OUString & rMimeType)
106 maTempFile.EnableKillingFile();
108 if (aGraphicObject.GetType() == GraphicType::NONE)
109 return;
111 std::unique_ptr<SvStream> pStream = ::utl::UcbStreamHelper::CreateStream(maTempFile.GetURL(), StreamMode::WRITE | StreamMode::TRUNC);
113 if (!pStream)
114 return;
116 const Graphic& aGraphic(aGraphicObject.GetGraphic());
117 const GfxLink aGfxLink(aGraphic.GetGfxLink());
118 bool bRet = false;
120 if (aGfxLink.GetDataSize() && aGfxLink.GetData())
122 if (rMimeType.isEmpty())
124 pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
125 bRet = (pStream->GetError() == ERRCODE_NONE);
127 else
129 GraphicFilter &rFilter = GraphicFilter::GetGraphicFilter();
130 bRet = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType(rMimeType)) == ERRCODE_NONE);
133 else
135 if (aGraphic.GetType() == GraphicType::Bitmap)
137 GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
138 OUString aFormat = rMimeType;
140 if (aGraphic.IsAnimated())
141 aFormat = "image/gif";
142 else if (aFormat.isEmpty())
143 aFormat = "image/png";
145 bRet = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType(aFormat)) == ERRCODE_NONE);
147 else if (rMimeType.isEmpty() && aGraphic.GetType() == GraphicType::GdiMetafile)
149 pStream->SetVersion(SOFFICE_FILEFORMAT_8);
150 pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
151 const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()).Write(*pStream);
152 bRet = (pStream->GetError() == ERRCODE_NONE);
154 else if (!rMimeType.isEmpty())
156 GraphicFilter & rFilter = GraphicFilter::GetGraphicFilter();
157 bRet = ( rFilter.ExportGraphic( aGraphic, "", *pStream, rFilter.GetExportFormatNumberForMediaType( rMimeType ) ) == ERRCODE_NONE );
161 if (bRet)
163 pStream->Seek( 0 );
164 mxStreamWrapper = new ::utl::OInputStreamWrapper(std::move(pStream));
168 sal_Int32 SAL_CALL GraphicInputStream::readBytes(Sequence<sal_Int8> & rData, sal_Int32 nBytesToRead)
170 if (!mxStreamWrapper.is())
171 throw NotConnectedException();
173 return mxStreamWrapper->readBytes(rData, nBytesToRead);
176 sal_Int32 SAL_CALL GraphicInputStream::readSomeBytes(Sequence<sal_Int8>& rData, sal_Int32 nMaxBytesToRead )
178 if (!mxStreamWrapper.is())
179 throw NotConnectedException() ;
181 return mxStreamWrapper->readSomeBytes(rData, nMaxBytesToRead);
184 void SAL_CALL GraphicInputStream::skipBytes(sal_Int32 nBytesToSkip)
186 if (!mxStreamWrapper.is())
187 throw NotConnectedException();
189 mxStreamWrapper->skipBytes(nBytesToSkip);
192 sal_Int32 SAL_CALL GraphicInputStream::available()
194 if (!mxStreamWrapper.is())
195 throw NotConnectedException();
197 return mxStreamWrapper->available();
200 void SAL_CALL GraphicInputStream::closeInput()
202 if (!mxStreamWrapper.is())
203 throw NotConnectedException();
205 mxStreamWrapper->closeInput();
208 class SvXMLGraphicOutputStream:
209 public cppu::WeakImplHelper<XOutputStream>
211 private:
213 // XOutputStream
214 virtual void SAL_CALL writeBytes( const Sequence< sal_Int8 >& rData ) override;
215 virtual void SAL_CALL flush() override;
216 virtual void SAL_CALL closeOutput() override;
218 private:
220 std::unique_ptr<::utl::TempFile> mpTmp;
221 std::unique_ptr<SvStream> mpOStm;
222 Reference< XOutputStream > mxStmWrapper;
223 std::unique_ptr<GraphicObject> mxGrfObj;
224 bool mbClosed;
226 public:
228 SvXMLGraphicOutputStream();
229 virtual ~SvXMLGraphicOutputStream() override;
230 SvXMLGraphicOutputStream(const SvXMLGraphicOutputStream&) = delete;
231 SvXMLGraphicOutputStream& operator=(const SvXMLGraphicOutputStream&) = delete;
233 bool Exists() const { return mxStmWrapper.is(); }
234 const GraphicObject& GetGraphicObject();
235 Graphic GetGraphic();
238 SvXMLGraphicOutputStream::SvXMLGraphicOutputStream()
239 : mpTmp(new ::utl::TempFile)
240 , mxGrfObj(new GraphicObject)
241 , mbClosed(false)
243 mpTmp->EnableKillingFile();
245 mpOStm = ::utl::UcbStreamHelper::CreateStream( mpTmp->GetURL(), StreamMode::WRITE | StreamMode::TRUNC );
247 if( mpOStm )
248 mxStmWrapper = new ::utl::OOutputStreamWrapper( *mpOStm );
251 SvXMLGraphicOutputStream::~SvXMLGraphicOutputStream()
253 mpTmp.reset();
254 mpOStm.reset();
257 void SAL_CALL SvXMLGraphicOutputStream::writeBytes( const Sequence< sal_Int8 >& rData )
259 if( !mxStmWrapper.is() )
260 throw NotConnectedException() ;
262 mxStmWrapper->writeBytes( rData );
265 void SAL_CALL SvXMLGraphicOutputStream::flush()
267 if( !mxStmWrapper.is() )
268 throw NotConnectedException() ;
270 mxStmWrapper->flush();
273 void SAL_CALL SvXMLGraphicOutputStream::closeOutput()
275 if( !mxStmWrapper.is() )
276 throw NotConnectedException() ;
278 mxStmWrapper->closeOutput();
279 mxStmWrapper.clear();
281 mbClosed = true;
284 Graphic SvXMLGraphicOutputStream::GetGraphic()
286 Graphic aGraphic;
288 if (mbClosed && mxGrfObj->GetType() == GraphicType::NONE && mpOStm)
290 mpOStm->Seek( 0 );
291 sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW;
292 sal_uInt16 nDeterminedFormat = GRFILTER_FORMAT_DONTKNOW;
293 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *mpOStm ,nFormat,&nDeterminedFormat);
295 if (nDeterminedFormat == GRFILTER_FORMAT_DONTKNOW)
297 //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
298 //unzip them and try again
300 sal_uInt8 sFirstBytes[ 2 ];
302 sal_uInt64 nStreamLen = mpOStm->TellEnd();
303 mpOStm->Seek( 0 );
305 if ( nStreamLen == 0 )
307 SvLockBytes* pLockBytes = mpOStm->GetLockBytes();
308 if ( pLockBytes )
309 pLockBytes->SetSynchronMode();
311 nStreamLen = mpOStm->TellEnd();
312 mpOStm->Seek( 0 );
314 if( nStreamLen >= 2 )
316 //read two byte
317 mpOStm->ReadBytes(sFirstBytes, 2);
319 if( sFirstBytes[0] == 0x1f && sFirstBytes[1] == 0x8b )
321 std::unique_ptr<SvMemoryStream> pDest(new SvMemoryStream);
322 ZCodec aZCodec( 0x8000, 0x8000 );
323 aZCodec.BeginCompression(ZCODEC_DEFAULT_COMPRESSION, /*gzLib*/true);
324 mpOStm->Seek( 0 );
325 aZCodec.Decompress( *mpOStm, *pDest );
327 if (aZCodec.EndCompression())
329 sal_uInt64 nStreamLen_ = pDest->TellEnd();
330 if (nStreamLen_ > 0)
332 pDest->Seek(0);
333 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic, "", *pDest ,nFormat,&nDeterminedFormat );
341 if (aGraphic.GetType() != GraphicType::NONE)
343 mpOStm.reset();
344 mpTmp.reset();
346 return aGraphic;
349 const GraphicObject& SvXMLGraphicOutputStream::GetGraphicObject()
351 Graphic aGraphic(GetGraphic());
352 if (aGraphic.GetType() != GraphicType::NONE)
354 mxGrfObj.reset(new GraphicObject(aGraphic));
356 return *mxGrfObj;
361 SvXMLGraphicHelper::SvXMLGraphicHelper(SvXMLGraphicHelperMode eCreateMode)
362 : cppu::WeakComponentImplHelper<document::XGraphicObjectResolver,
363 document::XGraphicStorageHandler,
364 document::XBinaryStreamResolver>(maMutex)
366 Init( nullptr, eCreateMode );
369 SvXMLGraphicHelper::SvXMLGraphicHelper()
370 : cppu::WeakComponentImplHelper<document::XGraphicObjectResolver,
371 document::XGraphicStorageHandler,
372 document::XBinaryStreamResolver>(maMutex)
373 , meCreateMode(SvXMLGraphicHelperMode::Read)
377 SvXMLGraphicHelper::~SvXMLGraphicHelper()
381 void SAL_CALL SvXMLGraphicHelper::disposing()
385 bool SvXMLGraphicHelper::ImplGetStreamNames( const OUString& rURLStr,
386 OUString& rPictureStorageName,
387 OUString& rPictureStreamName )
389 if (rURLStr.isEmpty())
390 return false;
392 const OUString aURLStr {rURLStr.copy(rURLStr.lastIndexOf(':')+1)};
394 if( !aURLStr.isEmpty() && aURLStr.indexOf('/')<0 ) // just one token?
396 rPictureStorageName = XML_GRAPHICSTORAGE_NAME;
397 rPictureStreamName = aURLStr;
399 else
400 SvXMLEmbeddedObjectHelper::splitObjectURL(aURLStr, rPictureStorageName, rPictureStreamName);
402 SAL_WARN_IF(rPictureStreamName.isEmpty(), "svx", "SvXMLGraphicHelper::ImplInsertGraphicURL: invalid scheme: " << rURLStr);
404 return !rPictureStreamName.isEmpty();
407 uno::Reference < embed::XStorage > SvXMLGraphicHelper::ImplGetGraphicStorage( const OUString& rStorageName )
409 uno::Reference < embed::XStorage > xRetStorage;
410 if( mxRootStorage.is() )
414 maCurStorageName = rStorageName;
415 xRetStorage = mxRootStorage->openStorageElement(
416 maCurStorageName,
417 ( SvXMLGraphicHelperMode::Write == meCreateMode )
418 ? embed::ElementModes::READWRITE
419 : embed::ElementModes::READ );
421 catch ( uno::Exception& )
424 //#i43196# try again to open the storage element - this time readonly
425 if(!xRetStorage.is())
429 maCurStorageName = rStorageName;
430 xRetStorage = mxRootStorage->openStorageElement( maCurStorageName, embed::ElementModes::READ );
432 catch ( uno::Exception& )
438 return xRetStorage;
441 SvxGraphicHelperStream_Impl SvXMLGraphicHelper::ImplGetGraphicStream( const OUString& rPictureStorageName,
442 const OUString& rPictureStreamName )
444 SvxGraphicHelperStream_Impl aRet;
445 aRet.xStorage = ImplGetGraphicStorage( rPictureStorageName );
447 if( aRet.xStorage.is() )
449 sal_Int32 nMode = embed::ElementModes::READ;
450 if ( SvXMLGraphicHelperMode::Write == meCreateMode )
452 nMode = embed::ElementModes::READWRITE;
455 aRet.xStream = aRet.xStorage->openStreamElement( rPictureStreamName, nMode );
456 if( aRet.xStream.is() && ( SvXMLGraphicHelperMode::Write == meCreateMode ) )
458 uno::Reference < beans::XPropertySet > xProps( aRet.xStream, uno::UNO_QUERY );
459 xProps->setPropertyValue( "UseCommonStoragePasswordEncryption", uno::makeAny( true) );
463 return aRet;
466 OUString SvXMLGraphicHelper::ImplGetGraphicMimeType( const OUString& rFileName )
468 if( ( rFileName.getLength() >= 4 ) && ( rFileName[ rFileName.getLength() - 4 ] == '.' ) )
470 const OString aExt(OUStringToOString(rFileName.copy(rFileName.getLength() - 3),
471 RTL_TEXTENCODING_ASCII_US));
472 return comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension( aExt );
475 return OUString();
478 Graphic SvXMLGraphicHelper::ImplReadGraphic( const OUString& rPictureStorageName,
479 const OUString& rPictureStreamName )
481 Graphic aReturnGraphic;
482 SvxGraphicHelperStream_Impl aStream( ImplGetGraphicStream( rPictureStorageName, rPictureStreamName ) );
483 if (aStream.xStream.is())
485 GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
486 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
487 Graphic aGraphic = rGraphicFilter.ImportUnloadedGraphic(*pStream);
488 if (!aGraphic.IsNone())
489 aReturnGraphic = aGraphic;
490 else
491 rGraphicFilter.ImportGraphic(aReturnGraphic, "", *pStream);
494 return aReturnGraphic;
497 void SvXMLGraphicHelper::Init( const uno::Reference < embed::XStorage >& rXMLStorage,
498 SvXMLGraphicHelperMode eCreateMode,
499 const OUString& rGraphicMimeType )
501 mxRootStorage = rXMLStorage;
502 meCreateMode = eCreateMode;
503 maOutputMimeType = rGraphicMimeType;
506 rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( const uno::Reference < embed::XStorage >& rXMLStorage,
507 SvXMLGraphicHelperMode eCreateMode )
509 rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
510 pThis->Init( rXMLStorage, eCreateMode, OUString() );
512 return pThis;
515 rtl::Reference<SvXMLGraphicHelper> SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode eCreateMode,
516 const OUString& rGraphicMimeType )
518 rtl::Reference<SvXMLGraphicHelper> pThis = new SvXMLGraphicHelper;
520 pThis->Init( nullptr, eCreateMode, rGraphicMimeType );
522 return pThis;
525 namespace
528 void splitUserDataFromURL(OUString const & rWholeURL, OUString & rJustURL, OUString & rUserData)
530 sal_Int32 nUser = rWholeURL.indexOf('?');
531 if (nUser >= 0)
533 rJustURL = rWholeURL.copy(0, nUser);
534 nUser++;
535 rUserData = rWholeURL.copy(nUser);
537 else
539 rJustURL = rWholeURL;
543 } // end anonymous namespace
545 // XGraphicObjectResolver
546 OUString SAL_CALL SvXMLGraphicHelper::resolveGraphicObjectURL( const OUString& /*rURL*/ )
548 throw uno::RuntimeException("XGraphicObjectResolver has been removed in LibreOffice 6.1");
551 // XGraphicStorageHandler
552 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphic(OUString const & rURL)
554 osl::MutexGuard aGuard(maMutex);
556 uno::Reference<graphic::XGraphic> xGraphic;
558 OUString aURLOnly;
559 OUString aUserData;
560 splitUserDataFromURL(rURL, aURLOnly, aUserData);
562 auto aIterator = maGraphicObjects.find(aURLOnly);
563 if (aIterator != maGraphicObjects.end())
565 return aIterator->second;
568 OUString aPictureStorageName, aPictureStreamName;
570 if (ImplGetStreamNames(aURLOnly, aPictureStorageName, aPictureStreamName))
572 const GraphicObject aGraphicObject(ImplReadGraphic(aPictureStorageName, aPictureStreamName));
574 if (aGraphicObject.GetType() != GraphicType::NONE)
576 xGraphic = aGraphicObject.GetGraphic().GetXGraphic();
577 maGraphicObjects[aURLOnly] = xGraphic;
581 return xGraphic;
584 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
586 osl::MutexGuard aGuard(maMutex);
588 uno::Reference<graphic::XGraphic> xGraphic;
590 if ((SvXMLGraphicHelperMode::Read == meCreateMode) && rxOutputStream.is())
593 SvXMLGraphicOutputStream* pGraphicOutputStream = static_cast<SvXMLGraphicOutputStream*>(rxOutputStream.get());
594 if (pGraphicOutputStream)
596 xGraphic = pGraphicOutputStream->GetGraphic().GetXGraphic();
599 return xGraphic;
602 OUString SAL_CALL SvXMLGraphicHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
603 OUString & rOutSavedMimeType, OUString const & rRequestName)
605 return implSaveGraphic(rxGraphic, rOutSavedMimeType, rRequestName);
608 OUString SAL_CALL SvXMLGraphicHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
610 OUString aOutMimeType;
611 return implSaveGraphic(rxGraphic, aOutMimeType, OUString());
614 OUString SvXMLGraphicHelper::implSaveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
615 OUString & rOutSavedMimeType, OUString const & rRequestName)
617 Graphic aGraphic(rxGraphic);
619 auto aIterator = maExportGraphics.find(aGraphic);
620 if (aIterator != maExportGraphics.end())
622 auto const & aURLAndMimePair = aIterator->second;
623 rOutSavedMimeType = aURLAndMimePair.second;
624 return aURLAndMimePair.first;
627 GraphicObject aGraphicObject(aGraphic);
629 if (aGraphicObject.GetType() != GraphicType::NONE)
631 const GfxLink aGfxLink(aGraphic.GetGfxLink());
632 OUString aExtension;
633 bool bUseGfxLink = true;
635 if (aGfxLink.GetDataSize())
637 switch (aGfxLink.GetType())
639 case GfxLinkType::EpsBuffer: aExtension = ".eps"; break;
640 case GfxLinkType::NativeGif: aExtension = ".gif"; break;
641 // #i15508# added BMP type for better exports (checked, works)
642 case GfxLinkType::NativeBmp: aExtension = ".bmp"; break;
643 case GfxLinkType::NativeJpg: aExtension = ".jpg"; break;
644 case GfxLinkType::NativePng: aExtension = ".png"; break;
645 case GfxLinkType::NativeTif: aExtension = ".tif"; break;
646 case GfxLinkType::NativeWmf:
647 if (aGfxLink.IsEMF())
648 aExtension = ".emf";
649 else
650 aExtension = ".wmf";
651 break;
652 case GfxLinkType::NativeMet: aExtension = ".met"; break;
653 case GfxLinkType::NativePct: aExtension = ".pct"; break;
654 case GfxLinkType::NativeSvg:
655 // backward-compat kludge: since no released OOo
656 // version to date can handle svg properly, wrap it up
657 // into an svm. slight catch22 here, since strict ODF
658 // conformance _recommends_ svg - then again, most old
659 // ODF consumers are believed to be OOo
660 if (SvtSaveOptions().GetODFSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012
661 || SvtSaveOptions().GetODFSaneDefaultVersion() == SvtSaveOptions::ODFSVER_012_EXT_COMPAT)
663 bUseGfxLink = false;
664 aExtension = ".svm";
666 else
668 aExtension = ".svg";
670 break;
671 case GfxLinkType::NativePdf: aExtension = ".pdf"; break;
673 default:
674 aExtension = ".grf";
675 break;
678 else
680 if (aGraphicObject.GetType() == GraphicType::Bitmap)
682 if (aGraphicObject.IsAnimated())
683 aExtension = ".gif";
684 else
685 aExtension = ".png";
687 else if (aGraphicObject.GetType() == GraphicType::GdiMetafile)
689 // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
690 GDIMetaFile& rMetafile(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
692 if (ImplCheckForEPS(rMetafile))
693 aExtension = ".eps";
694 else
695 aExtension = ".svm";
699 OUString rPictureStreamName;
700 if (!rRequestName.isEmpty())
702 rPictureStreamName = rRequestName + aExtension;
704 else
706 OUString sId = OStringToOUString(aGraphicObject.GetUniqueID(), RTL_TEXTENCODING_ASCII_US);
707 rPictureStreamName = sId + aExtension;
710 SvxGraphicHelperStream_Impl aStream(ImplGetGraphicStream(XML_GRAPHICSTORAGE_NAME, rPictureStreamName));
712 if (aStream.xStream.is())
714 const OUString aMimeType(ImplGetGraphicMimeType(rPictureStreamName));
715 uno::Reference<beans::XPropertySet> xProps(aStream.xStream, uno::UNO_QUERY);
717 // set stream properties (MediaType/Compression)
718 if (!aMimeType.isEmpty())
720 xProps->setPropertyValue("MediaType", uno::Any(aMimeType));
723 // picture formats that actually _do_ benefit from zip
724 // storage compression
725 // .svm pics gets compressed via ZBITMAP old-style stream
726 // option below
727 static const char* aCompressiblePics[] =
729 "image/svg+xml",
730 "image/x-emf",
731 "image/x-wmf",
732 "image/tiff",
733 "image/x-eps",
734 "image/bmp",
735 "image/x-pict"
738 bool bSuccess = false;
740 bool bCompressed = aMimeType.isEmpty();
741 if( !bCompressed )
743 for(const char* p : aCompressiblePics)
745 if( aMimeType.equalsIgnoreAsciiCaseAscii(p) )
747 bCompressed = true;
748 break;
753 xProps->setPropertyValue("Compressed", Any(bCompressed));
755 std::unique_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(aStream.xStream));
756 if (bUseGfxLink && aGfxLink.GetDataSize() && aGfxLink.GetData())
758 pStream->WriteBytes(aGfxLink.GetData(), aGfxLink.GetDataSize());
759 rOutSavedMimeType = aMimeType;
760 bSuccess = (pStream->GetError() == ERRCODE_NONE);
762 else
764 if (aGraphic.GetType() == GraphicType::Bitmap)
766 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
767 OUString aFormat;
769 if (aGraphic.IsAnimated())
771 aFormat = "gif";
773 else
775 aFormat = "png";
777 rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(aFormat.toUtf8());
779 bSuccess = (rFilter.ExportGraphic(aGraphic, "", *pStream, rFilter.GetExportFormatNumberForShortName(aFormat)) == ERRCODE_NONE);
781 else if (aGraphic.GetType() == GraphicType::GdiMetafile)
783 pStream->SetVersion(SOFFICE_FILEFORMAT_8);
784 pStream->SetCompressMode(SvStreamCompressFlags::ZBITMAP);
785 rOutSavedMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension("svm");
787 // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
788 GDIMetaFile& rMtf(const_cast<GDIMetaFile&>(aGraphic.GetGDIMetaFile()));
789 const MetaCommentAction* pComment = ImplCheckForEPS(rMtf);
790 if (pComment)
792 sal_uInt32 nSize = pComment->GetDataSize();
793 const sal_uInt8* pData = pComment->GetData();
794 if (nSize && pData)
795 pStream->WriteBytes(pData, nSize);
797 const MetaEPSAction* pAct = static_cast<const MetaEPSAction*>(rMtf.FirstAction());
798 const GfxLink& rLink = pAct->GetLink();
800 pStream->WriteBytes(rLink.GetData(), rLink.GetDataSize());
802 else
804 rMtf.Write(*pStream);
807 bSuccess = (pStream->GetError() == ERRCODE_NONE);
811 if (!bSuccess)
812 return OUString();
814 uno::Reference<embed::XTransactedObject> xStorage(aStream.xStorage, uno::UNO_QUERY);
815 pStream.reset();
816 aStream.xStream->getOutputStream()->closeOutput();
817 if (xStorage.is())
818 xStorage->commit();
820 OUString aStoragePath = "Pictures/" + rPictureStreamName;
822 // put into cache
823 maExportGraphics[aGraphic] = std::make_pair(aStoragePath, rOutSavedMimeType);
825 return aStoragePath;
829 return OUString();
832 uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
834 Reference<XInputStream> xInputStream;
836 Graphic aGraphic(rxGraphic);
837 GraphicObject aGraphicObject(aGraphic);
839 if (SvXMLGraphicHelperMode::Write == meCreateMode)
841 OUString sMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(OUStringToOString(maOutputMimeType, RTL_TEXTENCODING_ASCII_US));
842 std::unique_ptr<GraphicInputStream> pInputStream(new GraphicInputStream(aGraphicObject, sMimeType));
844 // We release the pointer from unique_ptr and assign it to the input stream return type.
845 // In case the stream doesn't exists, unique_ptr will delete the pointer when we go out of scope.
846 if (pInputStream->exists())
847 xInputStream = pInputStream.release();
850 return xInputStream;
853 // XBinaryStreamResolver
854 Reference< XInputStream > SAL_CALL SvXMLGraphicHelper::getInputStream( const OUString& /*rURL*/ )
856 Reference<XInputStream> xRet;
857 return xRet;
860 Reference< XOutputStream > SAL_CALL SvXMLGraphicHelper::createOutputStream()
862 Reference< XOutputStream > xRet;
864 if( SvXMLGraphicHelperMode::Read == meCreateMode )
866 std::unique_ptr<SvXMLGraphicOutputStream> pOutputStream(new SvXMLGraphicOutputStream);
868 if( pOutputStream->Exists() )
870 xRet = pOutputStream.release();
871 maGrfStms.push_back( xRet );
875 return xRet;
878 OUString SAL_CALL SvXMLGraphicHelper::resolveOutputStream( const Reference< XOutputStream >& rxBinaryStream )
880 OUString aRet;
882 if( ( SvXMLGraphicHelperMode::Read == meCreateMode ) && rxBinaryStream.is() )
884 if( ::std::find( maGrfStms.begin(), maGrfStms.end(), rxBinaryStream ) != maGrfStms.end() )
886 SvXMLGraphicOutputStream* pOStm = static_cast< SvXMLGraphicOutputStream* >( rxBinaryStream.get() );
888 if( pOStm )
890 const GraphicObject& rGrfObj = pOStm->GetGraphicObject();
891 const OUString aId(OStringToOUString(
892 rGrfObj.GetUniqueID(), RTL_TEXTENCODING_ASCII_US));
894 if( !aId.isEmpty() )
896 aRet = XML_GRAPHICOBJECT_URL_BASE + aId;
902 return aRet;
905 // for instantiation via service manager
906 namespace {
908 namespace impl
910 typedef cppu::WeakComponentImplHelper<lang::XInitialization,
911 document::XGraphicObjectResolver,
912 document::XGraphicStorageHandler,
913 document::XBinaryStreamResolver,
914 lang::XServiceInfo>
915 SvXMLGraphicImportExportHelper_Base;
917 class MutexContainer
919 public:
920 virtual ~MutexContainer();
922 protected:
923 mutable ::osl::Mutex m_aMutex;
926 MutexContainer::~MutexContainer()
929 } // namespace impl
931 class SvXMLGraphicImportExportHelper :
932 public impl::MutexContainer,
933 public impl::SvXMLGraphicImportExportHelper_Base
935 public:
936 explicit SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode );
938 protected:
939 // is called from WeakComponentImplHelper when XComponent::dispose() was
940 // called from outside
941 virtual void SAL_CALL disposing() override;
943 // ____ XInitialization ____
944 // one argument is allowed, which is the XStorage
945 virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
947 // ____ XGraphicObjectResolver ____
948 virtual OUString SAL_CALL resolveGraphicObjectURL( const OUString& aURL ) override;
950 // ____ XGraphicStorageHandler ____
951 virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
952 loadGraphic(const OUString& aURL) override;
954 virtual css::uno::Reference<css::graphic::XGraphic> SAL_CALL
955 loadGraphicFromOutputStream(css::uno::Reference<css::io::XOutputStream> const & rxOutputStream) override;
957 virtual OUString SAL_CALL
958 saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
960 virtual OUString SAL_CALL
961 saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic, OUString & rOutSavedMimeType, OUString const & rRequestName) override;
963 virtual css::uno::Reference<css::io::XInputStream> SAL_CALL
964 createInputStream(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic) override;
966 // ____ XBinaryStreamResolver ____
967 virtual Reference< io::XInputStream > SAL_CALL getInputStream( const OUString& aURL ) override;
968 virtual Reference< io::XOutputStream > SAL_CALL createOutputStream() override;
969 virtual OUString SAL_CALL resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream ) override;
971 // ____ XServiceInfo ____
972 virtual OUString SAL_CALL getImplementationName() override;
973 virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
974 virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
976 private:
977 SvXMLGraphicHelperMode m_eGraphicHelperMode;
978 Reference< XGraphicObjectResolver > m_xGraphicObjectResolver;
979 Reference< XGraphicStorageHandler > m_xGraphicStorageHandler;
980 Reference< XBinaryStreamResolver > m_xBinaryStreamResolver;
983 SvXMLGraphicImportExportHelper::SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode ) :
984 impl::SvXMLGraphicImportExportHelper_Base( m_aMutex ),
985 m_eGraphicHelperMode( eMode )
988 void SAL_CALL SvXMLGraphicImportExportHelper::disposing()
990 Reference< XComponent > xComp( m_xGraphicObjectResolver, UNO_QUERY );
991 OSL_ASSERT( xComp.is());
992 if( xComp.is())
993 xComp->dispose();
994 // m_xBinaryStreamResolver and m_xGraphicStorageHandler are a reference to the same object,
995 // don't call dispose() again
998 // ____ XInitialization ____
999 void SAL_CALL SvXMLGraphicImportExportHelper::initialize(
1000 const Sequence< Any >& aArguments )
1002 Reference< embed::XStorage > xStorage;
1003 if( aArguments.hasElements() )
1004 aArguments[0] >>= xStorage;
1006 rtl::Reference<SvXMLGraphicHelper> pHelper( SvXMLGraphicHelper::Create( xStorage, m_eGraphicHelperMode ));
1007 m_xGraphicObjectResolver.set( pHelper.get() );
1008 m_xGraphicStorageHandler.set( pHelper.get() );
1009 m_xBinaryStreamResolver.set( pHelper.get() );
1012 // ____ XGraphicObjectResolver ____
1013 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveGraphicObjectURL( const OUString& aURL )
1015 return m_xGraphicObjectResolver->resolveGraphicObjectURL( aURL );
1018 // ____ XGraphicStorageHandler ____
1019 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphic(OUString const & rURL)
1021 return m_xGraphicStorageHandler->loadGraphic(rURL);
1024 uno::Reference<graphic::XGraphic> SAL_CALL SvXMLGraphicImportExportHelper::loadGraphicFromOutputStream(uno::Reference<io::XOutputStream> const & rxOutputStream)
1026 return m_xGraphicStorageHandler->loadGraphicFromOutputStream(rxOutputStream);
1029 OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphic(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic)
1031 return m_xGraphicStorageHandler->saveGraphic(rxGraphic);
1034 OUString SAL_CALL SvXMLGraphicImportExportHelper::saveGraphicByName(css::uno::Reference<css::graphic::XGraphic> const & rxGraphic,
1035 OUString & rOutSavedMimeType, OUString const & rRequestName)
1037 return m_xGraphicStorageHandler->saveGraphicByName(rxGraphic, rOutSavedMimeType, rRequestName);
1040 uno::Reference<io::XInputStream> SAL_CALL SvXMLGraphicImportExportHelper::createInputStream(uno::Reference<graphic::XGraphic> const & rxGraphic)
1042 return m_xGraphicStorageHandler->createInputStream(rxGraphic);
1045 // ____ XBinaryStreamResolver ____
1046 Reference< io::XInputStream > SAL_CALL SvXMLGraphicImportExportHelper::getInputStream( const OUString& aURL )
1048 return m_xBinaryStreamResolver->getInputStream( aURL );
1050 Reference< io::XOutputStream > SAL_CALL SvXMLGraphicImportExportHelper::createOutputStream()
1052 return m_xBinaryStreamResolver->createOutputStream();
1054 OUString SAL_CALL SvXMLGraphicImportExportHelper::resolveOutputStream( const Reference< io::XOutputStream >& aBinaryStream )
1056 return m_xBinaryStreamResolver->resolveOutputStream( aBinaryStream );
1059 // ____ XServiceInfo ____
1060 OUString SAL_CALL SvXMLGraphicImportExportHelper::getImplementationName()
1062 if( m_eGraphicHelperMode == SvXMLGraphicHelperMode::Read )
1063 return "com.sun.star.comp.Svx.GraphicImportHelper";
1064 return "com.sun.star.comp.Svx.GraphicExportHelper";
1067 sal_Bool SAL_CALL SvXMLGraphicImportExportHelper::supportsService( const OUString& ServiceName )
1069 return cppu::supportsService(this, ServiceName);
1072 Sequence< OUString > SAL_CALL SvXMLGraphicImportExportHelper::getSupportedServiceNames()
1074 return { "com.sun.star.document.GraphicObjectResolver",
1075 "com.sun.star.document.GraphicStorageHandler",
1076 "com.sun.star.document.BinaryStreamResolver" };
1081 /** Create this with createInstanceWithArguments. service name
1082 "com.sun.star.comp.Svx.GraphicImportHelper", one argument which is the
1083 XStorage. Without arguments no helper class is created. With an empty
1084 argument the helper class is created and initialized like in the CTOR to
1085 SvXMLGraphicHelper that only gets the create mode.
1087 You should call dispose after you no longer need this component.
1089 uses eCreateMode == SvXMLGraphicHelperMode::Read, bDirect == sal_True in
1090 SvXMLGraphicHelper
1092 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1093 com_sun_star_comp_Svx_GraphicImportHelper_get_implementation(
1094 css::uno::XComponentContext *,
1095 css::uno::Sequence<css::uno::Any> const &)
1097 return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Read));
1100 /** Create this with createInstanceWithArguments. service name
1101 "com.sun.star.comp.Svx.GraphicExportHelper", one argument which is the
1102 XStorage. Without arguments no helper class is created. With an empty
1103 argument the helper class is created and initialized like in the CTOR to
1104 SvXMLGraphicHelper that only gets the create mode
1106 To write the Pictures stream, you have to call dispose at this component.
1107 Make sure you call dispose before you commit the parent storage.
1109 uses eCreateMode == SvXMLGraphicHelperMode::Write, bDirect == sal_True in
1110 SvXMLGraphicHelper
1112 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
1113 com_sun_star_comp_Svx_GraphicExportHelper_get_implementation(
1114 css::uno::XComponentContext *,
1115 css::uno::Sequence<css::uno::Any> const &)
1117 return cppu::acquire(new SvXMLGraphicImportExportHelper(SvXMLGraphicHelperMode::Write));
1120 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */