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 <com/sun/star/container/XNameContainer.hpp>
21 #include <oox/helper/graphichelper.hxx>
23 #include <com/sun/star/awt/Point.hpp>
24 #include <com/sun/star/awt/Size.hpp>
25 #include <com/sun/star/awt/XDevice.hpp>
26 #include <com/sun/star/awt/XUnitConversion.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/frame/Desktop.hpp>
29 #include <com/sun/star/graphic/GraphicObject.hpp>
30 #include <com/sun/star/graphic/GraphicProvider.hpp>
31 #include <com/sun/star/graphic/XGraphicProvider.hpp>
32 #include <com/sun/star/util/MeasureUnit.hpp>
33 #include <osl/diagnose.h>
34 #include <sal/log.hxx>
35 #include <comphelper/seqstream.hxx>
36 #include <vcl/wmf.hxx>
37 #include <vcl/wmfexternal.hxx>
38 #include <vcl/svapp.hxx>
39 #include <vcl/outdev.hxx>
40 #include <tools/gen.hxx>
41 #include <comphelper/propertysequence.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <oox/helper/containerhelper.hxx>
44 #include <oox/helper/propertyset.hxx>
45 #include <oox/token/properties.hxx>
46 #include <oox/token/tokens.hxx>
50 using namespace ::com::sun::star
;
51 using namespace ::com::sun::star::beans
;
52 using namespace ::com::sun::star::frame
;
53 using namespace ::com::sun::star::graphic
;
54 using namespace ::com::sun::star::io
;
55 using namespace ::com::sun::star::lang
;
56 using namespace ::com::sun::star::uno
;
60 sal_Int32
lclConvertScreenPixelToHmm( double fPixel
, double fPixelPerHmm
)
62 return static_cast< sal_Int32
>( (fPixelPerHmm
> 0.0) ? (fPixel
/ fPixelPerHmm
+ 0.5) : 0.0 );
67 GraphicHelper::GraphicHelper( const Reference
< XComponentContext
>& rxContext
, const Reference
< XFrame
>& rxTargetFrame
, const StorageRef
& rxStorage
) :
68 mxContext( rxContext
),
69 mxStorage( rxStorage
)
71 OSL_ENSURE( mxContext
.is(), "GraphicHelper::GraphicHelper - missing component context" );
73 mxGraphicProvider
.set( graphic::GraphicProvider::create( mxContext
), uno::UNO_QUERY
);
75 //! TODO: get colors from system
76 maSystemPalette
[ XML_3dDkShadow
] = Color(0x716F64);
77 maSystemPalette
[ XML_3dLight
] = Color(0xF1EFE2);
78 maSystemPalette
[ XML_activeBorder
] = Color(0xD4D0C8);
79 maSystemPalette
[ XML_activeCaption
] = Color(0x0054E3);
80 maSystemPalette
[ XML_appWorkspace
] = Color(0x808080);
81 maSystemPalette
[ XML_background
] = Color(0x004E98);
82 maSystemPalette
[ XML_btnFace
] = Color(0xECE9D8);
83 maSystemPalette
[ XML_btnHighlight
] = Color(0xFFFFFF);
84 maSystemPalette
[ XML_btnShadow
] = Color(0xACA899);
85 maSystemPalette
[ XML_btnText
] = Color(0x000000);
86 maSystemPalette
[ XML_captionText
] = Color(0xFFFFFF);
87 maSystemPalette
[ XML_gradientActiveCaption
] = Color(0x3D95FF);
88 maSystemPalette
[ XML_gradientInactiveCaption
] = Color(0xD8E4F8);
89 maSystemPalette
[ XML_grayText
] = Color(0xACA899);
90 maSystemPalette
[ XML_highlight
] = Color(0x316AC5);
91 maSystemPalette
[ XML_highlightText
] = Color(0xFFFFFF);
92 maSystemPalette
[ XML_hotLight
] = Color(0x000080);
93 maSystemPalette
[ XML_inactiveBorder
] = Color(0xD4D0C8);
94 maSystemPalette
[ XML_inactiveCaption
] = Color(0x7A96DF);
95 maSystemPalette
[ XML_inactiveCaptionText
] = Color(0xD8E4F8);
96 maSystemPalette
[ XML_infoBk
] = Color(0xFFFFE1);
97 maSystemPalette
[ XML_infoText
] = Color(0x000000);
98 maSystemPalette
[ XML_menu
] = Color(0xFFFFFF);
99 maSystemPalette
[ XML_menuBar
] = Color(0xECE9D8);
100 maSystemPalette
[ XML_menuHighlight
] = Color(0x316AC5);
101 maSystemPalette
[ XML_menuText
] = Color(0x000000);
102 maSystemPalette
[ XML_scrollBar
] = Color(0xD4D0C8);
103 maSystemPalette
[ XML_window
] = Color(0xFFFFFF);
104 maSystemPalette
[ XML_windowFrame
] = Color(0x000000);
105 maSystemPalette
[ XML_windowText
] = Color(0x000000);
107 // if no target frame has been passed (e.g. OLE objects), try to fallback to the active frame
108 // TODO: we need some mechanism to keep and pass the parent frame
109 Reference
< XFrame
> xFrame
= rxTargetFrame
;
110 if( !xFrame
.is() && mxContext
.is() ) try
112 Reference
< XDesktop2
> xFramesSupp
= Desktop::create( mxContext
);
113 xFrame
= xFramesSupp
->getActiveFrame();
119 // get the metric of the output device
120 OSL_ENSURE( xFrame
.is(), "GraphicHelper::GraphicHelper - cannot get target frame" );
121 // some default just in case, 100 000 is 1 meter in MM100
122 Size aDefault
= Application::GetDefaultDevice()->LogicToPixel(Size(100000, 100000), MapMode(MapUnit::Map100thMM
));
123 maDeviceInfo
.PixelPerMeterX
= aDefault
.Width();
124 maDeviceInfo
.PixelPerMeterY
= aDefault
.Height();
125 if( xFrame
.is() ) try
127 Reference
< awt::XDevice
> xDevice( xFrame
->getContainerWindow(), UNO_QUERY_THROW
);
128 mxUnitConversion
.set( xDevice
, UNO_QUERY
);
129 OSL_ENSURE( mxUnitConversion
.is(), "GraphicHelper::GraphicHelper - cannot get unit converter" );
130 maDeviceInfo
= xDevice
->getInfo();
134 OSL_FAIL( "GraphicHelper::GraphicHelper - cannot get output device info" );
136 mfPixelPerHmmX
= maDeviceInfo
.PixelPerMeterX
/ 100000.0;
137 mfPixelPerHmmY
= maDeviceInfo
.PixelPerMeterY
/ 100000.0;
140 GraphicHelper::~GraphicHelper()
144 // System colors and predefined colors ----------------------------------------
146 ::Color
GraphicHelper::getSystemColor( sal_Int32 nToken
, ::Color nDefaultRgb
) const
148 return ContainerHelper::getMapElement( maSystemPalette
, nToken
, nDefaultRgb
);
151 ::Color
GraphicHelper::getSchemeColor( sal_Int32
/*nToken*/ ) const
153 OSL_FAIL( "GraphicHelper::getSchemeColor - scheme colors not implemented" );
154 return API_RGB_TRANSPARENT
;
157 ::Color
GraphicHelper::getPaletteColor( sal_Int32
/*nPaletteIdx*/ ) const
159 OSL_FAIL( "GraphicHelper::getPaletteColor - palette colors not implemented" );
160 return API_RGB_TRANSPARENT
;
163 sal_Int32
GraphicHelper::getDefaultChartAreaFillStyle() const
165 return XML_solidFill
;
168 sal_Int32
GraphicHelper::getDefaultChartAreaLineStyle()
170 return XML_solidFill
;
173 sal_Int16
GraphicHelper::getDefaultChartAreaLineWidth()
175 // this value is what MSO 2016 writes fixing incomplete MSO 2010 documents (0.75 pt in emu)
179 // Device info and device dependent unit conversion ---------------------------
181 sal_Int32
GraphicHelper::convertScreenPixelXToHmm( double fPixelX
) const
183 return lclConvertScreenPixelToHmm( fPixelX
, mfPixelPerHmmX
);
186 sal_Int32
GraphicHelper::convertScreenPixelYToHmm( double fPixelY
) const
188 return lclConvertScreenPixelToHmm( fPixelY
, mfPixelPerHmmY
);
191 awt::Size
GraphicHelper::convertScreenPixelToHmm( const awt::Size
& rPixel
) const
193 return awt::Size( convertScreenPixelXToHmm( rPixel
.Width
), convertScreenPixelYToHmm( rPixel
.Height
) );
196 double GraphicHelper::convertHmmToScreenPixelX( sal_Int32 nHmmX
) const
198 return nHmmX
* mfPixelPerHmmX
;
201 double GraphicHelper::convertHmmToScreenPixelY( sal_Int32 nHmmY
) const
203 return nHmmY
* mfPixelPerHmmY
;
206 awt::Point
GraphicHelper::convertHmmToScreenPixel( const awt::Point
& rHmm
) const
209 static_cast< sal_Int32
>( convertHmmToScreenPixelX( rHmm
.X
) + 0.5 ),
210 static_cast< sal_Int32
>( convertHmmToScreenPixelY( rHmm
.Y
) + 0.5 ) );
213 awt::Size
GraphicHelper::convertHmmToScreenPixel( const awt::Size
& rHmm
) const
216 static_cast< sal_Int32
>( convertHmmToScreenPixelX( rHmm
.Width
) + 0.5 ),
217 static_cast< sal_Int32
>( convertHmmToScreenPixelY( rHmm
.Height
) + 0.5 ) );
220 awt::Point
GraphicHelper::convertHmmToAppFont( const awt::Point
& rHmm
) const
222 if( mxUnitConversion
.is() ) try
224 awt::Point aPixel
= convertHmmToScreenPixel( rHmm
);
225 return mxUnitConversion
->convertPointToLogic( aPixel
, css::util::MeasureUnit::APPFONT
);
230 return awt::Point( 0, 0 );
233 awt::Size
GraphicHelper::convertHmmToAppFont( const awt::Size
& rHmm
) const
235 if( mxUnitConversion
.is() ) try
237 awt::Size aPixel
= convertHmmToScreenPixel( rHmm
);
238 return mxUnitConversion
->convertSizeToLogic( aPixel
, css::util::MeasureUnit::APPFONT
);
243 return awt::Size( 0, 0 );
246 // Graphics and graphic objects ----------------------------------------------
248 Reference
< XGraphic
> GraphicHelper::importGraphic( const Reference
< XInputStream
>& rxInStrm
,
249 const WmfExternal
* pExtHeader
) const
251 Reference
< XGraphic
> xGraphic
;
252 if( rxInStrm
.is() && mxGraphicProvider
.is() ) try
254 Sequence
< PropertyValue
> aArgs( 2 );
255 aArgs
[ 0 ].Name
= "InputStream";
256 aArgs
[ 0 ].Value
<<= rxInStrm
;
257 aArgs
[ 1 ].Name
= "LazyRead";
258 bool bLazyRead
= !pExtHeader
;
259 aArgs
[ 1 ].Value
<<= bLazyRead
;
261 if ( pExtHeader
&& pExtHeader
->mapMode
> 0 )
263 aArgs
.realloc( aArgs
.getLength() + 1 );
264 Sequence
< PropertyValue
> aFilterData( 3 );
265 aFilterData
[ 0 ].Name
= "ExternalWidth";
266 aFilterData
[ 0 ].Value
<<= pExtHeader
->xExt
;
267 aFilterData
[ 1 ].Name
= "ExternalHeight";
268 aFilterData
[ 1 ].Value
<<= pExtHeader
->yExt
;
269 aFilterData
[ 2 ].Name
= "ExternalMapMode";
270 aFilterData
[ 2 ].Value
<<= pExtHeader
->mapMode
;
271 aArgs
[ 2 ].Name
= "FilterData";
272 aArgs
[ 2 ].Value
<<= aFilterData
;
275 xGraphic
= mxGraphicProvider
->queryGraphic( aArgs
);
283 std::vector
< uno::Reference
<graphic::XGraphic
> > GraphicHelper::importGraphics(const std::vector
< uno::Reference
<io::XInputStream
> >& rStreams
) const
285 std::vector
< uno::Sequence
<beans::PropertyValue
> > aArgsVec
;
287 for (const auto& rStream
: rStreams
)
289 uno::Sequence
<beans::PropertyValue
> aArgs
= comphelper::InitPropertySequence(
291 {"InputStream", uno::makeAny(rStream
)}
293 aArgsVec
.push_back(aArgs
);
296 std::vector
< uno::Reference
<graphic::XGraphic
> > aRet
;
298 if (mxGraphicProvider
.is())
299 aRet
= comphelper::sequenceToContainer
< std::vector
< uno::Reference
<graphic::XGraphic
> > >(mxGraphicProvider
->queryGraphics(comphelper::containerToSequence(aArgsVec
)));
304 Reference
< XGraphic
> GraphicHelper::importGraphic( const StreamDataSequence
& rGraphicData
) const
306 Reference
< XGraphic
> xGraphic
;
307 if( rGraphicData
.hasElements() )
309 Reference
< XInputStream
> xInStrm( new ::comphelper::SequenceInputStream( rGraphicData
) );
310 xGraphic
= importGraphic( xInStrm
);
315 void GraphicHelper::importEmbeddedGraphics(const std::vector
<OUString
>& rStreamNames
) const
317 // Don't actually return anything, just fill maEmbeddedGraphics.
319 // Stream names and streams to be imported.
320 std::vector
<OUString
> aMissingStreamNames
;
321 std::vector
< uno::Reference
<io::XInputStream
> > aMissingStreams
;
323 for (const auto& rStreamName
: rStreamNames
)
325 if(rStreamName
.isEmpty())
327 SAL_WARN("oox", "GraphicHelper::importEmbeddedGraphics - empty stream name");
331 EmbeddedGraphicMap::const_iterator aIt
= maEmbeddedGraphics
.find(rStreamName
);
332 if (aIt
== maEmbeddedGraphics
.end())
334 aMissingStreamNames
.push_back(rStreamName
);
335 aMissingStreams
.push_back(mxStorage
->openInputStream(rStreamName
));
339 std::vector
< uno::Reference
<graphic::XGraphic
> > aGraphics
= importGraphics(aMissingStreams
);
341 assert(aGraphics
.size() == aMissingStreamNames
.size());
342 for (size_t i
= 0; i
< aGraphics
.size(); ++i
)
344 if (aGraphics
[i
].is())
345 maEmbeddedGraphics
[aMissingStreamNames
[i
]] = aGraphics
[i
];
349 Reference
< XGraphic
> GraphicHelper::importEmbeddedGraphic( const OUString
& rStreamName
, const WmfExternal
* pExtHeader
) const
351 Reference
< XGraphic
> xGraphic
;
352 OSL_ENSURE( !rStreamName
.isEmpty(), "GraphicHelper::importEmbeddedGraphic - empty stream name" );
353 if( !rStreamName
.isEmpty() )
355 EmbeddedGraphicMap::const_iterator aIt
= maEmbeddedGraphics
.find( rStreamName
);
356 if( aIt
== maEmbeddedGraphics
.end() )
358 // Lazy-loading doesn't work with TIFF or WMF at the moment.
360 if ( (rStreamName
.endsWith(".tiff") || rStreamName
.endsWith(".wmf") ) && !pExtHeader
)
361 pExtHeader
= &aHeader
;
363 xGraphic
= importGraphic(mxStorage
->openInputStream(rStreamName
), pExtHeader
);
365 maEmbeddedGraphics
[ rStreamName
] = xGraphic
;
368 xGraphic
= aIt
->second
;
373 awt::Size
GraphicHelper::getOriginalSize( const Reference
< XGraphic
>& xGraphic
) const
376 PropertySet
aPropSet( xGraphic
);
377 if( aPropSet
.getProperty( aSizeHmm
, PROP_Size100thMM
) && (aSizeHmm
.Width
== 0) && (aSizeHmm
.Height
== 0) ) // MAPMODE_PIXEL used?
379 awt::Size
aSizePixel( 0, 0 );
380 if( aPropSet
.getProperty( aSizePixel
, PROP_SizePixel
) )
381 aSizeHmm
= convertScreenPixelToHmm( aSizePixel
);
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */