1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <comphelper/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/filter/SvmWriter.hxx>
44 #include <vcl/gfxlink.hxx>
45 #include <vcl/metaact.hxx>
46 #include <tools/zcodec.hxx>
47 #include <comphelper/diagnose_ex.hxx>
49 #include <vcl/GraphicObject.hxx>
50 #include <vcl/graphicfilter.hxx>
51 #include <svx/xmlgrhlp.hxx>
52 #include <svx/xmleohlp.hxx>
56 #include <string_view>
59 using namespace com::sun::star
;
60 using namespace com::sun::star::uno
;
61 using namespace com::sun::star::io
;
63 namespace com::sun::star::uno
{ class XComponentContext
; }
65 constexpr OUStringLiteral XML_GRAPHICSTORAGE_NAME
= u
"Pictures";
66 constexpr OUStringLiteral XML_GRAPHICOBJECT_URL_BASE
= u
"vnd.sun.star.GraphicObject:";
70 const MetaCommentAction
* ImplCheckForEPS( GDIMetaFile
const & rMtf
)
72 const MetaCommentAction
* pComment
= nullptr;
74 if ( rMtf
.GetActionSize() >= 2
75 && rMtf
.GetAction(0)->GetType() == MetaActionType::EPS
76 && rMtf
.GetAction(1)->GetType() == MetaActionType::COMMENT
77 && ( static_cast<const MetaCommentAction
*>(rMtf
.GetAction( 1 ))->GetComment() == "EPSReplacementGraphic" ) )
78 pComment
= static_cast<const MetaCommentAction
*>(rMtf
.GetAction( 1 ));
83 class GraphicInputStream
: public cppu::WeakImplHelper
<XInputStream
>
86 virtual sal_Int32 SAL_CALL
readBytes(Sequence
<sal_Int8
> & aData
, sal_Int32 nBytesToRead
) override
;
87 virtual sal_Int32 SAL_CALL
readSomeBytes(Sequence
<sal_Int8
> & aData
, sal_Int32 nMaxBytesToRead
) override
;
88 virtual void SAL_CALL
skipBytes(sal_Int32 nBytesToSkip
) override
;
89 virtual sal_Int32 SAL_CALL
available() override
;
90 virtual void SAL_CALL
closeInput() override
;
93 utl::TempFileFast maTempFile
;
94 rtl::Reference
<::utl::OInputStreamWrapper
> mxStreamWrapper
;
98 explicit GraphicInputStream(GraphicObject
const & raGraphicObject
, const OUString
& rMimeType
);
99 GraphicInputStream(const GraphicInputStream
&) = delete;
101 GraphicInputStream
& operator=(const GraphicInputStream
&) = delete;
105 return mxStreamWrapper
.is();
110 GraphicInputStream::GraphicInputStream(GraphicObject
const & aGraphicObject
, const OUString
& rMimeType
)
112 if (aGraphicObject
.GetType() == GraphicType::NONE
)
115 SvStream
* pStream
= maTempFile
.GetStream(StreamMode::READWRITE
);
120 const Graphic
& aGraphic(aGraphicObject
.GetGraphic());
121 const GfxLink
aGfxLink(aGraphic
.GetGfxLink());
124 if (aGfxLink
.GetDataSize() && aGfxLink
.GetData())
126 if (rMimeType
.isEmpty())
128 pStream
->WriteBytes(aGfxLink
.GetData(), aGfxLink
.GetDataSize());
129 bRet
= (pStream
->GetError() == ERRCODE_NONE
);
133 GraphicFilter
&rFilter
= GraphicFilter::GetGraphicFilter();
134 bRet
= (rFilter
.ExportGraphic(aGraphic
, u
"", *pStream
, rFilter
.GetExportFormatNumberForMediaType(rMimeType
)) == ERRCODE_NONE
);
139 if (aGraphic
.GetType() == GraphicType::Bitmap
)
141 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
142 OUString aFormat
= rMimeType
;
144 if (aGraphic
.IsAnimated())
145 aFormat
= "image/gif";
146 else if (aFormat
.isEmpty())
147 aFormat
= "image/png";
149 bRet
= (rFilter
.ExportGraphic(aGraphic
, u
"", *pStream
, rFilter
.GetExportFormatNumberForMediaType(aFormat
)) == ERRCODE_NONE
);
151 else if (rMimeType
.isEmpty() && aGraphic
.GetType() == GraphicType::GdiMetafile
)
153 pStream
->SetVersion(SOFFICE_FILEFORMAT_8
);
154 pStream
->SetCompressMode(SvStreamCompressFlags::ZBITMAP
);
155 SvmWriter
aWriter(*pStream
);
156 aWriter
.Write(aGraphic
.GetGDIMetaFile());
157 bRet
= (pStream
->GetError() == ERRCODE_NONE
);
159 else if (!rMimeType
.isEmpty())
161 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
162 bRet
= ( rFilter
.ExportGraphic( aGraphic
, u
"", *pStream
, rFilter
.GetExportFormatNumberForMediaType( rMimeType
) ) == ERRCODE_NONE
);
169 mxStreamWrapper
= new ::utl::OInputStreamWrapper(*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
>
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
;
225 std::optional
<::utl::TempFileFast
> moTmp
;
227 rtl::Reference
< ::utl::OOutputStreamWrapper
> mxStmWrapper
;
228 std::optional
<GraphicObject
> moGrfObj
;
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 : moTmp(std::in_place
)
245 , moGrfObj(std::in_place
)
248 mpOStm
= moTmp
->GetStream( StreamMode::READWRITE
);
251 mxStmWrapper
= new ::utl::OOutputStreamWrapper( *mpOStm
);
254 SvXMLGraphicOutputStream::~SvXMLGraphicOutputStream()
259 void SAL_CALL
SvXMLGraphicOutputStream::writeBytes( const Sequence
< sal_Int8
>& rData
)
261 if( !mxStmWrapper
.is() )
262 throw NotConnectedException() ;
264 mxStmWrapper
->writeBytes( rData
);
267 void SAL_CALL
SvXMLGraphicOutputStream::flush()
269 if( !mxStmWrapper
.is() )
270 throw NotConnectedException() ;
272 mxStmWrapper
->flush();
275 void SAL_CALL
SvXMLGraphicOutputStream::closeOutput()
277 if( !mxStmWrapper
.is() )
278 throw NotConnectedException() ;
280 mxStmWrapper
->closeOutput();
281 mxStmWrapper
.clear();
286 Graphic
SvXMLGraphicOutputStream::GetGraphic()
290 if (mbClosed
&& moGrfObj
->GetType() == GraphicType::NONE
&& mpOStm
)
293 sal_uInt16 nFormat
= GRFILTER_FORMAT_DONTKNOW
;
294 sal_uInt16 nDeterminedFormat
= GRFILTER_FORMAT_DONTKNOW
;
295 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic
, u
"", *mpOStm
,nFormat
,&nDeterminedFormat
);
297 if (nDeterminedFormat
== GRFILTER_FORMAT_DONTKNOW
)
299 //Read the first two byte to check whether it is a gzipped stream, is so it may be in wmz or emz format
300 //unzip them and try again
302 sal_uInt8 sFirstBytes
[ 2 ];
304 sal_uInt64 nStreamLen
= mpOStm
->TellEnd();
307 if ( nStreamLen
== 0 )
309 SvLockBytes
* pLockBytes
= mpOStm
->GetLockBytes();
311 pLockBytes
->SetSynchronMode();
313 nStreamLen
= mpOStm
->TellEnd();
316 if( nStreamLen
>= 2 )
319 mpOStm
->ReadBytes(sFirstBytes
, 2);
321 if( sFirstBytes
[0] == 0x1f && sFirstBytes
[1] == 0x8b )
323 SvMemoryStream aDest
;
324 ZCodec
aZCodec( 0x8000, 0x8000 );
325 aZCodec
.BeginCompression(ZCODEC_DEFAULT_COMPRESSION
, /*gzLib*/true);
327 aZCodec
.Decompress( *mpOStm
, aDest
);
329 if (aZCodec
.EndCompression())
331 sal_uInt64 nStreamLen_
= aDest
.TellEnd();
335 GraphicFilter::GetGraphicFilter().ImportGraphic( aGraphic
, u
"", aDest
,nFormat
,&nDeterminedFormat
);
343 if (aGraphic
.GetType() != GraphicType::NONE
)
351 const GraphicObject
& SvXMLGraphicOutputStream::GetGraphicObject()
353 Graphic
aGraphic(GetGraphic());
354 if (aGraphic
.GetType() != GraphicType::NONE
)
356 moGrfObj
.emplace(std::move(aGraphic
));
363 SvXMLGraphicHelper::SvXMLGraphicHelper(SvXMLGraphicHelperMode eCreateMode
)
365 Init( nullptr, eCreateMode
);
368 SvXMLGraphicHelper::SvXMLGraphicHelper()
369 : meCreateMode(SvXMLGraphicHelperMode::Read
)
373 SvXMLGraphicHelper::~SvXMLGraphicHelper()
377 bool SvXMLGraphicHelper::ImplGetStreamNames( const OUString
& rURLStr
,
378 OUString
& rPictureStorageName
,
379 OUString
& rPictureStreamName
)
381 if (rURLStr
.isEmpty())
384 const OUString aURLStr
{rURLStr
.copy(rURLStr
.lastIndexOf(':')+1)};
386 if( !aURLStr
.isEmpty() && aURLStr
.indexOf('/')<0 ) // just one token?
388 rPictureStorageName
= OUString();
389 rPictureStreamName
= aURLStr
;
392 SvXMLEmbeddedObjectHelper::splitObjectURL(aURLStr
, rPictureStorageName
, rPictureStreamName
);
394 SAL_WARN_IF(rPictureStreamName
.isEmpty(), "svx", "SvXMLGraphicHelper::ImplInsertGraphicURL: invalid scheme: " << rURLStr
);
396 return !rPictureStreamName
.isEmpty();
399 uno::Reference
< embed::XStorage
> SvXMLGraphicHelper::ImplGetGraphicStorage( const OUString
& rStorageName
)
401 uno::Reference
< embed::XStorage
> xRetStorage
;
402 if( mxRootStorage
.is() )
406 maCurStorageName
= rStorageName
;
407 xRetStorage
= mxRootStorage
->openStorageElement(
409 ( SvXMLGraphicHelperMode::Write
== meCreateMode
)
410 ? embed::ElementModes::READWRITE
411 : embed::ElementModes::READ
);
413 catch ( uno::Exception
& )
416 //#i43196# try again to open the storage element - this time readonly
417 if(!xRetStorage
.is())
421 maCurStorageName
= rStorageName
;
422 xRetStorage
= mxRootStorage
->openStorageElement( maCurStorageName
, embed::ElementModes::READ
);
424 catch ( uno::Exception
& )
433 SvxGraphicHelperStream_Impl
SvXMLGraphicHelper::ImplGetGraphicStream( const OUString
& rPictureStorageName
,
434 const OUString
& rPictureStreamName
)
436 SvxGraphicHelperStream_Impl aRet
;
437 if (!rPictureStorageName
.isEmpty())
438 aRet
.xStorage
= ImplGetGraphicStorage(rPictureStorageName
);
440 aRet
.xStorage
= mxRootStorage
;
442 sal_Int32 nMode
= embed::ElementModes::READ
;
443 if (SvXMLGraphicHelperMode::Write
== meCreateMode
)
445 nMode
= embed::ElementModes::READWRITE
;
448 if (aRet
.xStorage
.is())
450 aRet
.xStream
= aRet
.xStorage
->openStreamElement( rPictureStreamName
, nMode
);
452 else if (rPictureStorageName
.indexOf('/') != -1)
454 uno::Reference
<embed::XHierarchicalStorageAccess
> xHierRootStorage(mxRootStorage
,
456 if (xHierRootStorage
.is())
460 aRet
.xStream
= xHierRootStorage
->openStreamElementByHierarchicalName(
461 rPictureStorageName
+ "/" + rPictureStreamName
, nMode
);
462 aRet
.xStorage
= mxRootStorage
;
464 catch (const uno::Exception
&)
466 TOOLS_WARN_EXCEPTION("svx",
467 "SvXMLGraphicHelper::ImplGetGraphicStream: failed to open "
468 << rPictureStreamName
);
473 if (aRet
.xStream
.is() && (SvXMLGraphicHelperMode::Write
== meCreateMode
))
475 uno::Reference
<beans::XPropertySet
> xProps(aRet
.xStream
, uno::UNO_QUERY
);
476 xProps
->setPropertyValue(u
"UseCommonStoragePasswordEncryption"_ustr
, uno::Any(true));
482 OUString
SvXMLGraphicHelper::ImplGetGraphicMimeType( std::u16string_view rFileName
)
484 if( ( rFileName
.size() >= 4 ) && ( rFileName
[ rFileName
.size() - 4 ] == '.' ) )
486 const OString
aExt(OUStringToOString(rFileName
.substr(rFileName
.size() - 3),
487 RTL_TEXTENCODING_ASCII_US
));
488 return comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension( aExt
);
494 Graphic
SvXMLGraphicHelper::ImplReadGraphic( const OUString
& rPictureStorageName
,
495 const OUString
& rPictureStreamName
)
497 Graphic aReturnGraphic
;
498 SvxGraphicHelperStream_Impl
aStream( ImplGetGraphicStream( rPictureStorageName
, rPictureStreamName
) );
499 if (aStream
.xStream
.is())
501 GraphicFilter
& rGraphicFilter
= GraphicFilter::GetGraphicFilter();
502 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(aStream
.xStream
));
503 Graphic aGraphic
= rGraphicFilter
.ImportUnloadedGraphic(*pStream
);
504 if (!aGraphic
.IsNone())
505 aReturnGraphic
= std::move(aGraphic
);
507 rGraphicFilter
.ImportGraphic(aReturnGraphic
, u
"", *pStream
);
510 return aReturnGraphic
;
513 void SvXMLGraphicHelper::Init( const uno::Reference
< embed::XStorage
>& rXMLStorage
,
514 SvXMLGraphicHelperMode eCreateMode
,
515 const OUString
& rGraphicMimeType
)
517 mxRootStorage
= rXMLStorage
;
518 meCreateMode
= eCreateMode
;
519 maOutputMimeType
= rGraphicMimeType
;
522 rtl::Reference
<SvXMLGraphicHelper
> SvXMLGraphicHelper::Create( const uno::Reference
< embed::XStorage
>& rXMLStorage
,
523 SvXMLGraphicHelperMode eCreateMode
)
525 rtl::Reference
<SvXMLGraphicHelper
> pThis
= new SvXMLGraphicHelper
;
526 pThis
->Init( rXMLStorage
, eCreateMode
, OUString() );
531 rtl::Reference
<SvXMLGraphicHelper
> SvXMLGraphicHelper::Create( SvXMLGraphicHelperMode eCreateMode
,
532 const OUString
& rGraphicMimeType
)
534 rtl::Reference
<SvXMLGraphicHelper
> pThis
= new SvXMLGraphicHelper
;
536 pThis
->Init( nullptr, eCreateMode
, rGraphicMimeType
);
544 void splitUserDataFromURL(OUString
const & rWholeURL
, OUString
& rJustURL
, OUString
& rUserData
)
546 sal_Int32 nUser
= rWholeURL
.indexOf('?');
549 rJustURL
= rWholeURL
.copy(0, nUser
);
551 rUserData
= rWholeURL
.copy(nUser
);
555 rJustURL
= rWholeURL
;
559 } // end anonymous namespace
561 // XGraphicObjectResolver
562 OUString SAL_CALL
SvXMLGraphicHelper::resolveGraphicObjectURL( const OUString
& /*rURL*/ )
564 throw uno::RuntimeException(u
"XGraphicObjectResolver has been removed in LibreOffice 6.1"_ustr
);
567 // XGraphicStorageHandler
568 uno::Reference
<graphic::XGraphic
> SAL_CALL
SvXMLGraphicHelper::loadGraphic(OUString
const & rURL
)
570 std::unique_lock
aGuard(m_aMutex
);
572 uno::Reference
<graphic::XGraphic
> xGraphic
;
576 splitUserDataFromURL(rURL
, aURLOnly
, aUserData
);
578 auto aIterator
= maGraphicObjects
.find(aURLOnly
);
579 if (aIterator
!= maGraphicObjects
.end())
581 return aIterator
->second
;
584 OUString aPictureStorageName
, aPictureStreamName
;
586 if (ImplGetStreamNames(aURLOnly
, aPictureStorageName
, aPictureStreamName
))
588 const GraphicObject
aGraphicObject(ImplReadGraphic(aPictureStorageName
, aPictureStreamName
));
590 if (aGraphicObject
.GetType() != GraphicType::NONE
)
592 xGraphic
= aGraphicObject
.GetGraphic().GetXGraphic();
593 maGraphicObjects
[aURLOnly
] = xGraphic
;
600 uno::Reference
<graphic::XGraphic
> SAL_CALL
SvXMLGraphicHelper::loadGraphicFromOutputStream(uno::Reference
<io::XOutputStream
> const & rxOutputStream
)
602 std::unique_lock
aGuard(m_aMutex
);
604 uno::Reference
<graphic::XGraphic
> xGraphic
;
606 if ((SvXMLGraphicHelperMode::Read
== meCreateMode
) && rxOutputStream
.is())
609 SvXMLGraphicOutputStream
* pGraphicOutputStream
= static_cast<SvXMLGraphicOutputStream
*>(rxOutputStream
.get());
610 if (pGraphicOutputStream
)
612 xGraphic
= pGraphicOutputStream
->GetGraphic().GetXGraphic();
618 OUString SAL_CALL
SvXMLGraphicHelper::saveGraphicByName(css::uno::Reference
<css::graphic::XGraphic
> const & rxGraphic
,
619 OUString
& rOutSavedMimeType
, OUString
const & rRequestName
)
621 return implSaveGraphic(rxGraphic
, rOutSavedMimeType
, rRequestName
);
624 OUString SAL_CALL
SvXMLGraphicHelper::saveGraphic(css::uno::Reference
<css::graphic::XGraphic
> const & rxGraphic
)
626 OUString aOutMimeType
;
627 return implSaveGraphic(rxGraphic
, aOutMimeType
, std::u16string_view());
630 OUString
SvXMLGraphicHelper::implSaveGraphic(css::uno::Reference
<css::graphic::XGraphic
> const & rxGraphic
,
631 OUString
& rOutSavedMimeType
, std::u16string_view rRequestName
)
633 Graphic
aGraphic(rxGraphic
);
635 auto aIterator
= maExportGraphics
.find(aGraphic
);
636 if (aIterator
!= maExportGraphics
.end())
638 auto const & aURLAndMimePair
= aIterator
->second
;
639 rOutSavedMimeType
= aURLAndMimePair
.second
;
640 return aURLAndMimePair
.first
;
643 GraphicObject
aGraphicObject(aGraphic
);
645 if (aGraphicObject
.GetType() != GraphicType::NONE
)
647 const GfxLink
aGfxLink(aGraphic
.GetGfxLink());
649 bool bUseGfxLink
= true;
651 if (aGfxLink
.GetDataSize())
653 switch (aGfxLink
.GetType())
655 case GfxLinkType::EpsBuffer
: aExtension
= ".eps"; break;
656 case GfxLinkType::NativeGif
: aExtension
= ".gif"; break;
657 // #i15508# added BMP type for better exports (checked, works)
658 case GfxLinkType::NativeBmp
: aExtension
= ".bmp"; break;
659 case GfxLinkType::NativeJpg
: aExtension
= ".jpg"; break;
660 case GfxLinkType::NativePng
: aExtension
= ".png"; break;
661 case GfxLinkType::NativeTif
: aExtension
= ".tif"; break;
662 case GfxLinkType::NativeWmf
:
663 if (aGfxLink
.IsEMF())
668 case GfxLinkType::NativeMet
: aExtension
= ".met"; break;
669 case GfxLinkType::NativePct
: aExtension
= ".pct"; break;
670 case GfxLinkType::NativeSvg
:
672 // backward-compat kludge: since no released OOo
673 // version to date can handle svg properly, wrap it up
674 // into an svm. slight catch22 here, since strict ODF
675 // conformance _recommends_ svg - then again, most old
676 // ODF consumers are believed to be OOo
677 auto nSaneVersion
= GetODFSaneDefaultVersion();
678 if ( nSaneVersion
< SvtSaveOptions::ODFSVER_012
679 || nSaneVersion
== SvtSaveOptions::ODFSVER_012_EXT_COMPAT
)
690 case GfxLinkType::NativePdf
: aExtension
= ".pdf"; break;
691 case GfxLinkType::NativeWebp
: aExtension
= ".webp"; break;
700 if (aGraphicObject
.GetType() == GraphicType::Bitmap
)
702 if (aGraphicObject
.IsAnimated())
707 else if (aGraphicObject
.GetType() == GraphicType::GdiMetafile
)
709 // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
710 GDIMetaFile
& rMetafile(const_cast<GDIMetaFile
&>(aGraphic
.GetGDIMetaFile()));
712 if (ImplCheckForEPS(rMetafile
))
719 OUString rPictureStreamName
;
720 if (!rRequestName
.empty())
722 rPictureStreamName
= rRequestName
+ aExtension
;
726 OUString sId
= OStringToOUString(aGraphicObject
.GetUniqueID(), RTL_TEXTENCODING_ASCII_US
);
727 rPictureStreamName
= sId
+ aExtension
;
730 SvxGraphicHelperStream_Impl
aStream(ImplGetGraphicStream(XML_GRAPHICSTORAGE_NAME
, rPictureStreamName
));
732 if (aStream
.xStream
.is())
734 const OUString
aMimeType(ImplGetGraphicMimeType(rPictureStreamName
));
735 uno::Reference
<beans::XPropertySet
> xProps(aStream
.xStream
, uno::UNO_QUERY
);
737 // set stream properties (MediaType/Compression)
738 if (!aMimeType
.isEmpty())
740 xProps
->setPropertyValue(u
"MediaType"_ustr
, uno::Any(aMimeType
));
743 // picture formats that actually _do_ benefit from zip
744 // storage compression
745 // .svm pics gets compressed via ZBITMAP old-style stream
747 static const char* aCompressiblePics
[] =
758 bool bSuccess
= false;
760 bool bCompressed
= aMimeType
.isEmpty();
763 for(const char* p
: aCompressiblePics
)
765 if( aMimeType
.equalsIgnoreAsciiCaseAscii(p
) )
773 xProps
->setPropertyValue(u
"Compressed"_ustr
, Any(bCompressed
));
775 std::unique_ptr
<SvStream
> pStream(utl::UcbStreamHelper::CreateStream(aStream
.xStream
));
776 if (bUseGfxLink
&& aGfxLink
.GetDataSize() && aGfxLink
.GetData())
778 pStream
->WriteBytes(aGfxLink
.GetData(), aGfxLink
.GetDataSize());
779 rOutSavedMimeType
= aMimeType
;
780 bSuccess
= (pStream
->GetError() == ERRCODE_NONE
);
784 if (aGraphic
.GetType() == GraphicType::Bitmap
)
786 GraphicFilter
& rFilter
= GraphicFilter::GetGraphicFilter();
789 if (aGraphic
.IsAnimated())
797 rOutSavedMimeType
= comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(aFormat
.toUtf8());
799 bSuccess
= (rFilter
.ExportGraphic(aGraphic
, u
"", *pStream
, rFilter
.GetExportFormatNumberForShortName(aFormat
)) == ERRCODE_NONE
);
801 else if (aGraphic
.GetType() == GraphicType::GdiMetafile
)
803 pStream
->SetVersion(SOFFICE_FILEFORMAT_8
);
804 pStream
->SetCompressMode(SvStreamCompressFlags::ZBITMAP
);
805 rOutSavedMimeType
= comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension("svm");
807 // SJ: first check if this metafile is just an eps file, then we will store the eps instead of svm
808 GDIMetaFile
& rMtf(const_cast<GDIMetaFile
&>(aGraphic
.GetGDIMetaFile()));
809 const MetaCommentAction
* pComment
= ImplCheckForEPS(rMtf
);
812 sal_uInt32 nSize
= pComment
->GetDataSize();
813 const sal_uInt8
* pData
= pComment
->GetData();
815 pStream
->WriteBytes(pData
, nSize
);
817 const MetaEPSAction
* pAct
= static_cast<const MetaEPSAction
*>(rMtf
.FirstAction());
818 const GfxLink
& rLink
= pAct
->GetLink();
820 pStream
->WriteBytes(rLink
.GetData(), rLink
.GetDataSize());
824 SvmWriter
aWriter(*pStream
);
828 bSuccess
= (pStream
->GetError() == ERRCODE_NONE
);
835 uno::Reference
<embed::XTransactedObject
> xStorage(aStream
.xStorage
, uno::UNO_QUERY
);
837 aStream
.xStream
->getOutputStream()->closeOutput();
841 OUString aStoragePath
= "Pictures/" + rPictureStreamName
;
844 maExportGraphics
[aGraphic
] = std::make_pair(aStoragePath
, rOutSavedMimeType
);
853 uno::Reference
<io::XInputStream
> SAL_CALL
SvXMLGraphicHelper::createInputStream(uno::Reference
<graphic::XGraphic
> const & rxGraphic
)
855 Reference
<XInputStream
> xInputStream
;
857 GraphicObject
aGraphicObject((Graphic(rxGraphic
)));
859 if (SvXMLGraphicHelperMode::Write
== meCreateMode
)
861 OUString sMimeType
= comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(OUStringToOString(maOutputMimeType
, RTL_TEXTENCODING_ASCII_US
));
862 rtl::Reference
<GraphicInputStream
> pInputStream(new GraphicInputStream(aGraphicObject
, sMimeType
));
864 // We release the pointer from unique_ptr and assign it to the input stream return type.
865 // In case the stream doesn't exists, unique_ptr will delete the pointer when we go out of scope.
866 if (pInputStream
->exists())
867 xInputStream
= pInputStream
.get();
873 // XBinaryStreamResolver
874 Reference
< XInputStream
> SAL_CALL
SvXMLGraphicHelper::getInputStream( const OUString
& /*rURL*/ )
876 Reference
<XInputStream
> xRet
;
880 Reference
< XOutputStream
> SAL_CALL
SvXMLGraphicHelper::createOutputStream()
882 Reference
< XOutputStream
> xRet
;
884 if( SvXMLGraphicHelperMode::Read
== meCreateMode
)
886 rtl::Reference
<SvXMLGraphicOutputStream
> pOutputStream(new SvXMLGraphicOutputStream
);
888 if( pOutputStream
->Exists() )
890 xRet
= pOutputStream
.get();
891 maGrfStms
.push_back( xRet
);
898 OUString SAL_CALL
SvXMLGraphicHelper::resolveOutputStream( const Reference
< XOutputStream
>& rxBinaryStream
)
902 if( ( SvXMLGraphicHelperMode::Read
== meCreateMode
) && rxBinaryStream
.is() )
904 if( ::std::find( maGrfStms
.begin(), maGrfStms
.end(), rxBinaryStream
) != maGrfStms
.end() )
906 SvXMLGraphicOutputStream
* pOStm
= static_cast< SvXMLGraphicOutputStream
* >( rxBinaryStream
.get() );
910 const GraphicObject
& rGrfObj
= pOStm
->GetGraphicObject();
911 const OUString
aId(OStringToOUString(
912 rGrfObj
.GetUniqueID(), RTL_TEXTENCODING_ASCII_US
));
916 aRet
= XML_GRAPHICOBJECT_URL_BASE
+ aId
;
925 // for instantiation via service manager
930 typedef comphelper::WeakComponentImplHelper
<lang::XInitialization
,
931 document::XGraphicObjectResolver
,
932 document::XGraphicStorageHandler
,
933 document::XBinaryStreamResolver
,
935 SvXMLGraphicImportExportHelper_Base
;
939 class SvXMLGraphicImportExportHelper
:
940 public impl::SvXMLGraphicImportExportHelper_Base
943 explicit SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode
);
946 // is called from WeakComponentImplHelper when XComponent::dispose() was
947 // called from outside
948 virtual void disposing(std::unique_lock
<std::mutex
>&) override
;
950 // ____ XInitialization ____
951 // one argument is allowed, which is the XStorage
952 virtual void SAL_CALL
initialize( const Sequence
< Any
>& aArguments
) override
;
954 // ____ XGraphicObjectResolver ____
955 virtual OUString SAL_CALL
resolveGraphicObjectURL( const OUString
& aURL
) override
;
957 // ____ XGraphicStorageHandler ____
958 virtual css::uno::Reference
<css::graphic::XGraphic
> SAL_CALL
959 loadGraphic(const OUString
& aURL
) override
;
961 virtual css::uno::Reference
<css::graphic::XGraphic
> SAL_CALL
962 loadGraphicFromOutputStream(css::uno::Reference
<css::io::XOutputStream
> const & rxOutputStream
) override
;
964 virtual OUString SAL_CALL
965 saveGraphic(css::uno::Reference
<css::graphic::XGraphic
> const & rxGraphic
) override
;
967 virtual OUString SAL_CALL
968 saveGraphicByName(css::uno::Reference
<css::graphic::XGraphic
> const & rxGraphic
, OUString
& rOutSavedMimeType
, OUString
const & rRequestName
) override
;
970 virtual css::uno::Reference
<css::io::XInputStream
> SAL_CALL
971 createInputStream(css::uno::Reference
<css::graphic::XGraphic
> const & rxGraphic
) override
;
973 // ____ XBinaryStreamResolver ____
974 virtual Reference
< io::XInputStream
> SAL_CALL
getInputStream( const OUString
& aURL
) override
;
975 virtual Reference
< io::XOutputStream
> SAL_CALL
createOutputStream() override
;
976 virtual OUString SAL_CALL
resolveOutputStream( const Reference
< io::XOutputStream
>& aBinaryStream
) override
;
978 // ____ XServiceInfo ____
979 virtual OUString SAL_CALL
getImplementationName() override
;
980 virtual sal_Bool SAL_CALL
supportsService( const OUString
& ServiceName
) override
;
981 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
984 SvXMLGraphicHelperMode m_eGraphicHelperMode
;
985 rtl::Reference
<SvXMLGraphicHelper
> m_xXMLGraphicHelper
;
988 SvXMLGraphicImportExportHelper::SvXMLGraphicImportExportHelper( SvXMLGraphicHelperMode eMode
) :
989 m_eGraphicHelperMode( eMode
)
992 void SvXMLGraphicImportExportHelper::disposing(std::unique_lock
<std::mutex
>&)
994 if (m_xXMLGraphicHelper
)
996 m_xXMLGraphicHelper
->dispose();
997 m_xXMLGraphicHelper
.clear();
1001 // ____ XInitialization ____
1002 void SAL_CALL
SvXMLGraphicImportExportHelper::initialize(
1003 const Sequence
< Any
>& aArguments
)
1005 Reference
< embed::XStorage
> xStorage
;
1006 if( aArguments
.hasElements() )
1007 aArguments
[0] >>= xStorage
;
1009 m_xXMLGraphicHelper
= SvXMLGraphicHelper::Create( xStorage
, m_eGraphicHelperMode
);
1012 // ____ XGraphicObjectResolver ____
1013 OUString SAL_CALL
SvXMLGraphicImportExportHelper::resolveGraphicObjectURL( const OUString
& aURL
)
1015 return m_xXMLGraphicHelper
->resolveGraphicObjectURL( aURL
);
1018 // ____ XGraphicStorageHandler ____
1019 uno::Reference
<graphic::XGraphic
> SAL_CALL
SvXMLGraphicImportExportHelper::loadGraphic(OUString
const & rURL
)
1021 return m_xXMLGraphicHelper
->loadGraphic(rURL
);
1024 uno::Reference
<graphic::XGraphic
> SAL_CALL
SvXMLGraphicImportExportHelper::loadGraphicFromOutputStream(uno::Reference
<io::XOutputStream
> const & rxOutputStream
)
1026 return m_xXMLGraphicHelper
->loadGraphicFromOutputStream(rxOutputStream
);
1029 OUString SAL_CALL
SvXMLGraphicImportExportHelper::saveGraphic(css::uno::Reference
<css::graphic::XGraphic
> const & rxGraphic
)
1031 return m_xXMLGraphicHelper
->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_xXMLGraphicHelper
->saveGraphicByName(rxGraphic
, rOutSavedMimeType
, rRequestName
);
1040 uno::Reference
<io::XInputStream
> SAL_CALL
SvXMLGraphicImportExportHelper::createInputStream(uno::Reference
<graphic::XGraphic
> const & rxGraphic
)
1042 return m_xXMLGraphicHelper
->createInputStream(rxGraphic
);
1045 // ____ XBinaryStreamResolver ____
1046 Reference
< io::XInputStream
> SAL_CALL
SvXMLGraphicImportExportHelper::getInputStream( const OUString
& aURL
)
1048 return m_xXMLGraphicHelper
->getInputStream( aURL
);
1050 Reference
< io::XOutputStream
> SAL_CALL
SvXMLGraphicImportExportHelper::createOutputStream()
1052 return m_xXMLGraphicHelper
->createOutputStream();
1054 OUString SAL_CALL
SvXMLGraphicImportExportHelper::resolveOutputStream( const Reference
< io::XOutputStream
>& aBinaryStream
)
1056 return m_xXMLGraphicHelper
->resolveOutputStream( aBinaryStream
);
1059 // ____ XServiceInfo ____
1060 OUString SAL_CALL
SvXMLGraphicImportExportHelper::getImplementationName()
1062 if( m_eGraphicHelperMode
== SvXMLGraphicHelperMode::Read
)
1063 return u
"com.sun.star.comp.Svx.GraphicImportHelper"_ustr
;
1064 return u
"com.sun.star.comp.Svx.GraphicExportHelper"_ustr
;
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 { u
"com.sun.star.document.GraphicObjectResolver"_ustr
,
1075 u
"com.sun.star.document.GraphicStorageHandler"_ustr
,
1076 u
"com.sun.star.document.BinaryStreamResolver"_ustr
};
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
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
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
));
1122 void DropUnusedNamedItems(css::uno::Reference
<css::uno::XInterface
> const& xModel
)
1124 uno::Reference
<lang::XMultiServiceFactory
> const xModelFactory(xModel
, uno::UNO_QUERY
);
1125 assert(xModelFactory
.is());
1128 uno::Reference
<util::XCancellable
> const xGradient(
1129 xModelFactory
->createInstance(u
"com.sun.star.drawing.GradientTable"_ustr
),
1133 xGradient
->cancel();
1136 uno::Reference
<util::XCancellable
> const xHatch(
1137 xModelFactory
->createInstance(u
"com.sun.star.drawing.HatchTable"_ustr
),
1144 uno::Reference
<util::XCancellable
> const xBitmap(
1145 xModelFactory
->createInstance(u
"com.sun.star.drawing.BitmapTable"_ustr
),
1152 uno::Reference
<util::XCancellable
> const xTransGradient(
1153 xModelFactory
->createInstance(u
"com.sun.star.drawing.TransparencyGradientTable"_ustr
),
1155 if (xTransGradient
.is())
1157 xTransGradient
->cancel();
1160 uno::Reference
<util::XCancellable
> const xMarker(
1161 xModelFactory
->createInstance(u
"com.sun.star.drawing.MarkerTable"_ustr
),
1168 uno::Reference
<util::XCancellable
> const xDashes(
1169 xModelFactory
->createInstance(u
"com.sun.star.drawing.DashTable"_ustr
),
1176 catch (const Exception
&)
1178 TOOLS_WARN_EXCEPTION("svx", "dropUnusedNamedItems(): exception during clearing of unused named items");
1184 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */