Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/oox/source/drawingml/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 49 kB image not shown  

Quelle  fillproperties.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <drawingml/fillproperties.hxx>

#include <iterator>

#include <comphelper/propertyvalue.hxx>
#include <drawingml/graphicproperties.hxx>
#include <vcl/graph.hxx>
#include <vcl/bitmap/BitmapMonochromeFilter.hxx>
#include <docmodel/uno/UnoComplexColor.hxx>
#include <docmodel/uno/UnoGradientTools.hxx>
#include <basegfx/utils/gradienttools.hxx>

#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/awt/Gradient2.hpp>
#include <com/sun/star/text/GraphicCrop.hpp>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/drawing/BitmapMode.hpp>
#include <com/sun/star/drawing/ColorMode.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/RectanglePoint.hpp>
#include <com/sun/star/graphic/XGraphicTransformer.hpp>
#include <oox/helper/graphichelper.hxx>
#include <oox/drawingml/drawingmltypes.hxx>
#include <oox/drawingml/shapepropertymap.hxx>
#include <drawingml/hatchmap.hxx>
#include <oox/token/namespaces.hxx>
#include <oox/token/properties.hxx>
#include <oox/token/tokens.hxx>
#include <osl/diagnose.h>
#include <sal/log.hxx>

#include <frozen/bits/defines.h>
#include <frozen/bits/elsa_std.h>
#include <frozen/unordered_map.h>


using namespace ::com::sun::star;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::graphic;

using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Exception;
using ::com::sun::star::uno::UNO_QUERY_THROW;
using ::com::sun::star::geometry::IntegerRectangle2D;

namespace oox::drawingml {

namespace {

Reference< XGraphic > lclCheckAndApplyDuotoneTransform(const BlipFillProperties& aBlipProps, uno::Reference<graphic::XGraphic> const & xGraphic,
                                                       const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
{
    if (aBlipProps.maDuotoneColors[0].isUsed() && aBlipProps.maDuotoneColors[1].isUsed())
    {
        ::Color nColor1 = aBlipProps.maDuotoneColors[0].getColor( rGraphicHelper, nPhClr );
        ::Color nColor2 = aBlipProps.maDuotoneColors[1].getColor( rGraphicHelper, nPhClr );

        uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
        if (xTransformer.is())
            return xTransformer->applyDuotone(xGraphic, sal_Int32(nColor1), sal_Int32(nColor2));
    }
    return xGraphic;
}

Reference< XGraphic > lclRotateGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, Degree10 nRotation)
{
    ::Graphic aGraphic(xGraphic);
    ::Graphic aReturnGraphic;

    assert (aGraphic.GetType() == GraphicType::Bitmap);

    BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
    const ::Color aColor(0x00);
    aBitmapEx.Rotate(nRotation, aColor);
    aReturnGraphic = ::Graphic(aBitmapEx);
    aReturnGraphic.setOriginURL(aGraphic.getOriginURL());

    return aReturnGraphic.GetXGraphic();
}

using Quotients = std::tuple<doubledoubledoubledouble>;
Quotients getQuotients(geometry::IntegerRectangle2D aRelRect, double hDiv, double vDiv)
{
    return { aRelRect.X1 / hDiv, aRelRect.Y1 / vDiv, aRelRect.X2 / hDiv, aRelRect.Y2 / vDiv };
}

// ECMA-376 Part 1 20.1.8.55 srcRect (Source Rectangle)
std::optional<Quotients> CropQuotientsFromSrcRect(geometry::IntegerRectangle2D aSrcRect)
{
    aSrcRect.X1 = std::max(aSrcRect.X1, sal_Int32(0));
    aSrcRect.X2 = std::max(aSrcRect.X2, sal_Int32(0));
    aSrcRect.Y1 = std::max(aSrcRect.Y1, sal_Int32(0));
    aSrcRect.Y2 = std::max(aSrcRect.Y2, sal_Int32(0));
    if (aSrcRect.X1 + aSrcRect.X2 >= MAX_PERCENT || aSrcRect.Y1 + aSrcRect.Y2 >= MAX_PERCENT)
        return {}; // Cropped everything
    return getQuotients(aSrcRect, MAX_PERCENT, MAX_PERCENT);
}

// ECMA-376 Part 1 20.1.8.30 fillRect (Fill Rectangle)
std::optional<Quotients> CropQuotientsFromFillRect(geometry::IntegerRectangle2D aFillRect)
{
    aFillRect.X1 = std::min(aFillRect.X1, sal_Int32(0));
    aFillRect.X2 = std::min(aFillRect.X2, sal_Int32(0));
    aFillRect.Y1 = std::min(aFillRect.Y1, sal_Int32(0));
    aFillRect.Y2 = std::min(aFillRect.Y2, sal_Int32(0));
    // Negative divisor and negative relative offset give positive value wanted in lclCropGraphic
    return getQuotients(aFillRect, -MAX_PERCENT + aFillRect.X1 + aFillRect.X2,
                        -MAX_PERCENT + aFillRect.Y1 + aFillRect.Y2);
}

// Crops a piece of the bitmap. lclCropGraphic doesn't handle growing.
Reference<XGraphic> lclCropGraphic(uno::Reference<graphic::XGraphic> const& xGraphic,
                                   std::optional<Quotients> quotients)
{
    ::Graphic aGraphic(xGraphic);
    assert (aGraphic.GetType() == GraphicType::Bitmap);

    BitmapEx aBitmapEx;
    if (quotients)
    {
        aBitmapEx = aGraphic.GetBitmapEx();

        const Size bmpSize = aBitmapEx.GetSizePixel();
        const auto& [qx1, qy1, qx2, qy2] = *quotients;
        const tools::Long l = std::round(bmpSize.Width() * qx1);
        const tools::Long t = std::round(bmpSize.Height() * qy1);
        const tools::Long r = std::round(bmpSize.Width() * qx2);
        const tools::Long b = std::round(bmpSize.Height() * qy2);

        aBitmapEx.Crop({ l, t, bmpSize.Width() - r - 1, bmpSize.Height() - b - 1 });
    }

    ::Graphic aReturnGraphic(aBitmapEx);
    aReturnGraphic.setOriginURL(aGraphic.getOriginURL());

    return aReturnGraphic.GetXGraphic();
}

Reference< XGraphic > lclMirrorGraphic(uno::Reference<graphic::XGraphic> const & xGraphic, bool bFlipH, bool bFlipV)
{
    ::Graphic aGraphic(xGraphic);
    ::Graphic aReturnGraphic;

    assert (aGraphic.GetType() == GraphicType::Bitmap);

    BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
    BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;

    if(bFlipH)
        nMirrorFlags |= BmpMirrorFlags::Horizontal;
    if(bFlipV)
        nMirrorFlags |= BmpMirrorFlags::Vertical;

    aBitmapEx.Mirror(nMirrorFlags);

    aReturnGraphic = ::Graphic(aBitmapEx);
    aReturnGraphic.setOriginURL(aGraphic.getOriginURL());

    return aReturnGraphic.GetXGraphic();
}

Reference< XGraphic > lclGreysScaleGraphic(uno::Reference<graphic::XGraphic> const & xGraphic)
{
    ::Graphic aGraphic(xGraphic);
    ::Graphic aReturnGraphic;

    assert (aGraphic.GetType() == GraphicType::Bitmap);

    BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
    aBitmapEx.Convert(BmpConversion::N8BitGreys);

    aReturnGraphic = ::Graphic(aBitmapEx);
    aReturnGraphic.setOriginURL(aGraphic.getOriginURL());

    return aReturnGraphic.GetXGraphic();
}

/// Applies the graphic Black&White (Monochrome) effect with the imported threshold
Reference<XGraphic> lclApplyBlackWhiteEffect(const BlipFillProperties& aBlipProps,
                                             const uno::Reference<graphic::XGraphic>& xGraphic)
{
    const auto& oBiLevelThreshold = aBlipProps.moBiLevelThreshold;
    if (oBiLevelThreshold.has_value())
    {
        sal_uInt8 nThreshold
            = static_cast<sal_uInt8>(oBiLevelThreshold.value() * 255 / MAX_PERCENT);

        ::Graphic aGraphic(xGraphic);
        ::Graphic aReturnGraphic;

        BitmapEx aBitmapEx(aGraphic.GetBitmapEx());
        const AlphaMask& aMask(aBitmapEx.GetAlphaMask());

        BitmapEx aTmpBmpEx(aBitmapEx.GetBitmap());
        BitmapFilter::Filter(aTmpBmpEx, BitmapMonochromeFilter{ nThreshold });

        aReturnGraphic = ::Graphic(BitmapEx(aTmpBmpEx.GetBitmap(), aMask));
        aReturnGraphic.setOriginURL(aGraphic.getOriginURL());
        return aReturnGraphic.GetXGraphic();
    }
    return xGraphic;
}

Reference< XGraphic > lclCheckAndApplyChangeColorTransform(const BlipFillProperties &aBlipProps,&nbsp;uno::Reference<graphic::XGraphic> const & xGraphic,
                                                           const GraphicHelper& rGraphicHelper, const ::Color nPhClr)
{
    if( aBlipProps.maColorChangeFrom.isUsed() && aBlipProps.maColorChangeTo.isUsed() )
    {
        ::Color nFromColor = aBlipProps.maColorChangeFrom.getColor( rGraphicHelper, nPhClr );
        ::Color nToColor = aBlipProps.maColorChangeTo.getColor( rGraphicHelper, nPhClr );
        if ( (nFromColor != nToColor) || aBlipProps.maColorChangeTo.hasTransparency() )
        {
            sal_Int16 nToTransparence = aBlipProps.maColorChangeTo.getTransparency();
            sal_Int8 nToAlpha = static_cast< sal_Int8 >( (100 - nToTransparence) * 2.55 );

            sal_uInt8 nTolerance = 9;
            Graphic aGraphic{ xGraphic };
            if( aGraphic.IsGfxLink() )
            {
                // tdf#149670: Try to guess tolerance depending on image format
                switch (aGraphic.GetGfxLink().GetType())
                {
                    case GfxLinkType::NativeJpg:
                        nTolerance = 15;
                        break;
                    case GfxLinkType::NativePng:
                    case GfxLinkType::NativeTif:
                        nTolerance = 1;
                        break;
                    case GfxLinkType::NativeBmp:
                        nTolerance = 0;
                        break;
                    default:
                        break;
                }
            }

            uno::Reference<graphic::XGraphicTransformer> xTransformer(aBlipProps.mxFillGraphic, uno::UNO_QUERY);
            if (xTransformer.is())
                return xTransformer->colorChange(xGraphic, sal_Int32(nFromColor), nTolerance, sal_Int32(nToColor), nToAlpha);
        }
    }
    return xGraphic;
}

uno::Reference<graphic::XGraphic> applyBrightnessContrast(uno::Reference<graphic::XGraphic> const & xGraphic, sal_Int32 brightness, sal_Int32 contrast)
{
    uno::Reference<graphic::XGraphicTransformer> xTransformer(xGraphic, uno::UNO_QUERY);
    if (xTransformer.is())
        return xTransformer->applyBrightnessContrast(xGraphic, brightness, contrast, true);
    return xGraphic;
}

BitmapMode lclGetBitmapMode( sal_Int32 nToken )
{
    OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
    switch( nToken )
    {
        case XML_tile:      return BitmapMode_REPEAT;
        case XML_stretch:   return BitmapMode_STRETCH;
    }

    // tdf#128596 Default value is XML_tile for MSO.
    return BitmapMode_REPEAT;
}

RectanglePoint lclGetRectanglePoint( sal_Int32 nToken )
{
    OSL_ASSERT((nToken & sal_Int32(0xFFFF0000))==0);
    switch( nToken )
    {
        case XML_tl:    return RectanglePoint_LEFT_TOP;
        case XML_t:     return RectanglePoint_MIDDLE_TOP;
        case XML_tr:    return RectanglePoint_RIGHT_TOP;
        case XML_l:     return RectanglePoint_LEFT_MIDDLE;
        case XML_ctr:   return RectanglePoint_MIDDLE_MIDDLE;
        case XML_r:     return RectanglePoint_RIGHT_MIDDLE;
        case XML_bl:    return RectanglePoint_LEFT_BOTTOM;
        case XML_b:     return RectanglePoint_MIDDLE_BOTTOM;
        case XML_br:    return RectanglePoint_RIGHT_BOTTOM;
    }
    return RectanglePoint_LEFT_TOP;
}

awt::Size lclGetOriginalSize( const GraphicHelper& rGraphicHelper, const Reference< XGraphic >& rxGraphic )
{
    awt::Size aSizeHmm( 0, 0 );
    try
    {
        Reference< beans::XPropertySet > xGraphicPropertySet( rxGraphic, UNO_QUERY_THROW );
        if( xGraphicPropertySet->getPropertyValue( u"Size100thMM"_ustr ) >>= aSizeHmm )
        {
            if( !aSizeHmm.Width && !aSizeHmm.Height )
            {   // MAPMODE_PIXEL USED :-(
                awt::Size aSourceSizePixel( 0, 0 );
                if( xGraphicPropertySet->getPropertyValue( u"SizePixel"_ustr ) >>= aSourceSizePixel )
                    aSizeHmm = rGraphicHelper.convertScreenPixelToHmm( aSourceSizePixel );
            }
        }
    }
    catch( Exception& )
    {
    }
    return aSizeHmm;
}

// namespace

void GradientFillProperties::assignUsed( const GradientFillProperties& rSourceProps )
{
    if( !rSourceProps.maGradientStops.empty() )
        maGradientStops = rSourceProps.maGradientStops;
    assignIfUsed( moFillToRect, rSourceProps.moFillToRect );
    assignIfUsed( moTileRect, rSourceProps.moTileRect );
    assignIfUsed( moGradientPath, rSourceProps.moGradientPath );
    assignIfUsed( moShadeAngle, rSourceProps.moShadeAngle );
    assignIfUsed( moShadeFlip, rSourceProps.moShadeFlip );
    assignIfUsed( moShadeScaled, rSourceProps.moShadeScaled );
    assignIfUsed( moRotateWithShape, rSourceProps.moRotateWithShape );
}

void PatternFillProperties::assignUsed( const PatternFillProperties& rSourceProps )
{
    maPattFgColor.assignIfUsed( rSourceProps.maPattFgColor );
    maPattBgColor.assignIfUsed( rSourceProps.maPattBgColor );
    assignIfUsed( moPattPreset, rSourceProps.moPattPreset );
}

void BlipFillProperties::assignUsed( const BlipFillProperties& rSourceProps )
{
    if(rSourceProps.mxFillGraphic.is())
        mxFillGraphic = rSourceProps.mxFillGraphic;
    assignIfUsed( moBitmapMode, rSourceProps.moBitmapMode );
    assignIfUsed( moFillRect, rSourceProps.moFillRect );
    assignIfUsed( moTileOffsetX, rSourceProps.moTileOffsetX );
    assignIfUsed( moTileOffsetY, rSourceProps.moTileOffsetY );
    assignIfUsed( moTileScaleX, rSourceProps.moTileScaleX );
    assignIfUsed( moTileScaleY, rSourceProps.moTileScaleY );
    assignIfUsed( moTileAlign, rSourceProps.moTileAlign );
    assignIfUsed( moTileFlip, rSourceProps.moTileFlip );
    assignIfUsed( moRotateWithShape, rSourceProps.moRotateWithShape );
    assignIfUsed( moColorEffect, rSourceProps.moColorEffect );
    assignIfUsed( moBrightness, rSourceProps.moBrightness );
    assignIfUsed( moContrast, rSourceProps.moContrast );
    assignIfUsed( moBiLevelThreshold, rSourceProps.moBiLevelThreshold );
    maColorChangeFrom.assignIfUsed( rSourceProps.maColorChangeFrom );
    maColorChangeTo.assignIfUsed( rSourceProps.maColorChangeTo );
    maDuotoneColors[0].assignIfUsed( rSourceProps.maDuotoneColors[0] );
    maDuotoneColors[1].assignIfUsed( rSourceProps.maDuotoneColors[1] );
    maEffect.assignUsed( rSourceProps.maEffect );
    assignIfUsed(moAlphaModFix, rSourceProps.moAlphaModFix);
}

void FillProperties::assignUsed( const FillProperties& rSourceProps )
{
    assignIfUsed( moFillType, rSourceProps.moFillType );
    maFillColor.assignIfUsed( rSourceProps.maFillColor );
    assignIfUsed( moUseBgFill, rSourceProps.moUseBgFill );
    maGradientProps.assignUsed( rSourceProps.maGradientProps );
    maPatternProps.assignUsed( rSourceProps.maPatternProps );
    maBlipProps.assignUsed( rSourceProps.maBlipProps );
}

Color FillProperties::getBestSolidColor() const
{
    Color aSolidColor;
    if( moFillType.has_value() ) switch( moFillType.value() )
    {
        case XML_solidFill:
            aSolidColor = maFillColor;
        break;
        case XML_gradFill:
            if( !maGradientProps.maGradientStops.empty() )
            {
                GradientFillProperties::GradientStopMap::const_iterator aGradientStop =
                    maGradientProps.maGradientStops.begin();
                if (maGradientProps.maGradientStops.size() > 2)
                    ++aGradientStop;
                aSolidColor = aGradientStop->second;
            }
        break;
        case XML_pattFill:
            aSolidColor = maPatternProps.maPattBgColor.isUsed() ? maPatternProps.maPattBgColor : maPatternProps.maPattFgColor;
        break;
    }
    return aSolidColor;
}

void FillProperties::pushToPropMap(ShapePropertyMap& rPropMap, const GraphicHelper& rGraphicHelper,
                                   sal_Int32 nShapeRotation, ::Color nPhClr,
                                   const css::awt::Size& rSize, sal_Int16 nPhClrTheme, bool bFlipH,
                                   bool bFlipV, bool bIsCustomShape) const
{
    if( !moFillType.has_value() )
        return;

    FillStyle eFillStyle = FillStyle_NONE;
    OSL_ASSERT((moFillType.value() & sal_Int32(0xFFFF0000))==0);
    switch( moFillType.value() )
    {
        case XML_noFill:
        {
            eFillStyle = FillStyle_NONE;
            rPropMap.setProperty(ShapeProperty::FillUseSlideBackground, moUseBgFill.value_or(false));
        }
        break;

        case XML_solidFill:
            if( maFillColor.isUsed() )
            {
                ::Color aFillColor = maFillColor.getColor(rGraphicHelper, nPhClr);
                rPropMap.setProperty(ShapeProperty::FillColor, aFillColor);
                if( maFillColor.hasTransparency() )
                    rPropMap.setProperty( ShapeProperty::FillTransparency, maFillColor.getTransparency() );

                model::ComplexColor aComplexColor;
                if (aFillColor == nPhClr)
                {
                    aComplexColor.setThemeColor(model::convertToThemeColorType(nPhClrTheme));
                }
                else
                {
                    aComplexColor = maFillColor.getComplexColor();
                    OUString sColorName = getBestSolidColor().getSchemeColorName();
                    sal_Int32 nToken = Color::getColorMapToken(sColorName);
                    if (nToken != -1)
                    {
                        rGraphicHelper.getSchemeColorToken(nToken);
                        model::ThemeColorType eThemeColorType = schemeTokenToThemeColorType(nToken);
                        aComplexColor.setThemeColor(eThemeColorType);
                    }
                }
                rPropMap.setProperty(PROP_FillComplexColor, model::color::createXComplexColor(aComplexColor));

                eFillStyle = FillStyle_SOLID;
            }
        break;

        case XML_gradFill:
            // do not create gradient struct if property is not supported...
            if( rPropMap.supportsProperty( ShapeProperty::FillGradient ) )
            {
                // prepare ColorStops
                basegfx::BColorStops aColorStops;
                basegfx::BColorStops aTransparencyStops;
                bool bContainsTransparency(false);

                // convert to BColorStops, check for contained transparency
                for (const auto& rCandidate : maGradientProps.maGradientStops)
                {
                    const ::Color aColor(rCandidate.second.getColor(rGraphicHelper, nPhClr));
                    aColorStops.emplace_back(rCandidate.first, aColor.getBColor());
                    bContainsTransparency = bContainsTransparency || rCandidate.second.hasTransparency();
                }

                // if we have transparency, convert to BColorStops
                if (bContainsTransparency)
                {
                    for (const auto& rCandidate : maGradientProps.maGradientStops)
                    {
                        const double fTrans(rCandidate.second.getTransparency() * (1.0/100.0));
                        aTransparencyStops.emplace_back(rCandidate.first, basegfx::BColor(fTrans, fTrans, fTrans));
                    }
                }

                // prepare BGradient with some defaults
                // CAUTION: This used awt::Gradient2 before who's empty constructor
                //          (see workdir/UnoApiHeadersTarget/offapi/normal/com/sun/
                //          star/awt/Gradient.hpp) initializes all to zeros, so reflect
                //          this here. OTOH set all that were set, e.g. Start/EndIntens
                //          were set to 100, so just use default of BGradient constructor
                basegfx::BGradient aGradient(
                    aColorStops,
                    awt::GradientStyle_LINEAR,
                    Degree10(900),
                    0,  // border
                    0,  // OfsX -> 0, not 50 (!)
                    0); // OfsY -> 0, not 50 (!)

                // "rotate with shape" set to false -> do not rotate
                if (!maGradientProps.moRotateWithShape.value_or(true))
                {
                    nShapeRotation = 0;
                }

                if (maGradientProps.moGradientPath.has_value())
                {
                    IntegerRectangle2D aFillToRect = maGradientProps.moFillToRect.value_or( IntegerRectangle2D( 0, 0, MAX_PERCENT, MAX_PERCENT ) );
                    sal_Int32 nCenterX = (MAX_PERCENT + aFillToRect.X1 - aFillToRect.X2) / 2;
                    aGradient.SetXOffset(getLimitedValue<sal_Int16, sal_Int32>(
                        nCenterX / PER_PERCENT, 0, 100));
                    sal_Int32 nCenterY = (MAX_PERCENT + aFillToRect.Y1 - aFillToRect.Y2) / 2;
                    aGradient.SetYOffset(getLimitedValue<sal_Int16, sal_Int32>(
                        nCenterY / PER_PERCENT, 0, 100));

                    // FIXME tdf#166140: Size of gradient is smaller than in MSO
                    if( maGradientProps.moGradientPath.value() == XML_circle )
                    {
                        aGradient.SetGradientStyle(awt::GradientStyle_RADIAL);
                    }
                    else
                    {
                        // XML_rect or XML_shape, but the latter is not implemented.
                        aGradient.SetGradientStyle(awt::GradientStyle_RECT);
                    }

                    aColorStops.reverseColorStops();
                    aGradient.SetColorStops(aColorStops);
                    aTransparencyStops.reverseColorStops();
                }
                else if (!maGradientProps.maGradientStops.empty())
                {
                    // aGradient.SetGradientStyle(awt::GradientStyle_LINEAR);
                    sal_Int32 nShadeAngle(maGradientProps.moShadeAngle.value_or( 0 ));
                    // Adjust for flips
                    if ( bFlipH )
                        nShadeAngle = 180*60000 - nShadeAngle;
                    if ( bFlipV )
                        nShadeAngle = -nShadeAngle;
                    const sal_Int32 nDmlAngle = nShadeAngle + nShapeRotation;

                    // convert DrawingML angle (in 1/60000 degrees) to API angle (in 1/10 degrees)
                    aGradient.SetAngle(Degree10(static_cast< sal_Int16 >( (8100 - (nDmlAngle / (PER_DEGREE / 10))) % 3600 )));

                    // If this is symmetrical, set it as an axial gradient for better UI/export.
                    // There were chart2 unit test failures when doing this to transparent gradients
                    // so just avoid that case.
                    if (!bContainsTransparency)
                        aGradient.tryToConvertToAxial();
                }

                if (awt::GradientStyle_RECT == aGradient.GetGradientStyle())
                {
                    // MCGR: tdf#155362: better support border
                    // CAUTION: Need to handle TransparencyStops if used
                    aGradient.tryToRecreateBorder(aTransparencyStops.empty() ? nullptr : &aTransparencyStops);
                }

                // push gradient or named gradient to property map
                if (rPropMap.setProperty(ShapeProperty::FillGradient, model::gradient::createUnoGradient2(aGradient)))
                {
                    eFillStyle = FillStyle_GRADIENT;
                }

                // push gradient transparency to property map if it exists
                if (!aTransparencyStops.empty())
                {
                    aGradient.SetColorStops(aTransparencyStops);
                    rPropMap.setProperty(ShapeProperty::GradientTransparency, model::gradient::createUnoGradient2(aGradient));
                }
            }
        break;

        case XML_blipFill:
            // do not start complex graphic transformation if property is not supported...
            if (maBlipProps.mxFillGraphic.is() && rPropMap.supportsProperty(ShapeProperty::FillBitmap))
            {
                uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, nPhClr);
                // TODO: "rotate with shape" is not possible with our current core

                if (xGraphic.is())
                {
                    if (maBlipProps.moColorEffect.value_or(XML_TOKEN_INVALID) == XML_grayscl)
                        xGraphic = lclGreysScaleGraphic(xGraphic);

                    if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName) &&
                        rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic))
                    {
                        eFillStyle = FillStyle_BITMAP;
                    }
                    else if (rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic))
                    {
                        eFillStyle = FillStyle_BITMAP;
                    }
                }

                // set other bitmap properties, if bitmap has been inserted into the map
                if( eFillStyle == FillStyle_BITMAP )
                {
                    // bitmap mode (single, repeat, stretch)
                    BitmapMode eBitmapMode = lclGetBitmapMode( maBlipProps.moBitmapMode.value_or( XML_TOKEN_INVALID ) );

                    // additional settings for repeated bitmap
                    if( eBitmapMode == BitmapMode_REPEAT )
                    {
                        // anchor position inside bitmap
                        RectanglePoint eRectPoint = lclGetRectanglePoint( maBlipProps.moTileAlign.value_or( XML_tl ) );
                        rPropMap.setProperty( ShapeProperty::FillBitmapRectanglePoint, eRectPoint );

                        awt::Size aOriginalSize = lclGetOriginalSize(rGraphicHelper, maBlipProps.mxFillGraphic);
                        if( (aOriginalSize.Width > 0) && (aOriginalSize.Height > 0) )
                        {
                            // size of one bitmap tile (given as 1/1000 percent of bitmap size), convert to 1/100 mm
                            double fScaleX = maBlipProps.moTileScaleX.value_or( MAX_PERCENT ) / static_castdouble >( MAX_PERCENT );
                            sal_Int32 nFillBmpSizeX = getLimitedValue< sal_Int32, double >( aOriginalSize.Width * fScaleX, 1, SAL_MAX_INT32 );
                            rPropMap.setProperty( ShapeProperty::FillBitmapSizeX, nFillBmpSizeX );
                            double fScaleY = maBlipProps.moTileScaleY.value_or( MAX_PERCENT ) / static_castdouble >( MAX_PERCENT );
                            sal_Int32 nFillBmpSizeY = getLimitedValue< sal_Int32, double >( aOriginalSize.Height * fScaleY, 1, SAL_MAX_INT32 );
                            rPropMap.setProperty( ShapeProperty::FillBitmapSizeY, nFillBmpSizeY );

                            awt::Size aBmpSize(nFillBmpSizeX, nFillBmpSizeY);
                            // offset of the first bitmap tile (given as EMUs), convert to percent
                            sal_Int16 nTileOffsetX = getDoubleIntervalValue< sal_Int16 >(std::round(maBlipProps.moTileOffsetX.value_or( 0 ) / 3.6 / aBmpSize.Width), 0, 100 );
                            rPropMap.setProperty( ShapeProperty::FillBitmapOffsetX, nTileOffsetX );
                            sal_Int16 nTileOffsetY = getDoubleIntervalValue< sal_Int16 >(std::round(maBlipProps.moTileOffsetY.value_or( 0 ) / 3.6 / aBmpSize.Height), 0, 100 );
                            rPropMap.setProperty( ShapeProperty::FillBitmapOffsetY, nTileOffsetY );
                        }
                    }
                    else if ( eBitmapMode == BitmapMode_STRETCH && maBlipProps.moFillRect.has_value() )
                    {
                        geometry::IntegerRectangle2D aFillRect( maBlipProps.moFillRect.value() );
                        awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );
                        if ( aOriginalSize.Width && aOriginalSize.Height )
                        {
                            text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
                            if ( aFillRect.X1 )
                                aGraphCrop.Left = o3tl::convert(aFillRect.X1, aOriginalSize.Width, MAX_PERCENT);
                            if ( aFillRect.Y1 )
                                aGraphCrop.Top = o3tl::convert(aFillRect.Y1, aOriginalSize.Height, MAX_PERCENT);
                            if ( aFillRect.X2 )
                                aGraphCrop.Right = o3tl::convert(aFillRect.X2, aOriginalSize.Width, MAX_PERCENT);
                            if ( aFillRect.Y2 )
                                aGraphCrop.Bottom = o3tl::convert(aFillRect.Y2, aOriginalSize.Height, MAX_PERCENT);

                            bool bHasCropValues = aGraphCrop.Left != 0 || aGraphCrop.Right !=0 || aGraphCrop.Top != 0 || aGraphCrop.Bottom != 0;
                            // Negative GraphicCrop values means "crop" here.
                            bool bNeedCrop = aGraphCrop.Left <= 0 && aGraphCrop.Right <= 0 && aGraphCrop.Top <= 0 && aGraphCrop.Bottom <= 0;

                            if (bHasCropValues)
                            {
                                if (bIsCustomShape && bNeedCrop)
                                {
                                    // Physically crop the image
                                    // In this case, don't set the PROP_GraphicCrop because that
                                    // would lead to applying the crop twice after roundtrip
                                    xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromFillRect(aFillRect));
                                    if (rPropMap.supportsProperty(ShapeProperty::FillBitmapName))
                                        rPropMap.setProperty(ShapeProperty::FillBitmapName, xGraphic);
                                    else
                                        rPropMap.setProperty(ShapeProperty::FillBitmap, xGraphic);
                                }
                                else if ((aFillRect.X1 != 0 && aFillRect.X2 != 0
                                          && aFillRect.X1 != aFillRect.X2)
                                         || (aFillRect.Y1 != 0 && aFillRect.Y2 != 0
                                             && aFillRect.Y1 != aFillRect.Y2))
                                {
                                    rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);
                                }
                                else
                                {
                                    double nL = aFillRect.X1 / static_cast<double>(MAX_PERCENT);
                                    double nT = aFillRect.Y1 / static_cast<double>(MAX_PERCENT);
                                    double nR = aFillRect.X2 / static_cast<double>(MAX_PERCENT);
                                    double nB = aFillRect.Y2 / static_cast<double>(MAX_PERCENT);

                                    sal_Int32 nSizeX;
                                    if (nL || nR)
                                        nSizeX = rSize.Width * (1 - (nL + nR));
                                    else
                                        nSizeX = rSize.Width;
                                    rPropMap.setProperty(ShapeProperty::FillBitmapSizeX, nSizeX);

                                    sal_Int32 nSizeY;
                                    if (nT || nB)
                                        nSizeY = rSize.Height * (1 - (nT + nB));
                                    else
                                        nSizeY = rSize.Height;
                                    rPropMap.setProperty(ShapeProperty::FillBitmapSizeY, nSizeY);

                                    RectanglePoint eRectPoint;
                                    if (!aFillRect.X1 && aFillRect.X2)
                                    {
                                        if (!aFillRect.Y1 && aFillRect.Y2)
                                            eRectPoint = lclGetRectanglePoint(XML_tl);
                                        else if (aFillRect.Y1 && !aFillRect.Y2)
                                            eRectPoint = lclGetRectanglePoint(XML_bl);
                                        else
                                            eRectPoint = lclGetRectanglePoint(XML_l);
                                    }
                                    else if (aFillRect.X1 && !aFillRect.X2)
                                    {
                                        if (!aFillRect.Y1 && aFillRect.Y2)
                                            eRectPoint = lclGetRectanglePoint(XML_tr);
                                        else if (aFillRect.Y1 && !aFillRect.Y2)
                                            eRectPoint = lclGetRectanglePoint(XML_br);
                                        else
                                            eRectPoint = lclGetRectanglePoint(XML_r);
                                    }
                                    else
                                    {
                                        if (!aFillRect.Y1 && aFillRect.Y2)
                                            eRectPoint = lclGetRectanglePoint(XML_t);
                                        else if (aFillRect.Y1 && !aFillRect.Y2)
                                            eRectPoint = lclGetRectanglePoint(XML_b);
                                        else
                                            eRectPoint = lclGetRectanglePoint(XML_ctr);
                                    }
                                    rPropMap.setProperty(ShapeProperty::FillBitmapRectanglePoint, eRectPoint);
                                    eBitmapMode = BitmapMode_NO_REPEAT;
                                }
                            }
                        }
                    }
                    rPropMap.setProperty(ShapeProperty::FillBitmapMode, eBitmapMode);
                }

                if (maBlipProps.moAlphaModFix.has_value())
                    rPropMap.setProperty(ShapeProperty::FillTransparency, static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
            }
        break;

        case XML_pattFill:
        {
            if( rPropMap.supportsProperty( ShapeProperty::FillHatch ) )
            {
                Color aColor( maPatternProps.maPattFgColor );
                if( aColor.isUsed() && maPatternProps.moPattPreset.has_value() )
                {
                    eFillStyle = FillStyle_HATCH;
                    rPropMap.setProperty( ShapeProperty::FillHatch, createHatch( maPatternProps.moPattPreset.value(), aColor.getColor( rGraphicHelper, nPhClr ) ) );
                    if( aColor.hasTransparency() )
                        rPropMap.setProperty( ShapeProperty::FillTransparency, aColor.getTransparency() );

                    // Set background color for hatch
                    if(maPatternProps.maPattBgColor.isUsed())
                    {
                        aColor = maPatternProps.maPattBgColor;
                        rPropMap.setProperty( ShapeProperty::FillBackground, aColor.getTransparency() != 100 );
                        rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
                    }
                }
                else if ( maPatternProps.maPattBgColor.isUsed() )
                {
                    aColor = maPatternProps.maPattBgColor;
                    rPropMap.setProperty( ShapeProperty::FillColor, aColor.getColor( rGraphicHelper, nPhClr ) );
                    if( aColor.hasTransparency() )
                        rPropMap.setProperty( ShapeProperty::FillTransparency, aColor.getTransparency() );
                    eFillStyle = FillStyle_SOLID;
                }
            }
        }
        break;

        case XML_grpFill:
            // todo
            eFillStyle = FillStyle_NONE;
        break;
    }

    // set final fill style property
    rPropMap.setProperty( ShapeProperty::FillStyle, eFillStyle );
}

void GraphicProperties::pushToPropMap( PropertyMap& rPropMap, const GraphicHelper&&nbsp;rGraphicHelper, bool bFlipH, bool bFlipV) const
{
    sal_Int16 nBrightness = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moBrightness.value_or( 0 ) / PER_PERCENT, -100, 100 );
    sal_Int16 nContrast = getLimitedValue< sal_Int16, sal_Int32 >( maBlipProps.moContrast.value_or( 0 ) / PER_PERCENT, -100, 100 );
    ColorMode eColorMode = ColorMode_STANDARD;

    switch( maBlipProps.moColorEffect.value_or( XML_TOKEN_INVALID ) )
    {
        case XML_biLevel:   eColorMode = ColorMode_MONO;    break;
        case XML_grayscl:   eColorMode = ColorMode_GREYS;   break;
    }

    if (maBlipProps.mxFillGraphic.is())
    {
        // created transformed graphic
        uno::Reference<graphic::XGraphic> xGraphic = lclCheckAndApplyChangeColorTransform(maBlipProps, maBlipProps.mxFillGraphic, rGraphicHelper, API_RGB_TRANSPARENT);
        xGraphic = lclCheckAndApplyDuotoneTransform(maBlipProps, xGraphic, rGraphicHelper, API_RGB_TRANSPARENT);

        if( eColorMode == ColorMode_MONO )
        {
            // ColorMode_MONO is the same with MSO's biLevel with 50000 (50%) threshold,
            // when threshold isn't 50000 bake the effect instead.
            if( maBlipProps.moBiLevelThreshold != 50000 )
            {
                xGraphic = lclApplyBlackWhiteEffect(maBlipProps, xGraphic);
                eColorMode = ColorMode_STANDARD;
            }
        }

        if (eColorMode == ColorMode_STANDARD && nBrightness == 70 && nContrast == -70)
        {
            // map MSO 'washout' to our Watermark colormode
            eColorMode = ColorMode_WATERMARK;
            nBrightness = 0;
            nContrast = 0;
        }
        else if( nBrightness != 0 && nContrast != 0 )
        {
            // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
            // while MSO apparently applies half of brightness before contrast and half after. So if only
            // contrast or brightness need to be altered, the result is the same, but if both are involved,
            // there's no way to map that, so just force a conversion of the image.
            xGraphic = applyBrightnessContrast( xGraphic, nBrightness, nContrast );
            nBrightness = 0;
            nContrast = 0;
        }

        // cropping
        if ( maBlipProps.moClipRect.has_value() )
        {
            geometry::IntegerRectangle2D oClipRect( maBlipProps.moClipRect.value() );
            awt::Size aOriginalSize( rGraphicHelper.getOriginalSize( xGraphic ) );

            if (aOriginalSize.Width <= 0 || aOriginalSize.Height <= 0)
            {
                // VectorGraphic Objects need the correct object size for cropping
                Graphic aGraphic(xGraphic);
                if (aGraphic.getVectorGraphicData())
                {
                    Size aPrefSize = aGraphic.GetPrefSize();
                    aOriginalSize.Height = static_cast<sal_Int32>(aPrefSize.getHeight());
                    aOriginalSize.Width = static_cast<sal_Int32>(aPrefSize.getWidth());
                }
            }

            if (aOriginalSize.Width > 0 && aOriginalSize.Height > 0)
            {
                text::GraphicCrop aGraphCrop( 0, 0, 0, 0 );
                if ( oClipRect.X1 )
                    aGraphCrop.Left = o3tl::convert(oClipRect.X1, aOriginalSize.Width, MAX_PERCENT);
                if ( oClipRect.Y1 )
                    aGraphCrop.Top = o3tl::convert(oClipRect.Y1, aOriginalSize.Height, MAX_PERCENT);
                if ( oClipRect.X2 )
                    aGraphCrop.Right = o3tl::convert(oClipRect.X2, aOriginalSize.Width, MAX_PERCENT);
                if ( oClipRect.Y2 )
                    aGraphCrop.Bottom = o3tl::convert(oClipRect.Y2, aOriginalSize.Height, MAX_PERCENT);
                rPropMap.setProperty(PROP_GraphicCrop, aGraphCrop);

                if(mbIsCustomShape)
                {
                    // Positive GraphicCrop values means "crop" here.
                    if (aGraphCrop.Left > 0 || aGraphCrop.Right > 0 || aGraphCrop.Top > 0 || aGraphCrop.Bottom > 0)
                        xGraphic = lclCropGraphic(xGraphic, CropQuotientsFromSrcRect(oClipRect));
                }
            }
        }

        if(mbIsCustomShape)
        {
            // it is a cropped graphic.
            rPropMap.setProperty(PROP_FillStyle, FillStyle_BITMAP);
            rPropMap.setProperty(PROP_FillBitmapMode, BitmapMode_STRETCH);

            // It is a bitmap filled and rotated graphic.
            // When custom shape is rotated, bitmap have to be rotated too.
            // Only in extruded mode the bitmap is transformed together with the shape
            if(rPropMap.hasProperty(PROP_RotateAngle) && !mbIsExtruded)
            {
                tools::Long nAngle = rPropMap.getProperty(PROP_RotateAngle).get<tools::Long>();
                xGraphic = lclRotateGraphic(xGraphic, Degree10(nAngle/10) );
            }

            // We have not core feature that flips graphic in the shape.
            // Here we are applying flip property to bitmap directly.
            if((bFlipH || bFlipV) && !mbIsExtruded)
                xGraphic = lclMirrorGraphic(xGraphic, bFlipH, bFlipV );

            if(eColorMode == ColorMode_GREYS)
                xGraphic = lclGreysScaleGraphic( xGraphic );

            rPropMap.setProperty(PROP_FillBitmap, xGraphic);
        }
        else
            rPropMap.setProperty(PROP_Graphic, xGraphic);


        if ( maBlipProps.moAlphaModFix.has_value() )
        {
            rPropMap.setProperty(
                mbIsCustomShape ? PROP_FillTransparence : PROP_Transparency,
                static_cast<sal_Int16>(100 - (maBlipProps.moAlphaModFix.value() / PER_PERCENT)));
        }
    }
    rPropMap.setProperty(PROP_GraphicColorMode, eColorMode);

    // brightness and contrast
    if( nBrightness != 0 )
        rPropMap.setProperty(PROP_AdjustLuminance, nBrightness);
    if( nContrast != 0 )
        rPropMap.setProperty(PROP_AdjustContrast, nContrast);

    // Media content
    if (!m_sMediaPackageURL.isEmpty())
    {
        rPropMap.setProperty(PROP_MediaURL, m_sMediaPackageURL);
        if (m_xMediaStream.is())
            rPropMap.setProperty(PROP_PrivateStream, m_xMediaStream);
    }
}

bool ArtisticEffectProperties::isEmpty() const
{
    return msName.isEmpty();
}

css::beans::PropertyValue ArtisticEffectProperties::getEffect()
{
    css::beans::PropertyValue aRet;
    if( msName.isEmpty() )
        return aRet;

    css::uno::Sequence< css::beans::PropertyValue > aSeq( maAttribs.size() + 1 );
    auto pSeq = aSeq.getArray();
    sal_uInt32 i = 0;
    for (auto const& attrib : maAttribs)
    {
        pSeq[i].Name = attrib.first;
        pSeq[i].Value = attrib.second;
        i++;
    }

    if( mrOleObjectInfo.maEmbeddedData.hasElements() )
    {
        css::uno::Sequence< css::beans::PropertyValue > aGraphicSeq{
            comphelper::makePropertyValue(u"Id"_ustr, mrOleObjectInfo.maProgId),
            comphelper::makePropertyValue(u"Data"_ustr, mrOleObjectInfo.maEmbeddedData)
        };

        pSeq[i].Name = "OriginalGraphic";
        pSeq[i].Value <<= aGraphicSeq;
    }

    aRet.Name = msName;
    aRet.Value <<= aSeq;

    return aRet;
}

void ArtisticEffectProperties::assignUsed( const ArtisticEffectProperties& rSourceProps )
{
    if( !rSourceProps.isEmpty() )
    {
        msName = rSourceProps.msName;
        maAttribs = rSourceProps.maAttribs;
    }
}

OUString ArtisticEffectProperties::getEffectString( sal_Int32 nToken )
{
    switch( nToken )
    {
        // effects
        case OOX_TOKEN( a14, artisticBlur ):                return u"artisticBlur"_ustr;
        case OOX_TOKEN( a14, artisticCement ):              return u"artisticCement"_ustr;
        case OOX_TOKEN( a14, artisticChalkSketch ):         return u"artisticChalkSketch"_ustr;
        case OOX_TOKEN( a14, artisticCrisscrossEtching ):   return u"artisticCrisscrossEtching"_ustr;
        case OOX_TOKEN( a14, artisticCutout ):              return u"artisticCutout"_ustr;
        case OOX_TOKEN( a14, artisticFilmGrain ):           return u"artisticFilmGrain"_ustr;
        case OOX_TOKEN( a14, artisticGlass ):               return u"artisticGlass"_ustr;
        case OOX_TOKEN( a14, artisticGlowDiffused ):        return u"artisticGlowDiffused"_ustr;
        case OOX_TOKEN( a14, artisticGlowEdges ):           return u"artisticGlowEdges"_ustr;
        case OOX_TOKEN( a14, artisticLightScreen ):         return u"artisticLightScreen"_ustr;
        case OOX_TOKEN( a14, artisticLineDrawing ):         return u"artisticLineDrawing"_ustr;
        case OOX_TOKEN( a14, artisticMarker ):              return u"artisticMarker"_ustr;
        case OOX_TOKEN( a14, artisticMosiaicBubbles ):      return u"artisticMosiaicBubbles"_ustr;
        case OOX_TOKEN( a14, artisticPaintStrokes ):        return u"artisticPaintStrokes"_ustr;
        case OOX_TOKEN( a14, artisticPaintBrush ):          return u"artisticPaintBrush"_ustr;
        case OOX_TOKEN( a14, artisticPastelsSmooth ):       return u"artisticPastelsSmooth"_ustr;
        case OOX_TOKEN( a14, artisticPencilGrayscale ):     return u"artisticPencilGrayscale"_ustr;
        case OOX_TOKEN( a14, artisticPencilSketch ):        return u"artisticPencilSketch"_ustr;
        case OOX_TOKEN( a14, artisticPhotocopy ):           return u"artisticPhotocopy"_ustr;
        case OOX_TOKEN( a14, artisticPlasticWrap ):         return u"artisticPlasticWrap"_ustr;
        case OOX_TOKEN( a14, artisticTexturizer ):          return u"artisticTexturizer"_ustr;
        case OOX_TOKEN( a14, artisticWatercolorSponge ):    return u"artisticWatercolorSponge"_ustr;
        case OOX_TOKEN( a14, brightnessContrast ):          return u"brightnessContrast"_ustr;
        case OOX_TOKEN( a14, colorTemperature ):            return u"colorTemperature"_ustr;
        case OOX_TOKEN( a14, saturation ):                  return u"saturation"_ustr;
        case OOX_TOKEN( a14, sharpenSoften ):               return u"sharpenSoften"_ustr;

        // attributes
        case XML_visible:           return u"visible"_ustr;
        case XML_trans:             return u"trans"_ustr;
        case XML_crackSpacing:      return u"crackSpacing"_ustr;
        case XML_pressure:          return u"pressure"_ustr;
        case XML_numberOfShades:    return u"numberOfShades"_ustr;
        case XML_grainSize:         return u"grainSize"_ustr;
        case XML_intensity:         return u"intensity"_ustr;
        case XML_smoothness:        return u"smoothness"_ustr;
        case XML_gridSize:          return u"gridSize"_ustr;
        case XML_pencilSize:        return u"pencilSize"_ustr;
        case XML_size:              return u"size"_ustr;
        case XML_brushSize:         return u"brushSize"_ustr;
        case XML_scaling:           return u"scaling"_ustr;
        case XML_detail:            return u"detail"_ustr;
        case XML_bright:            return u"bright"_ustr;
        case XML_contrast:          return u"contrast"_ustr;
        case XML_colorTemp:         return u"colorTemp"_ustr;
        case XML_sat:               return u"sat"_ustr;
        case XML_amount:            return u"amount"_ustr;
    }
    SAL_WARN( "oox.drawingml""ArtisticEffectProperties::getEffectString: unexpected token " << nToken );
    return OUString();
}

constexpr auto constEffectTokenForEffectNameMap = frozen::make_unordered_map<std::u16string_view, sal_Int32>(
{
    // effects
    { u"artisticBlur", XML_artisticBlur },
    { u"artisticCement", XML_artisticCement },
    { u"artisticChalkSketch", XML_artisticChalkSketch },
    { u"artisticCrisscrossEtching", XML_artisticCrisscrossEtching },
    { u"artisticCutout", XML_artisticCutout },
    { u"artisticFilmGrain", XML_artisticFilmGrain },
    { u"artisticGlass", XML_artisticGlass },
    { u"artisticGlowDiffused", XML_artisticGlowDiffused },
    { u"artisticGlowEdges", XML_artisticGlowEdges },
    { u"artisticLightScreen", XML_artisticLightScreen },
    { u"artisticLineDrawing", XML_artisticLineDrawing },
    { u"artisticMarker", XML_artisticMarker },
    { u"artisticMosiaicBubbles", XML_artisticMosiaicBubbles },
    { u"artisticPaintStrokes", XML_artisticPaintStrokes },
    { u"artisticPaintBrush", XML_artisticPaintBrush },
    { u"artisticPastelsSmooth", XML_artisticPastelsSmooth },
    { u"artisticPencilGrayscale", XML_artisticPencilGrayscale },
    { u"artisticPencilSketch", XML_artisticPencilSketch },
    { u"artisticPhotocopy", XML_artisticPhotocopy },
    { u"artisticPlasticWrap", XML_artisticPlasticWrap },
    { u"artisticTexturizer", XML_artisticTexturizer },
    { u"artisticWatercolorSponge", XML_artisticWatercolorSponge },
    { u"brightnessContrast", XML_brightnessContrast },
    { u"colorTemperature", XML_colorTemperature },
    { u"saturation", XML_saturation },
    { u"sharpenSoften", XML_sharpenSoften },

    // attributes
    { u"visible", XML_visible },
    { u"trans", XML_trans },
    { u"crackSpacing", XML_crackSpacing },
    { u"pressure", XML_pressure },
    { u"numberOfShades", XML_numberOfShades },
    { u"grainSize", XML_grainSize },
    { u"intensity", XML_intensity },
    { u"smoothness", XML_smoothness },
    { u"gridSize", XML_gridSize },
    { u"pencilSize", XML_pencilSize },
    { u"size", XML_size },
    { u"brushSize", XML_brushSize },
    { u"scaling", XML_scaling },
    { u"detail", XML_detail },
    { u"bright", XML_bright },
    { u"contrast", XML_contrast },
    { u"colorTemp", XML_colorTemp },
    { u"sat", XML_sat },
    { u"amount", XML_amount }
});

sal_Int32 ArtisticEffectProperties::getEffectToken(const OUString& sName)
{
    auto const aIterator = constEffectTokenForEffectNameMap.find(sName);

    if (aIterator != constEffectTokenForEffectNameMap.end())
        return aIterator->second;

    SAL_WARN( "oox.drawingml""ArtisticEffectProperties::getEffectToken - unexpected token name: " << sName );
    return XML_none;
}

// namespace oox

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=99 G=95

¤ Dauer der Verarbeitung: 0.12 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.