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