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