LibreOffice Module oox (master) 1
fillproperties.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
21
22#include <iterator>
23
26#include <vcl/graph.hxx>
27#include <vcl/BitmapFilter.hxx>
29
30#include <com/sun/star/beans/XPropertySet.hpp>
31#include <com/sun/star/awt/Gradient.hpp>
32#include <com/sun/star/text/GraphicCrop.hpp>
33#include <com/sun/star/awt/Size.hpp>
34#include <com/sun/star/drawing/BitmapMode.hpp>
35#include <com/sun/star/drawing/ColorMode.hpp>
36#include <com/sun/star/drawing/FillStyle.hpp>
37#include <com/sun/star/drawing/RectanglePoint.hpp>
38#include <com/sun/star/graphic/XGraphicTransformer.hpp>
43#include <oox/token/namespaces.hxx>
44#include <oox/token/properties.hxx>
45#include <oox/token/tokens.hxx>
46#include <osl/diagnose.h>
47#include <sal/log.hxx>
48
49using namespace ::com::sun::star;
50using namespace ::com::sun::star::drawing;
51using namespace ::com::sun::star::graphic;
52
53using ::com::sun::star::uno::Reference;
54using ::com::sun::star::uno::Exception;
55using ::com::sun::star::uno::UNO_QUERY_THROW;
56using ::com::sun::star::geometry::IntegerRectangle2D;
57
58namespace oox::drawingml {
59
60namespace {
61
62Reference< XGraphic > lclCheckAndApplyDuotoneTransform(const BlipFillProperties& aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic,
63 const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
64{
65 if (aBlipProps.maDuotoneColors[0].isUsed() && aBlipProps.maDuotoneColors[1].isUsed())
66 {
67 ::Color nColor1 = aBlipProps.maDuotoneColors[0].getColor( rGraphicHelper, nPhClr );
68 ::Color nColor2 = aBlipProps.maDuotoneColors[1].getColor( rGraphicHelper, nPhClr );
69
70 uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
71 if (xTransformer.is())
72 return xTransformer->applyDuotone(xGraphic, sal_Int32(nColor1), sal_Int32(nColor2));
73 }
74 return xGraphic;
75}
76
77Reference< XGraphic > lclRotateGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, Degree10 nRotation)
78{
79 ::Graphic aGraphic(xGraphic);
80 ::Graphic aReturnGraphic;
81
82 assert (aGraphic.GetType() == GraphicType::Bitmap);
83
84 BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
85 const ::Color& aColor = ::Color(0x00);
86 aBitmapEx.Rotate(nRotation, aColor);
87 aReturnGraphic = ::Graphic(aBitmapEx);
88 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
89
90 return aReturnGraphic.GetXGraphic();
91}
92
93using Quotients = std::tuple<double, double, double, double>;
94Quotients getQuotients(geometry::IntegerRectangle2D aRelRect, double hDiv, double vDiv)
95{
96 return { aRelRect.X1 / hDiv, aRelRect.Y1 / vDiv, aRelRect.X2 / hDiv, aRelRect.Y2 / vDiv };
97}
98
99// ECMA-376 Part 1 20.1.8.55 srcRect (Source Rectangle)
100std::optional<Quotients> CropQuotientsFromSrcRect(geometry::IntegerRectangle2D aSrcRect)
101{
102 aSrcRect.X1 = std::max(aSrcRect.X1, sal_Int32(0));
103 aSrcRect.X2 = std::max(aSrcRect.X2, sal_Int32(0));
104 aSrcRect.Y1 = std::max(aSrcRect.Y1, sal_Int32(0));
105 aSrcRect.Y2 = std::max(aSrcRect.Y2, sal_Int32(0));
106 if (aSrcRect.X1 + aSrcRect.X2 >= 100'000 || aSrcRect.Y1 + aSrcRect.Y2 >= 100'000)
107 return {}; // Cropped everything
108 return getQuotients(aSrcRect, 100'000.0, 100'000.0);
109}
110
111// ECMA-376 Part 1 20.1.8.30 fillRect (Fill Rectangle)
112std::optional<Quotients> CropQuotientsFromFillRect(geometry::IntegerRectangle2D aFillRect)
113{
114 aFillRect.X1 = std::min(aFillRect.X1, sal_Int32(0));
115 aFillRect.X2 = std::min(aFillRect.X2, sal_Int32(0));
116 aFillRect.Y1 = std::min(aFillRect.Y1, sal_Int32(0));
117 aFillRect.Y2 = std::min(aFillRect.Y2, sal_Int32(0));
118 // Negative divisor and negative relative offset give positive value wanted in lclCropGraphic
119 return getQuotients(aFillRect, -100'000.0 + aFillRect.X1 + aFillRect.X2,
120 -100'000.0 + aFillRect.Y1 + aFillRect.Y2);
121}
122
123// Crops a piece of the bitmap. lclCropGraphic doesn't handle growing.
124Reference<XGraphic> lclCropGraphic(uno::Reference<graphic::XGraphic> const& xGraphic,
125 std::optional<Quotients> quotients)
126{
127 ::Graphic aGraphic(xGraphic);
128 assert (aGraphic.GetType() == GraphicType::Bitmap);
129
130 BitmapEx aBitmapEx;
131 if (quotients)
132 {
133 aBitmapEx = aGraphic.GetBitmapEx();
134
135 const Size bmpSize = aBitmapEx.GetSizePixel();
136 const auto& [qx1, qy1, qx2, qy2] = *quotients;
137 const tools::Long l = std::round(bmpSize.Width() * qx1);
138 const tools::Long t = std::round(bmpSize.Height() * qy1);
139 const tools::Long r = std::round(bmpSize.Width() * qx2);
140 const tools::Long b = std::round(bmpSize.Height() * qy2);
141
142 aBitmapEx.Crop({ l, t, bmpSize.Width() - r - 1, bmpSize.Height() - b - 1 });
143 }
144
145 ::Graphic aReturnGraphic(aBitmapEx);
146 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
147
148 return aReturnGraphic.GetXGraphic();
149}
150
151Reference< XGraphic > lclMirrorGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, bool bFlipH, bool bFlipV)
152{
153 ::Graphic aGraphic(xGraphic);
154 ::Graphic aReturnGraphic;
155
156 assert (aGraphic.GetType() == GraphicType::Bitmap);
157
158 BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
159 BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
160
161 if(bFlipH)
162 nMirrorFlags |= BmpMirrorFlags::Horizontal;
163 if(bFlipV)
164 nMirrorFlags |= BmpMirrorFlags::Vertical;
165
166 aBitmapEx.Mirror(nMirrorFlags);
167
168 aReturnGraphic = ::Graphic(aBitmapEx);
169 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
170
171 return aReturnGraphic.GetXGraphic();
172}
173
174Reference< XGraphic > lclGreysScaleGraphic(uno::Reference<graphic::XGraphic> const & xGraphic)
175{
176 ::Graphic aGraphic(xGraphic);
177 ::Graphic aReturnGraphic;
178
179 assert (aGraphic.GetType() == GraphicType::Bitmap);
180
181 BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
182 aBitmapEx.Convert(BmpConversion::N8BitGreys);
183
184 aReturnGraphic = ::Graphic(aBitmapEx);
185 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
186
187 return aReturnGraphic.GetXGraphic();
188}
189
191Reference<XGraphic> lclApplyBlackWhiteEffect(const BlipFillProperties& aBlipProps,
192 const uno::Reference<graphic::XGraphic>& xGraphic)
193{
194 const auto& oBiLevelThreshold = aBlipProps.moBiLevelThreshold;
195 if (oBiLevelThreshold.has_value())
196 {
197 sal_uInt8 nThreshold
198 = static_cast<sal_uInt8>(oBiLevelThreshold.value() * 255 / MAX_PERCENT);
199
200 ::Graphic aGraphic(xGraphic);
201 ::Graphic aReturnGraphic;
202
203 BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
204 AlphaMask aMask(aBitmapEx.GetAlpha());
205
206 BitmapEx aTmpBmpEx(aBitmapEx.GetBitmap());
207 BitmapFilter::Filter(aTmpBmpEx, BitmapMonochromeFilter{ nThreshold });
208
209 aReturnGraphic = ::Graphic(BitmapEx(aTmpBmpEx.GetBitmap(), aMask));
210 aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
211 return aReturnGraphic.GetXGraphic();
212 }
213 return xGraphic;
214}
215
216Reference< XGraphic > lclCheckAndApplyChangeColorTransform(const BlipFillProperties &aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic,
217 const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
218{
219 if( aBlipProps.maColorChangeFrom.isUsed() && aBlipProps.maColorChangeTo.isUsed() )
220 {
221 ::Color nFromColor = aBlipProps.maColorChangeFrom.getColor( rGraphicHelper, nPhClr );
222 ::Color nToColor = aBlipProps.maColorChangeTo.getColor( rGraphicHelper, nPhClr );
223 if ( (nFromColor != nToColor) || aBlipProps.maColorChangeTo.hasTransparency() )
224 {
225 sal_Int16 nToTransparence = aBlipProps.maColorChangeTo.getTransparency();
226 sal_Int8 nToAlpha = static_cast< sal_Int8 >( (100 - nToTransparence) * 2.55 );
227
228 sal_uInt8 nTolerance = 9;
229 Graphic aGraphic{ xGraphic };
230 if( aGraphic.IsGfxLink() )
231 {
232 // tdf#149670: Try to guess tolerance depending on image format
233 switch (aGraphic.GetGfxLink().GetType())
234 {
235 case GfxLinkType::NativeJpg:
236 nTolerance = 15;
237 break;
238 case GfxLinkType::NativePng:
239 case GfxLinkType::NativeTif:
240 nTolerance = 1;
241 break;
242 case GfxLinkType::NativeBmp:
243 nTolerance = 0;
244 break;
245 default:
246 break;
247 }
248 }
249
250 uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
251 if (xTransformer.is())
252 return xTransformer->colorChange(xGraphic, sal_Int32(nFromColor), nTolerance, sal_Int32(nToColor), nToAlpha);
253 }
254 }
255 return xGraphic;
256}
257
258uno::Reference<graphic::XGraphic> applyBrightnessContrast(uno::Reference<graphic::XGraphic> const & xGraphic, sal_Int32 brightness, sal_Int32 contrast)
259{
260 uno::Reference<graphic::XGraphicTransformer> xTransformer(xGraphic, uno::UNO_QUERY);
261 if (xTransformer.is())
262 return xTransformer->applyBrightnessContrast(xGraphic, brightness, contrast, true);
263 return xGraphic;
264}
265
266BitmapMode lclGetBitmapMode( sal_Int32 nToken )
267{
268 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
269 switch( nToken )
270 {
271 case XML_tile: return BitmapMode_REPEAT;
272 case XML_stretch: return BitmapMode_STRETCH;
273 }
274
275 // tdf#128596 Default value is XML_tile for MSO.
276 return BitmapMode_REPEAT;
277}
278
279RectanglePoint lclGetRectanglePoint( sal_Int32 nToken )
280{
281 OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
282 switch( nToken )
283 {
284 case XML_tl: return RectanglePoint_LEFT_TOP;
285 case XML_t: return RectanglePoint_MIDDLE_TOP;
286 case XML_tr: return RectanglePoint_RIGHT_TOP;
287 case XML_l: return RectanglePoint_LEFT_MIDDLE;
288 case XML_ctr: return RectanglePoint_MIDDLE_MIDDLE;
289 case XML_r: return RectanglePoint_RIGHT_MIDDLE;
290 case XML_bl: return RectanglePoint_LEFT_BOTTOM;
291 case XML_b: return RectanglePoint_MIDDLE_BOTTOM;
292 case XML_br: return RectanglePoint_RIGHT_BOTTOM;
293 }
294 return RectanglePoint_LEFT_TOP;
295}
296
297awt::Size lclGetOriginalSize( const GraphicHelper& rGraphicHelper, const Reference< XGraphic >& rxGraphic )
298{
299 awt::Size aSizeHmm( 0, 0 );
300 try
301 {
302 Reference< beans::XPropertySet > xGraphicPropertySet( rxGraphic, UNO_QUERY_THROW );
303 if( xGraphicPropertySet->getPropertyValue( "Size100thMM" ) >>= aSizeHmm )
304 {
305 if( !aSizeHmm.Width && !aSizeHmm.Height )
306 { // MAPMODE_PIXEL USED :-(
307 awt::Size aSourceSizePixel( 0, 0 );
308 if( xGraphicPropertySet->getPropertyValue( "SizePixel" ) >>= aSourceSizePixel )
309 aSizeHmm = rGraphicHelper.convertScreenPixelToHmm( aSourceSizePixel );
310 }
311 }
312 }
313 catch( Exception& )
314 {
315 }
316 return aSizeHmm;
317}
318
323void extractGradientBorderFromStops(const GradientFillProperties& rGradientProps,
324 const GraphicHelper& rGraphicHelper, ::Color nPhClr,
325 awt::Gradient& rGradient)
326{
327 if (rGradientProps.maGradientStops.size() <= 1)
328 return;
329
330 auto it = rGradientProps.maGradientStops.rbegin();
331 double fLastPos = it->first;
332 Color aLastColor = it->second;
333 ++it;
334 double fLastButOnePos = it->first;
335 Color aLastButOneColor = it->second;
336 if (!aLastColor.equals(aLastButOneColor, rGraphicHelper, nPhClr))
337 return;
338
339 // Last transition has the same color, we can map that to a border.
340 rGradient.Border = rtl::math::round((fLastPos - fLastButOnePos) * 100);
341}
342
343} // namespace
344
346{
347 if( !rSourceProps.maGradientStops.empty() )
348 maGradientStops = rSourceProps.maGradientStops;
349 assignIfUsed( moFillToRect, rSourceProps.moFillToRect );
350 assignIfUsed( moTileRect, rSourceProps.moTileRect );
352 assignIfUsed( moShadeAngle, rSourceProps.moShadeAngle );
353 assignIfUsed( moShadeFlip, rSourceProps.moShadeFlip );
356}
357
359{
362 assignIfUsed( moPattPreset, rSourceProps.moPattPreset );
363}
364
366{
367 if(rSourceProps.mxFillGraphic.is())
368 mxFillGraphic = rSourceProps.mxFillGraphic;
369 assignIfUsed( moBitmapMode, rSourceProps.moBitmapMode );
370 assignIfUsed( moFillRect, rSourceProps.moFillRect );
373 assignIfUsed( moTileScaleX, rSourceProps.moTileScaleX );
374 assignIfUsed( moTileScaleY, rSourceProps.moTileScaleY );
375 assignIfUsed( moTileAlign, rSourceProps.moTileAlign );
376 assignIfUsed( moTileFlip, rSourceProps.moTileFlip );
379 assignIfUsed( moBrightness, rSourceProps.moBrightness );
380 assignIfUsed( moContrast, rSourceProps.moContrast );
384 maDuotoneColors[0].assignIfUsed( rSourceProps.maDuotoneColors[0] );
385 maDuotoneColors[1].assignIfUsed( rSourceProps.maDuotoneColors[1] );
386 maEffect.assignUsed( rSourceProps.maEffect );
388}
389
391{
392 assignIfUsed( moFillType, rSourceProps.moFillType );
393 maFillColor.assignIfUsed( rSourceProps.maFillColor );
394 assignIfUsed( moUseBgFill, rSourceProps.moUseBgFill );
397 maBlipProps.assignUsed( rSourceProps.maBlipProps );
398}
399
401{
402 Color aSolidColor;
403 if( moFillType.has_value() ) switch( moFillType.value() )
404 {
405 case XML_solidFill:
406 aSolidColor = maFillColor;
407 break;
408 case XML_gradFill:
409 if( !maGradientProps.maGradientStops.empty() )
410 {
411 GradientFillProperties::GradientStopMap::const_iterator aGradientStop =
413 if (maGradientProps.maGradientStops.size() > 2)
414 ++aGradientStop;
415 aSolidColor = aGradientStop->second;
416 }
417 break;
418 case XML_pattFill:
420 break;
421 }
422 return aSolidColor;
423}
424
426 const GraphicHelper& rGraphicHelper, sal_Int32 nShapeRotation, ::Color nPhClr, sal_Int16 nPhClrTheme,
427 bool bFlipH, bool bFlipV, bool bIsCustomShape) const
428{
429 if( !moFillType.has_value() )
430 return;
431
432 FillStyle eFillStyle = FillStyle_NONE;
433 OSL_ASSERT((moFillType.value() & sal_Int32(0xFFFF0000))==0);
434 switch( moFillType.value() )
435 {
436 case XML_noFill:
437 {
438 eFillStyle = FillStyle_NONE;
440 }
441 break;
442
443 case XML_solidFill:
444 if( maFillColor.isUsed() )
445 {
446 ::Color aFillColor = maFillColor.getColor(rGraphicHelper, nPhClr);
447 rPropMap.setProperty(ShapeProperty::FillColor, aFillColor);
450
451 if (aFillColor == nPhClr)
452 {
453 rPropMap.setProperty(PROP_FillColorTheme, nPhClrTheme);
454 }
455 else if (maFillColor.getTintOrShade() == 0)
456 {
460 }
461
462 eFillStyle = FillStyle_SOLID;
463 }
464 break;
465
466 case XML_gradFill:
467 // do not create gradient struct if property is not supported...
469 {
470 sal_Int32 nEndTrans = 0;
471 sal_Int32 nStartTrans = 0;
472 awt::Gradient aGradient;
473 aGradient.Angle = 900;
474 aGradient.StartIntensity = 100;
475 aGradient.EndIntensity = 100;
476
477 // Old code, values in aGradient overwritten in many cases by newer code below
478 if( maGradientProps.maGradientStops.size() > 1 )
479 {
480 aGradient.StartColor = sal_Int32(maGradientProps.maGradientStops.begin()->second.getColor( rGraphicHelper, nPhClr ));
481 aGradient.EndColor = sal_Int32(maGradientProps.maGradientStops.rbegin()->second.getColor( rGraphicHelper, nPhClr ));
482 if( maGradientProps.maGradientStops.rbegin()->second.hasTransparency() )
483 nEndTrans = maGradientProps.maGradientStops.rbegin()->second.getTransparency()*255/100;
484 if( maGradientProps.maGradientStops.begin()->second.hasTransparency() )
485 nStartTrans = maGradientProps.maGradientStops.begin()->second.getTransparency()*255/100;
486 }
487
488 // "rotate with shape" set to false -> do not rotate
489 if ( !maGradientProps.moRotateWithShape.value_or( true ) )
490 nShapeRotation = 0;
491
492 if( maGradientProps.moGradientPath.has_value() )
493 {
494 IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.value_or( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) );
495 sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2;
496 aGradient.XOffset = getLimitedValue<sal_Int16, sal_Int32>(
497 nCenterX / PER_PERCENT, 0, 100);
498 sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2;
499 aGradient.YOffset = getLimitedValue<sal_Int16, sal_Int32>(
500 nCenterY / PER_PERCENT, 0, 100);
501
502 if( maGradientProps.moGradientPath.value() == XML_circle )
503 {
504 // Style should be radial at least when the horizontal center is at 50%.
505 // Otherwise import as a linear gradient, because it is the most similar to the MSO radial style.
506 aGradient.Style = awt::GradientStyle_LINEAR;
507 if( aGradient.XOffset == 100 && aGradient.YOffset == 100 )
508 aGradient.Angle = 450;
509 else if( aGradient.XOffset == 0 && aGradient.YOffset == 100 )
510 aGradient.Angle = 3150;
511 else if( aGradient.XOffset == 100 && aGradient.YOffset == 0 )
512 aGradient.Angle = 1350;
513 else if( aGradient.XOffset == 0 && aGradient.YOffset == 0 )
514 aGradient.Angle = 2250;
515 else
516 aGradient.Style = awt::GradientStyle_RADIAL;
517 }
518 else
519 {
520 aGradient.Style = awt::GradientStyle_RECT;
521 }
522
523 ::std::swap( aGradient.StartColor, aGradient.EndColor );
524 ::std::swap( nStartTrans, nEndTrans );
525
526 extractGradientBorderFromStops(maGradientProps, rGraphicHelper, nPhClr,
527 aGradient);
528 }
529 else if (!maGradientProps.maGradientStops.empty())
530 {
531 // A copy of the gradient stops for local modification
533
534 // Add a fake gradient stop at 0% and 100% if necessary, so that the gradient always starts
535 // at 0% and ends at 100%, to make following logic clearer (?).
536 auto a0 = aGradientStops.find( 0.0 );
537 if( a0 == aGradientStops.end() )
538 {
539 // temp variable required
540 Color aFirstColor(aGradientStops.begin()->second);
541 aGradientStops.emplace( 0.0, aFirstColor );
542 }
543
544 auto a1 = aGradientStops.find( 1.0 );
545 if( a1 == aGradientStops.end() )
546 {
547 // ditto
548 Color aLastColor(aGradientStops.rbegin()->second);
549 aGradientStops.emplace( 1.0, aLastColor );
550 }
551
552 // Check if the gradient is symmetric, which we will emulate with an "axial" gradient.
553 bool bSymmetric(true);
554 {
555 GradientFillProperties::GradientStopMap::const_iterator aItA( aGradientStops.begin() );
556 GradientFillProperties::GradientStopMap::const_iterator aItZ(std::prev(aGradientStops.end()));
557 assert(aItZ != aGradientStops.end());
558 while( bSymmetric && aItA->first < aItZ->first )
559 {
560 if (!aItA->second.equals(aItZ->second, rGraphicHelper, nPhClr))
561 bSymmetric = false;
562 else
563 {
564 ++aItA;
565 aItZ = std::prev(aItZ);
566 }
567 }
568 // Don't be fooled if the middlemost stop isn't at 0.5.
569 if( bSymmetric && aItA == aItZ && aItA->first != 0.5 )
570 bSymmetric = false;
571
572 // If symmetric, do the rest of the logic for just a half.
573 if( bSymmetric )
574 {
575 // aItZ already points to the colour for the middle, but insert a fake stop at the
576 // exact middle if necessary.
577 if( aItA->first != aItZ->first )
578 {
579 Color aMiddleColor = aItZ->second;
580 auto a05 = aGradientStops.find( 0.5 );
581
582 if( a05 != aGradientStops.end() )
583 a05->second = aMiddleColor;
584 else
585 aGradientStops.emplace( 0.5, aMiddleColor );
586 }
587 // Drop the rest of the stops
588 while( aGradientStops.rbegin()->first > 0.5 )
589 aGradientStops.erase( aGradientStops.rbegin()->first );
590 }
591 }
592
593 SAL_INFO("oox.drawingml.gradient", "symmetric: " << (bSymmetric ? "YES" : "NO") <<
594 ", number of stops: " << aGradientStops.size());
595 size_t nIndex = 0;
596 for (auto const& gradientStop : aGradientStops)
597 SAL_INFO("oox.drawingml.gradient", " " << nIndex++ << ": " <<
598 gradientStop.first << ": " <<
599 std::hex << sal_Int32(gradientStop.second.getColor( rGraphicHelper, nPhClr )) << std::dec <<
600 "@" << (100 - gradientStop.second.getTransparency()) << "%");
601
602 // Now estimate the simple LO style gradient (only two stops, at n% and 100%, where n ==
603 // the "border") that best emulates the gradient between begin() and prior(end()).
604
605 // First look for the largest segment in the gradient.
606 GradientFillProperties::GradientStopMap::iterator aIt(aGradientStops.begin());
607 double nWidestWidth = -1;
608 GradientFillProperties::GradientStopMap::iterator aWidestSegmentStart;
609 ++aIt;
610 while( aIt != aGradientStops.end() )
611 {
612 if (aIt->first - std::prev(aIt)->first > nWidestWidth)
613 {
614 nWidestWidth = aIt->first - std::prev(aIt)->first;
615 aWidestSegmentStart = std::prev(aIt);
616 }
617 ++aIt;
618 }
619 assert( nWidestWidth > 0 );
620
621 double nBorder = 0;
622 bool bSwap(false);
623
624 // Do we have just two segments, and either one is of uniform colour, or three or more
625 // segments, and the widest one is the first or last one, and is it of uniform colour? If
626 // so, deduce the border from it, and drop that segment.
627 if( aGradientStops.size() == 3 &&
628 aGradientStops.begin()->second.getColor(rGraphicHelper, nPhClr) == std::next(aGradientStops.begin())->second.getColor(rGraphicHelper, nPhClr) &&
629 aGradientStops.begin()->second.getTransparency() == std::next(aGradientStops.begin())->second.getTransparency())
630 {
631 // Two segments, first is uniformly coloured
632 SAL_INFO("oox.drawingml.gradient", "two segments, first is uniformly coloured");
633 nBorder = std::next(aGradientStops.begin())->first - aGradientStops.begin()->first;
634 aGradientStops.erase(aGradientStops.begin());
635 aWidestSegmentStart = aGradientStops.begin();
636 }
637 else if( !bSymmetric &&
638 aGradientStops.size() == 3 &&
639 std::next(aGradientStops.begin())->second.getColor(rGraphicHelper, nPhClr) == std::prev(aGradientStops.end())->second.getColor(rGraphicHelper, nPhClr) &&
640 std::next(aGradientStops.begin())->second.getTransparency() == std::prev(aGradientStops.end())->second.getTransparency())
641 {
642 // Two segments, second is uniformly coloured
643 SAL_INFO("oox.drawingml.gradient", "two segments, second is uniformly coloured");
644 auto aNext = std::next(aGradientStops.begin());
645 auto aPrev = std::prev(aGradientStops.end());
646 assert(aPrev != aGradientStops.end());
647 nBorder = aPrev->first - aNext->first;
648 aGradientStops.erase(aNext);
649 aWidestSegmentStart = aGradientStops.begin();
650 bSwap = true;
651 nShapeRotation = 180*60000 - nShapeRotation;
652 }
653 else if( !bSymmetric &&
654 aGradientStops.size() >= 4 &&
655 aWidestSegmentStart->second.getColor( rGraphicHelper, nPhClr ) == std::next(aWidestSegmentStart)->second.getColor(rGraphicHelper, nPhClr) &&
656 aWidestSegmentStart->second.getTransparency() == std::next(aWidestSegmentStart)->second.getTransparency() &&
657 ( aWidestSegmentStart == aGradientStops.begin() ||
658 std::next(aWidestSegmentStart) == std::prev(aGradientStops.end())))
659 {
660 // Not symmetric, three or more segments, the widest is first or last and is uniformly coloured
661 SAL_INFO("oox.drawingml.gradient", "first or last segment is widest and is uniformly coloured");
662 nBorder = std::next(aWidestSegmentStart)->first - aWidestSegmentStart->first;
663
664 // If it's the last segment that is uniformly coloured, rotate the gradient 180
665 // degrees and swap start and end colours
666 if (std::next(aWidestSegmentStart) == std::prev(aGradientStops.end()))
667 {
668 bSwap = true;
669 nShapeRotation = 180*60000 - nShapeRotation;
670 }
671
672 aGradientStops.erase( aWidestSegmentStart++ );
673
674 // Look for which is widest now
675 aIt = std::next(aGradientStops.begin());
676 nWidestWidth = -1;
677 while( aIt != aGradientStops.end() )
678 {
679 if (aIt->first - std::prev(aIt)->first > nWidestWidth)
680 {
681 nWidestWidth = aIt->first - std::prev(aIt)->first;
682 aWidestSegmentStart = std::prev(aIt);
683 }
684 ++aIt;
685 }
686 }
687 SAL_INFO("oox.drawingml.gradient", "widest segment start: " << aWidestSegmentStart->first << ", border: " << nBorder);
688 assert( (!bSymmetric && !bSwap) || !(bSymmetric && bSwap) );
689
690 // Now we have a potential border and a largest segment. Use those.
691
692 aGradient.Style = bSymmetric ? awt::GradientStyle_AXIAL : awt::GradientStyle_LINEAR;
693 sal_Int32 nShadeAngle = maGradientProps.moShadeAngle.value_or( 0 );
694 // Adjust for flips
695 if ( bFlipH )
696 nShadeAngle = 180*60000 - nShadeAngle;
697 if ( bFlipV )
698 nShadeAngle = -nShadeAngle;
699 sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation;
700 // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees)
701 aGradient.Angle = static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 );
702 Color aStartColor, aEndColor;
703
704 // Make a note where the widest segment stops, because we will try to grow it next.
705 auto aWidestSegmentEnd = std::next(aWidestSegmentStart);
706
707 // Try to grow the widest segment backwards: if a previous segment has the same
708 // color, just different transparency, include it.
709 while (aWidestSegmentStart != aGradientStops.begin())
710 {
711 auto it = std::prev(aWidestSegmentStart);
712 if (it->second.getColor(rGraphicHelper, nPhClr)
713 != aWidestSegmentStart->second.getColor(rGraphicHelper, nPhClr))
714 {
715 break;
716 }
717
718 aWidestSegmentStart = it;
719 }
720
721 // Try to grow the widest segment forward: if a next segment has the same
722 // color, just different transparency, include it.
723 while (aWidestSegmentEnd != std::prev(aGradientStops.end()))
724 {
725 auto it = std::next(aWidestSegmentEnd);
726 if (it->second.getColor(rGraphicHelper, nPhClr)
727 != aWidestSegmentEnd->second.getColor(rGraphicHelper, nPhClr))
728 {
729 break;
730 }
731
732 aWidestSegmentEnd = it;
733 }
734
735 assert(aWidestSegmentEnd != aGradientStops.end());
736
737 if( bSymmetric )
738 {
739 aStartColor = aWidestSegmentEnd->second;
740 aEndColor = aWidestSegmentStart->second;
741 nBorder *= 2;
742 }
743 else if( bSwap )
744 {
745 aStartColor = aWidestSegmentEnd->second;
746 aEndColor = aWidestSegmentStart->second;
747 }
748 else
749 {
750 aStartColor = aWidestSegmentStart->second;
751 aEndColor = aWidestSegmentEnd->second;
752 }
753
754 SAL_INFO("oox.drawingml.gradient", "start color: " << std::hex << sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr )) << std::dec <<
755 "@" << (100-aStartColor.getTransparency()) << "%"
756 ", end color: " << std::hex << sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr )) << std::dec <<
757 "@" << (100-aEndColor.getTransparency()) << "%");
758
759 aGradient.StartColor = sal_Int32(aStartColor.getColor( rGraphicHelper, nPhClr ));
760 aGradient.EndColor = sal_Int32(aEndColor.getColor( rGraphicHelper, nPhClr ));
761
762 nStartTrans = aStartColor.hasTransparency() ? aStartColor.getTransparency()*255/100 : 0;
763 nEndTrans = aEndColor.hasTransparency() ? aEndColor.getTransparency()*255/100 : 0;
764
765 aGradient.Border = rtl::math::round(100*nBorder);
766 }
767
768 // push gradient or named gradient to property map
769 if( rPropMap.setProperty( ShapeProperty::FillGradient, aGradient ) )
770 eFillStyle = FillStyle_GRADIENT;
771
772 // push gradient transparency to property map
773 if( nStartTrans != 0 || nEndTrans != 0 )
774 {
775 awt::Gradient aGrad(aGradient);
776 uno::Any aVal;
777 aGrad.EndColor = static_cast<sal_Int32>( nEndTrans | nEndTrans << 8 | nEndTrans << 16 );
778 aGrad.StartColor = static_cast<sal_Int32>( nStartTrans | nStartTrans << 8 | nStartTrans << 16 );
779 aVal <<= aGrad;
781 }
782
783 }
784 break;
785
786 case XML_blipFill:
787 // do not start complex graphic transformation if property is not supported...
789 {
790 uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, nPhClr);
791 // TODO: "rotate with shape" is not possible with our current core
792
793 if (xGraphic.is())
794 {
795 if (maBlipProps.moColorEffect.value_or(XML_TOKEN_INVALID) == XML_grayscl)
796 xGraphic = lclGreysScaleGraphic(xGraphic);
797
799 rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic))
800 {
801 eFillStyle = FillStyle_BITMAP;
802 }
803 else if (rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic))
804 {
805 eFillStyle = FillStyle_BITMAP;
806 }
807 }
808
809 // set other bitmap properties, if bitmap has been inserted into the map
810 if( eFillStyle == FillStyle_BITMAP )
811 {
812 // bitmap mode (single, repeat, stretch)
813 BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.value_or( XML_TOKEN_INVALID ) );
814 rPropMap.setProperty( ShapeProperty::FillBitmapMode, eBitmapMode );
815
816 // additional settings for repeated bitmap
817 if( eBitmapMode == BitmapMode_REPEAT )
818 {
819 // anchor position inside bitmap
820 RectanglePoint eRectPoint = lclGetRectanglePoint( maBlipProps.moTileAlign.value_or( XML_tl ) );
822
823 awt::Size aOriginalSize = lclGetOriginalSize(rGraphicHelper, maBlipProps.mxFillGraphic);
824 if( (aOriginalSize.Width > 0) && (aOriginalSize.Height > 0) )
825 {
826 // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm
827 double fScaleX = maBlipProps.moTileScaleX.value_or( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
828 sal_Int32 nFillBmpSizeX = getLimitedValue< sal_Int32, double >( aOriginalSize.Width * fScaleX, 1, SAL_MAX_INT32 );
829 rPropMap.setProperty( ShapeProperty::FillBitmapSizeX, nFillBmpSizeX );
830 double fScaleY = maBlipProps.moTileScaleY.value_or( MAX_PERCENT ) / static_cast< double >( MAX_PERCENT );
831 sal_Int32 nFillBmpSizeY = getLimitedValue< sal_Int32, double >( aOriginalSize.Height * fScaleY, 1, SAL_MAX_INT32 );
832 rPropMap.setProperty( ShapeProperty::FillBitmapSizeY, nFillBmpSizeY );
833
834 // offset of the first bitmap tile (given as EMUs), convert to percent
835 sal_Int16 nTileOffsetX = getDoubleIntervalValue< sal_Int16 >( maBlipProps.moTileOffsetX.value_or( 0 ) / 3.6 / aOriginalSize.Width, 0, 100 );
836 rPropMap.setProperty( ShapeProperty::FillBitmapOffsetX, nTileOffsetX );
837 sal_Int16 nTileOffsetY = getDoubleIntervalValue< sal_Int16 >( maBlipProps.moTileOffsetY.value_or( 0 ) / 3.6 / aOriginalSize.Height, 0, 100 );
838 rPropMap.setProperty( ShapeProperty::FillBitmapOffsetY, nTileOffsetY );
839 }
840 }
841 else if ( eBitmapMode == BitmapMode_STRETCH && maBlipProps.moFillRect.has_value() )
842 {
843 geometry::IntegerRectangle2D aFillRect( maBlipProps.moFillRect.value() );
844 awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );
845 if ( aOriginalSize.Width && aOriginalSize.Height )
846 {
847 text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
848 if ( aFillRect.X1 )
849 aGraphCrop.Left = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Width ) * aFillRect.X1 ) / 100000 );
850 if ( aFillRect.Y1 )
851 aGraphCrop.Top = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Height ) * aFillRect.Y1 ) / 100000 );
852 if ( aFillRect.X2 )
853 aGraphCrop.Right = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Width ) * aFillRect.X2 ) / 100000 );
854 if ( aFillRect.Y2 )
855 aGraphCrop.Bottom = static_cast< sal_Int32 >( ( static_cast< double >( aOriginalSize.Height ) * aFillRect.Y2 ) / 100000 );
856 rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);
857
858 bool bHasCropValues = aGraphCrop.Left != 0 || aGraphCrop.Right !=0 || aGraphCrop.Top != 0 || aGraphCrop.Bottom != 0;
859 // Negative GraphicCrop values means "crop" here.
860 bool bNeedCrop = aGraphCrop.Left <= 0 && aGraphCrop.Right <= 0 && aGraphCrop.Top <= 0 && aGraphCrop.Bottom <= 0;
861
862 if(bIsCustomShape && bHasCropValues && bNeedCrop)
863 {
864 xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromFillRect(aFillRect));
866 rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic);
867 else
868 rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic);
869 }
870 }
871 }
872 }
873
874 if (maBlipProps.moAlphaModFix.has_value())
875 rPropMap.setProperty(ShapeProperty::FillTransparency, static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
876 }
877 break;
878
879 case XML_pattFill:
880 {
882 {
884 if( aColor.isUsed() && maPatternProps.moPattPreset.has_value() )
885 {
886 eFillStyle = FillStyle_HATCH;
887 rPropMap.setProperty( ShapeProperty::FillHatch, createHatch( maPatternProps.moPattPreset.value(), aColor.getColor( rGraphicHelper, nPhClr ) ) );
888 if( aColor.hasTransparency() )
890
891 // Set background color for hatch
893 {
895 rPropMap.setProperty( ShapeProperty::FillBackground, aColor.getTransparency() != 100 );
896 rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
897 }
898 }
900 {
902 rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
903 if( aColor.hasTransparency() )
905 eFillStyle = FillStyle_SOLID;
906 }
907 }
908 }
909 break;
910
911 case XML_grpFill:
912 // todo
913 eFillStyle = FillStyle_NONE;
914 break;
915 }
916
917 // set final fill style property
918 rPropMap.setProperty( ShapeProperty::FillStyle, eFillStyle );
919}
920
921void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelper& rGraphicHelper, bool bFlipH, bool bFlipV) const
922{
923 sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.value_or( 0 ) / PER_PERCENT, -100, 100 );
924 sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.value_or( 0 ) / PER_PERCENT, -100, 100 );
925 ColorMode eColorMode = ColorMode_STANDARD;
926
927 switch( maBlipProps.moColorEffect.value_or( XML_TOKEN_INVALID ) )
928 {
929 case XML_biLevel: eColorMode = ColorMode_MONO; break;
930 case XML_grayscl: eColorMode = ColorMode_GREYS; break;
931 }
932
933 if (maBlipProps.mxFillGraphic.is())
934 {
935 // created transformed graphic
936 uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyChangeColorTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, API_RGB_TRANSPARENT);
937 xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, xGraphic, rGraphicHelper, API_RGB_TRANSPARENT);
938
939 if( eColorMode == ColorMode_MONO )
940 {
941 // ColorMode_MONO is the same with MSO's biLevel with 50000 (50%) threshold,
942 // when threshold isn't 50000 bake the effect instead.
943 if( maBlipProps.moBiLevelThreshold != 50000 )
944 {
945 xGraphic = lclApplyBlackWhiteEffect(maBlipProps, xGraphic);
946 eColorMode = ColorMode_STANDARD;
947 }
948 }
949
950 if (eColorMode == ColorMode_STANDARD && nBrightness == 70 && nContrast == -70)
951 {
952 // map MSO 'washout' to our Watermark colormode
953 eColorMode = ColorMode_WATERMARK;
954 nBrightness = 0;
955 nContrast = 0;
956 }
957 else if( nBrightness != 0 && nContrast != 0 )
958 {
959 // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
960 // while MSO apparently applies half of brightness before contrast and half after. So if only
961 // contrast or brightness need to be altered, the result is the same, but if both are involved,
962 // there's no way to map that, so just force a conversion of the image.
963 xGraphic = applyBrightnessContrast( xGraphic, nBrightness, nContrast );
964 nBrightness = 0;
965 nContrast = 0;
966 }
967
968 // cropping
969 if ( maBlipProps.moClipRect.has_value() )
970 {
971 geometry::IntegerRectangle2D oClipRect( maBlipProps.moClipRect.value() );
972 awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );
973 if ( aOriginalSize.Width && aOriginalSize.Height )
974 {
975 text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
976 if ( oClipRect.X1 )
977 aGraphCrop.Left = rtl::math::round( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X1 ) / 100000 );
978 if ( oClipRect.Y1 )
979 aGraphCrop.Top = rtl::math::round( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y1 ) / 100000 );
980 if ( oClipRect.X2 )
981 aGraphCrop.Right = rtl::math::round( ( static_cast< double >( aOriginalSize.Width ) * oClipRect.X2 ) / 100000 );
982 if ( oClipRect.Y2 )
983 aGraphCrop.Bottom = rtl::math::round( ( static_cast< double >( aOriginalSize.Height ) * oClipRect.Y2 ) / 100000 );
984 rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);
985
986 bool bHasCropValues = aGraphCrop.Left != 0 || aGraphCrop.Right !=0 || aGraphCrop.Top != 0 || aGraphCrop.Bottom != 0;
987 // Positive GraphicCrop values means "crop" here.
988 bool bNeedCrop = aGraphCrop.Left >= 0 && aGraphCrop.Right >= 0 && aGraphCrop.Top >= 0 && aGraphCrop.Bottom >= 0;
989
990 if(mbIsCustomShape && bHasCropValues && bNeedCrop)
991 {
992 xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromSrcRect(oClipRect));
993 }
994 }
995 }
996
998 {
999 // it is a cropped graphic.
1000 rPropMap.setProperty(PROP_FillStyle, FillStyle_BITMAP);
1001 rPropMap.setProperty(PROP_FillBitmapMode, BitmapMode_STRETCH);
1002
1003 // It is a bitmap filled and rotated graphic.
1004 // When custom shape is rotated, bitmap have to be rotated too.
1005 if(rPropMap.hasProperty(PROP_RotateAngle))
1006 {
1007 tools::Long nAngle = rPropMap.getProperty(PROP_RotateAngle).get<tools::Long>();
1008 xGraphic = lclRotateGraphic(xGraphic, Degree10(nAngle/10) );
1009 }
1010
1011 // We have not core feature that flips graphic in the shape.
1012 // Here we are applying flip property to bitmap directly.
1013 if(bFlipH || bFlipV)
1014 xGraphic = lclMirrorGraphic(xGraphic, bFlipH, bFlipV );
1015
1016 if(eColorMode == ColorMode_GREYS)
1017 xGraphic = lclGreysScaleGraphic( xGraphic );
1018
1019 rPropMap.setProperty(PROP_FillBitmap, xGraphic);
1020 }
1021 else
1022 rPropMap.setProperty(PROP_Graphic, xGraphic);
1023
1024
1025 if ( maBlipProps.moAlphaModFix.has_value() )
1026 {
1027 rPropMap.setProperty(PROP_Transparency, static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
1028 }
1029 }
1030 rPropMap.setProperty(PROP_GraphicColorMode, eColorMode);
1031
1032 // brightness and contrast
1033 if( nBrightness != 0 )
1034 rPropMap.setProperty(PROP_AdjustLuminance, nBrightness);
1035 if( nContrast != 0 )
1036 rPropMap.setProperty(PROP_AdjustContrast, nContrast);
1037
1038 // Media content
1039 if (!m_sMediaPackageURL.isEmpty())
1040 {
1041 rPropMap.setProperty(PROP_MediaURL, m_sMediaPackageURL);
1042 if (m_xMediaStream.is())
1043 rPropMap.setProperty(PROP_PrivateStream, m_xMediaStream);
1044 }
1045}
1046
1048{
1049 return msName.isEmpty();
1050}
1051
1052css::beans::PropertyValue ArtisticEffectProperties::getEffect()
1053{
1054 css::beans::PropertyValue aRet;
1055 if( msName.isEmpty() )
1056 return aRet;
1057
1058 css::uno::Sequence< css::beans::PropertyValue > aSeq( maAttribs.size() + 1 );
1059 auto pSeq = aSeq.getArray();
1060 sal_uInt32 i = 0;
1061 for (auto const& attrib : maAttribs)
1062 {
1063 pSeq[i].Name = attrib.first;
1064 pSeq[i].Value = attrib.second;
1065 i++;
1066 }
1067
1068 if( mrOleObjectInfo.maEmbeddedData.hasElements() )
1069 {
1070 css::uno::Sequence< css::beans::PropertyValue > aGraphicSeq{
1073 };
1074
1075 pSeq[i].Name = "OriginalGraphic";
1076 pSeq[i].Value <<= aGraphicSeq;
1077 }
1078
1079 aRet.Name = msName;
1080 aRet.Value <<= aSeq;
1081
1082 return aRet;
1083}
1084
1086{
1087 if( !rSourceProps.isEmpty() )
1088 {
1089 msName = rSourceProps.msName;
1090 maAttribs = rSourceProps.maAttribs;
1091 }
1092}
1093
1095{
1096 switch( nToken )
1097 {
1098 // effects
1099 case OOX_TOKEN( a14, artisticBlur ): return "artisticBlur";
1100 case OOX_TOKEN( a14, artisticCement ): return "artisticCement";
1101 case OOX_TOKEN( a14, artisticChalkSketch ): return "artisticChalkSketch";
1102 case OOX_TOKEN( a14, artisticCrisscrossEtching ): return "artisticCrisscrossEtching";
1103 case OOX_TOKEN( a14, artisticCutout ): return "artisticCutout";
1104 case OOX_TOKEN( a14, artisticFilmGrain ): return "artisticFilmGrain";
1105 case OOX_TOKEN( a14, artisticGlass ): return "artisticGlass";
1106 case OOX_TOKEN( a14, artisticGlowDiffused ): return "artisticGlowDiffused";
1107 case OOX_TOKEN( a14, artisticGlowEdges ): return "artisticGlowEdges";
1108 case OOX_TOKEN( a14, artisticLightScreen ): return "artisticLightScreen";
1109 case OOX_TOKEN( a14, artisticLineDrawing ): return "artisticLineDrawing";
1110 case OOX_TOKEN( a14, artisticMarker ): return "artisticMarker";
1111 case OOX_TOKEN( a14, artisticMosiaicBubbles ): return "artisticMosiaicBubbles";
1112 case OOX_TOKEN( a14, artisticPaintStrokes ): return "artisticPaintStrokes";
1113 case OOX_TOKEN( a14, artisticPaintBrush ): return "artisticPaintBrush";
1114 case OOX_TOKEN( a14, artisticPastelsSmooth ): return "artisticPastelsSmooth";
1115 case OOX_TOKEN( a14, artisticPencilGrayscale ): return "artisticPencilGrayscale";
1116 case OOX_TOKEN( a14, artisticPencilSketch ): return "artisticPencilSketch";
1117 case OOX_TOKEN( a14, artisticPhotocopy ): return "artisticPhotocopy";
1118 case OOX_TOKEN( a14, artisticPlasticWrap ): return "artisticPlasticWrap";
1119 case OOX_TOKEN( a14, artisticTexturizer ): return "artisticTexturizer";
1120 case OOX_TOKEN( a14, artisticWatercolorSponge ): return "artisticWatercolorSponge";
1121 case OOX_TOKEN( a14, brightnessContrast ): return "brightnessContrast";
1122 case OOX_TOKEN( a14, colorTemperature ): return "colorTemperature";
1123 case OOX_TOKEN( a14, saturation ): return "saturation";
1124 case OOX_TOKEN( a14, sharpenSoften ): return "sharpenSoften";
1125
1126 // attributes
1127 case XML_visible: return "visible";
1128 case XML_trans: return "trans";
1129 case XML_crackSpacing: return "crackSpacing";
1130 case XML_pressure: return "pressure";
1131 case XML_numberOfShades: return "numberOfShades";
1132 case XML_grainSize: return "grainSize";
1133 case XML_intensity: return "intensity";
1134 case XML_smoothness: return "smoothness";
1135 case XML_gridSize: return "gridSize";
1136 case XML_pencilSize: return "pencilSize";
1137 case XML_size: return "size";
1138 case XML_brushSize: return "brushSize";
1139 case XML_scaling: return "scaling";
1140 case XML_detail: return "detail";
1141 case XML_bright: return "bright";
1142 case XML_contrast: return "contrast";
1143 case XML_colorTemp: return "colorTemp";
1144 case XML_sat: return "sat";
1145 case XML_amount: return "amount";
1146 }
1147 SAL_WARN( "oox.drawingml", "ArtisticEffectProperties::getEffectString: unexpected token " << nToken );
1148 return OUString();
1149}
1150
1152{
1153 // effects
1154 if( sName == "artisticBlur" )
1155 return XML_artisticBlur;
1156 else if( sName == "artisticCement" )
1157 return XML_artisticCement;
1158 else if( sName == "artisticChalkSketch" )
1159 return XML_artisticChalkSketch;
1160 else if( sName == "artisticCrisscrossEtching" )
1161 return XML_artisticCrisscrossEtching;
1162 else if( sName == "artisticCutout" )
1163 return XML_artisticCutout;
1164 else if( sName == "artisticFilmGrain" )
1165 return XML_artisticFilmGrain;
1166 else if( sName == "artisticGlass" )
1167 return XML_artisticGlass;
1168 else if( sName == "artisticGlowDiffused" )
1169 return XML_artisticGlowDiffused;
1170 else if( sName == "artisticGlowEdges" )
1171 return XML_artisticGlowEdges;
1172 else if( sName == "artisticLightScreen" )
1173 return XML_artisticLightScreen;
1174 else if( sName == "artisticLineDrawing" )
1175 return XML_artisticLineDrawing;
1176 else if( sName == "artisticMarker" )
1177 return XML_artisticMarker;
1178 else if( sName == "artisticMosiaicBubbles" )
1179 return XML_artisticMosiaicBubbles;
1180 else if( sName == "artisticPaintStrokes" )
1181 return XML_artisticPaintStrokes;
1182 else if( sName == "artisticPaintBrush" )
1183 return XML_artisticPaintBrush;
1184 else if( sName == "artisticPastelsSmooth" )
1185 return XML_artisticPastelsSmooth;
1186 else if( sName == "artisticPencilGrayscale" )
1187 return XML_artisticPencilGrayscale;
1188 else if( sName == "artisticPencilSketch" )
1189 return XML_artisticPencilSketch;
1190 else if( sName == "artisticPhotocopy" )
1191 return XML_artisticPhotocopy;
1192 else if( sName == "artisticPlasticWrap" )
1193 return XML_artisticPlasticWrap;
1194 else if( sName == "artisticTexturizer" )
1195 return XML_artisticTexturizer;
1196 else if( sName == "artisticWatercolorSponge" )
1197 return XML_artisticWatercolorSponge;
1198 else if( sName == "brightnessContrast" )
1199 return XML_brightnessContrast;
1200 else if( sName == "colorTemperature" )
1201 return XML_colorTemperature;
1202 else if( sName == "saturation" )
1203 return XML_saturation;
1204 else if( sName == "sharpenSoften" )
1205 return XML_sharpenSoften;
1206
1207 // attributes
1208 else if( sName == "visible" )
1209 return XML_visible;
1210 else if( sName == "trans" )
1211 return XML_trans;
1212 else if( sName == "crackSpacing" )
1213 return XML_crackSpacing;
1214 else if( sName == "pressure" )
1215 return XML_pressure;
1216 else if( sName == "numberOfShades" )
1217 return XML_numberOfShades;
1218 else if( sName == "grainSize" )
1219 return XML_grainSize;
1220 else if( sName == "intensity" )
1221 return XML_intensity;
1222 else if( sName == "smoothness" )
1223 return XML_smoothness;
1224 else if( sName == "gridSize" )
1225 return XML_gridSize;
1226 else if( sName == "pencilSize" )
1227 return XML_pencilSize;
1228 else if( sName == "size" )
1229 return XML_size;
1230 else if( sName == "brushSize" )
1231 return XML_brushSize;
1232 else if( sName == "scaling" )
1233 return XML_scaling;
1234 else if( sName == "detail" )
1235 return XML_detail;
1236 else if( sName == "bright" )
1237 return XML_bright;
1238 else if( sName == "contrast" )
1239 return XML_contrast;
1240 else if( sName == "colorTemp" )
1241 return XML_colorTemp;
1242 else if( sName == "sat" )
1243 return XML_sat;
1244 else if( sName == "amount" )
1245 return XML_amount;
1246
1247 SAL_WARN( "oox.drawingml", "ArtisticEffectProperties::getEffectToken - unexpected token name: " << sName );
1248 return XML_none;
1249}
1250
1251} // namespace oox
1252
1253/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
AlphaMask GetAlpha() const
bool Convert(BmpConversion eConversion)
bool Mirror(BmpMirrorFlags nMirrorFlags)
Bitmap GetBitmap(Color aTransparentReplaceColor) const
bool Crop(const tools::Rectangle &rRectPixel)
const Size & GetSizePixel() const
static bool Filter(BitmapEx &rBmpEx, BitmapFilter const &rFilter)
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
void setOriginURL(OUString const &rOriginURL)
constexpr tools::Long Height() const
constexpr tools::Long Width() const
Provides helper functions for colors, device measurement conversion, graphics, and graphic objects ha...
css::awt::Size getOriginalSize(const css::uno::Reference< css::graphic::XGraphic > &rxGraphic) const
calculates the original size of a graphic which is necessary to be able to calculate cropping values
css::awt::Size convertScreenPixelToHmm(const css::awt::Size &rPixel) const
Converts the passed size from screen pixels to 1/100 mm.
A helper that maps property identifiers to property values.
Definition: propertymap.hxx:52
css::uno::Any getProperty(sal_Int32 nPropId)
bool hasProperty(sal_Int32 nPropId) const
Returns true, if the map contains a property with the passed identifier.
bool setProperty(sal_Int32 nPropId, Type &&rValue)
Sets the specified property to the passed value.
Definition: propertymap.hxx:72
sal_Int16 getTintOrShade() const
Definition: color.cxx:482
sal_Int16 getLumMod() const
Definition: color.cxx:499
sal_Int16 getTransparency() const
Returns the transparency of the color (0 = opaque, 100 = full transparent).
Definition: color.cxx:708
void assignIfUsed(const Color &rColor)
Overwrites this color with the passed color, if it is used.
Definition: color.hxx:84
sal_Int16 getLumOff() const
Definition: color.cxx:515
bool isUsed() const
Returns true, if the color is initialized.
Definition: color.hxx:87
bool hasTransparency() const
Returns true, if the color is transparent.
Definition: color.cxx:703
sal_Int16 getSchemeColorIndex() const
Definition: color.cxx:713
::Color getColor(const GraphicHelper &rGraphicHelper, ::Color nPhClr=API_RGB_TRANSPARENT) const
Returns the final RGB color value.
Definition: color.cxx:531
bool setProperty(ShapeProperty ePropId, const Type &rValue)
Sets the specified shape property to the passed value.
bool supportsProperty(ShapeProperty ePropId) const
Returns true, if the specified property is supported.
OString sName
Definition: drawingml.cxx:4092
static drawing::Hatch createHatch(sal_Int32 nHatchToken, ::Color nColor)
Definition: hatchmap.hxx:18
BmpMirrorFlags
sal_Int32 nIndex
Sequence< sal_Int8 > aSeq
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
tools::Long const nBorder
enum SAL_DLLPUBLIC_RTTI FillStyle
css::beans::PropertyValue makePropertyValue(const OUString &rName, T &&rValue)
@ FillBitmap
Explicit fill bitmap or name of a fill bitmap stored in a global container.
@ FillGradient
Explicit fill gradient or name of a fill gradient stored in a global container.
@ FillHatch
Explicit fill hatch or name of a fill hatch stored in a global container.
const sal_Int32 MAX_PERCENT
const sal_Int32 PER_DEGREE
const sal_Int32 PER_PERCENT
void assignIfUsed(std::optional< Type > &rDestValue, const std::optional< Type > &rSourceValue)
Definition: helper.hxx:174
const ::Color API_RGB_TRANSPARENT(ColorTransparency, 0xffffffff)
Transparent color for API calls.
XML_none
long Long
BitmapMode
XML_TOKEN_INVALID
DefTokenId nToken
bool isEmpty() const
The original graphic as embedded object.
css::beans::PropertyValue getEffect()
Returns the struct as a PropertyValue with Name = msName and Value = maAttribs as a Sequence< Propert...
void assignUsed(const ArtisticEffectProperties &rSourceProps)
Overwrites all members that are explicitly set in rSourceProps.
::oox::ole::OleObjectInfo mrOleObjectInfo
std::map< OUString, css::uno::Any > maAttribs
static OUString getEffectString(sal_Int32 nToken)
Translate effect tokens to strings.
static sal_Int32 getEffectToken(const OUString &sName)
Translate effect strings to tokens.
std::optional< css::geometry::IntegerRectangle2D > moClipRect
Stretch fill offsets.
Color maColorChangeTo
Start color of color transformation.
std::optional< css::geometry::IntegerRectangle2D > moFillRect
Bitmap tile or stretch.
std::optional< sal_Int32 > moColorEffect
True = rotate bitmap with shape.
std::optional< sal_Int32 > moBitmapMode
The fill graphic.
std::optional< sal_Int32 > moTileFlip
Anchor point inside bitmap.
Color maDuotoneColors[2]
Destination color of color transformation.
std::optional< sal_Int32 > moAlphaModFix
Artistic effect, not supported by core.
std::optional< sal_Int32 > moTileScaleY
Horizontal scaling of bitmap tiles (1/1000 percent).
std::optional< sal_Int32 > moTileOffsetY
Width of bitmap tiles (EMUs).
std::optional< sal_Int32 > moBrightness
XML token for a color effect.
Color maColorChangeFrom
Bi-Level (Black/White) effect threshold (1/1000 percent)
std::optional< bool > moRotateWithShape
Flip mode of bitmap tiles.
std::optional< sal_Int32 > moBiLevelThreshold
Contrast in the range [-100000,100000].
css::uno::Reference< css::graphic::XGraphic > mxFillGraphic
ArtisticEffectProperties maEffect
Duotone Colors.
void assignUsed(const BlipFillProperties &rSourceProps)
Overwrites all members that are explicitly set in rSourceProps.
std::optional< sal_Int32 > moTileAlign
Vertical scaling of bitmap tiles (1/1000 percent).
std::optional< sal_Int32 > moTileScaleX
Height of bitmap tiles (EMUs).
std::optional< sal_Int32 > moTileOffsetX
std::optional< sal_Int32 > moContrast
Brightness in the range [-100000,100000].
void pushToPropMap(ShapePropertyMap &rPropMap, const GraphicHelper &rGraphicHelper, sal_Int32 nShapeRotation=0, ::Color nPhClr=API_RGB_TRANSPARENT, sal_Int16 nPhClrTheme=-1, bool bFlipH=false, bool bFlipV=false, bool bIsCustomShape=false) const
Writes the properties to the passed property map.
PatternFillProperties maPatternProps
Properties for gradient fills.
GradientFillProperties maGradientProps
Whether the background is used as fill type.
BlipFillProperties maBlipProps
Properties for pattern fills.
void assignUsed(const FillProperties &rSourceProps)
Properties for bitmap fills.
Color getBestSolidColor() const
Tries to resolve current settings to a solid color, e.g.
std::optional< bool > moUseBgFill
Solid fill color and transparence.
Color maFillColor
Fill type (OOXML token).
std::optional< sal_Int32 > moFillType
std::optional< css::geometry::IntegerRectangle2D > moFillToRect
Gradient stops (colors/transparence).
std::optional< sal_Int32 > moShadeFlip
Rotation angle of linear gradients.
std::optional< bool > moRotateWithShape
True = scale gradient into shape.
std::optional< sal_Int32 > moGradientPath
void assignUsed(const GradientFillProperties &rSourceProps)
True = rotate gradient with shape.
std::optional< css::geometry::IntegerRectangle2D > moTileRect
std::optional< bool > moShadeScaled
Flip mode of gradient, if not stretched to shape.
std::optional< sal_Int32 > moShadeAngle
If set, gradient follows rectangle, circle, or shape.
::std::multimap< double, Color > GradientStopMap
OUString m_sMediaPackageURL
Audio/Video URL.
css::uno::Reference< css::io::XInputStream > m_xMediaStream
Audio/Video input stream.
void pushToPropMap(PropertyMap &rPropMap, const GraphicHelper &rGraphicHelper, bool bFlipH=false, bool bFlipV=false) const
Writes the properties to the passed property map.
BlipFillProperties maBlipProps
Properties for the graphic.
Color maPattBgColor
Pattern foreground color.
std::optional< sal_Int32 > moPattPreset
Pattern background color.
void assignUsed(const PatternFillProperties &rSourceProps)
Preset pattern type.
StreamDataSequence maEmbeddedData
Data of an embedded OLE object.
unsigned char sal_uInt8
#define SAL_MAX_INT32
signed char sal_Int8
constexpr OUStringLiteral PROP_FillBitmapMode
constexpr OUStringLiteral PROP_GraphicColorMode
constexpr OUStringLiteral PROP_AdjustLuminance
constexpr OUStringLiteral PROP_RotateAngle
constexpr OUStringLiteral PROP_AdjustContrast
constexpr OUStringLiteral PROP_FillColorLumOff
constexpr OUStringLiteral PROP_Transparency
constexpr OUStringLiteral PROP_GraphicCrop
constexpr OUStringLiteral PROP_FillColorTheme
constexpr OUStringLiteral PROP_FillStyle
constexpr OUStringLiteral PROP_FillColorLumMod