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