1092 lines
50 KiB
C++
1092 lines
50 KiB
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<double, double, double, double>;
|
|
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, 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));
|
|
|
|
if( maGradientProps.moGradientPath.value() == XML_circle )
|
|
{
|
|
// Style should be radial at least when the horizontal center is at 50%.
|
|
// Otherwise import as a linear gradient, because it is the most similar to the MSO radial style.
|
|
// aGradient.SetGradientStyle(awt::GradientStyle_LINEAR);
|
|
if( 100 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() )
|
|
aGradient.SetAngle( Degree10(450) );
|
|
else if( 0 == aGradient.GetXOffset() && 100 == aGradient.GetYOffset() )
|
|
aGradient.SetAngle( Degree10(3150) );
|
|
else if( 100 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() )
|
|
aGradient.SetAngle( Degree10(1350) );
|
|
else if( 0 == aGradient.GetXOffset() && 0 == aGradient.GetYOffset() )
|
|
aGradient.SetAngle( Degree10(2250) );
|
|
else
|
|
aGradient.SetGradientStyle(awt::GradientStyle_RADIAL);
|
|
}
|
|
else
|
|
{
|
|
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_cast< double >( 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_cast< double >( 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& 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: */
|