Hi, Throsten,
I express thanks for your review.
I was bit busy with school work. But here are updated patches.
0001 and 0003 are almost same as previous.
2011/2/2 Thorsten Behrens <thb@documentfoundation.org>:
Nope, this is still in use, especially in legacy binary documents
(soon to be axed I guess), and more importantly, for all those svm
metafiles. Could you keep both code paths - i.e. falling back to the
old code, should there be a step count (with 0 meaning smooth
gradient, and maybe you can even cut off at something like 100 or so
steps)?
I found the way to reproduce the stepping gradients with native gradients.
# Simply adding gradient stops as needed.
So 0002 patch uses native gradients for both smooth and non-smooth gradients.
A bit orthogonal to this great improvement, let me point you to
https://github.com/knobo/OOo-svg-Export.git - this is an early stage
of a slightly different attempt, using the new drawing layer
primitives (that contain more high-level geometry information, like
stroking etc.). I attach two changes I had lying around locally -
maybe you're also interested in looking into that.
It's very interesting and has a potential to resolve many long standing issues.
While it's really attractive, I would like to continue to improve the
current filter.
LibreOffice and its predecessors have never produced an SVG
preserving, at least, visual appearances.
Improving the current filter is the shortest path to make LibreOffice
export visual identical SVG files in a short term.
# I know the structure of an SVG produced by the current filter is mess.
Cheers,
--
Kurosawa Takeshi <taken.spc@gmail.com>
From ba06cca17ff6fd112d8fd4ee9a16176c34de5205 Mon Sep 17 00:00:00 2001
From: Kurosawa Takeshi <taken.spc@gmail.com>
Date: Fri, 11 Feb 2011 18:55:42 +0900
Subject: [PATCH 1/3] Export hatches and gradients as SVG <pattern>s
This patch tends not to improve a visual look, but improve semantic
structure of an exported file.
---
filter/source/svg/svgwriter.cxx | 85 +++++++++++++++++++++++++++------------
filter/source/svg/svgwriter.hxx | 3 +
2 files changed, 62 insertions(+), 26 deletions(-)
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index b33e84a..b0e2a0f 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -39,6 +39,7 @@
static const char aXMLElemG[] = "g";
static const char aXMLElemDefs[] = "defs";
static const char aXMLElemClipPath[] = "clipPath";
+static const char aXMLElemPattern[] = "pattern";
static const char aXMLElemLine[] = "line";
static const char aXMLElemRect[] = "rect";
static const char aXMLElemEllipse[] = "ellipse";
@@ -66,6 +67,7 @@ static const char aXMLAttrRY[] = "ry";
static const char aXMLAttrWidth[] = "width";
static const char aXMLAttrHeight[] = "height";
static const char aXMLAttrPoints[] = "points";
+static const char aXMLAttrPatternUnits[] = "patternUnits";
static const char aXMLAttrXLinkHRef[] = "xlink:href";
// --------------
@@ -379,7 +381,8 @@ SVGActionWriter::SVGActionWriter( SvXMLExport& rExport, SVGFontExport& rFontExpo
mrFontExport( rFontExport ),
mpContext( NULL ),
mbClipAttrChanged( sal_False ),
- mnCurClipId( 1 )
+ mnCurClipId( 1 ),
+ mnCurPatternId( 1 )
{
mpVDev = new VirtualDevice;
mpVDev->EnableOutput( sal_False );
@@ -659,48 +662,81 @@ void SVGActionWriter::ImplWritePolyPolygon( const PolyPolygon& rPolyPoly,
sal_Bo
// -----------------------------------------------------------------------------
-void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
- const NMSP_RTL::OUString* pStyle, sal_uInt32
nWriteFlags )
+void SVGActionWriter::ImplWritePattern( const PolyPolygon& rPolyPoly,
+ const Hatch* pHatch,
+ const Gradient* pGradient,
+ const NMSP_RTL::OUString* pStyle,
+ sal_uInt32 nWriteFlags )
{
if( rPolyPoly.Count() )
{
- SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
- FastString aClipId;
- FastString aClipStyle;
+ SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
- aClipId += B2UCONST( "clip" );
- aClipId += NMSP_RTL::OUString::valueOf( ImplGetNextClipId() );
+ FastString aPatternId;
+ aPatternId += B2UCONST( "pattern" );
+ aPatternId += GetValueString( ImplGetNextPatternId() );
{
SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, TRUE, TRUE );
- mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aClipId.GetString() );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aPatternId.GetString() );
+
+ Rectangle aRect( ImplMap( rPolyPoly.GetBoundRect() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX, GetValueString( aRect.Left() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY, GetValueString( aRect.Top() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrWidth, GetValueString(
aRect.GetWidth() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrHeight, GetValueString(
aRect.GetHeight() ) );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrPatternUnits, NMSP_RTL::OUString(
RTL_CONSTASCII_USTRINGPARAM( "userSpaceOnUse") ) );
{
- SvXMLElementExport aElemClipPath( mrExport, XML_NAMESPACE_NONE, aXMLElemClipPath,
TRUE, TRUE );
- ImplWritePolyPolygon( rPolyPoly, sal_False );
+ SvXMLElementExport aElemPattern( mrExport, XML_NAMESPACE_NONE, aXMLElemPattern,
TRUE, TRUE );
+
+ // The origin of a pattern is positioned at (aRect.Left(), aRect.Top()).
+ // So we need to adjust the pattern coordinate.
+ FastString aTransform;
+ aTransform += B2UCONST( "translate" );
+ aTransform += B2UCONST( "(" );
+ aTransform += GetValueString( -aRect.Left() );
+ aTransform += B2UCONST( "," );
+ aTransform += GetValueString( -aRect.Top() );
+ aTransform += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrTransform,
aTransform.GetString() );
+
+ {
+ SvXMLElementExport aElemG2( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE,
TRUE );
+
+ GDIMetaFile aTmpMtf;
+ if( pHatch )
+ mpVDev->AddHatchActions( rPolyPoly, *pHatch, aTmpMtf );
+ else if ( pGradient )
+ mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), *pGradient, aTmpMtf
);
+ ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
+ }
}
}
- // create new context with clippath set
- aClipStyle += B2UCONST( "clip-path:URL(#" );
- aClipStyle += aClipId.GetString();
- aClipStyle += B2UCONST( ")" );
-
- mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aClipStyle.GetString() );
+ FastString aPatternStyle;
+ aPatternStyle += B2UCONST( "fill:url(#" );
+ aPatternStyle += aPatternId.GetString();
+ aPatternStyle += B2UCONST( ")" );
{
- GDIMetaFile aTmpMtf;
- SvXMLElementExport aElemG2( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
-
- mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf );
- ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
+ ImplWritePolyPolygon( rPolyPoly, sal_False, &aPatternStyle.GetString() );
}
}
}
// -----------------------------------------------------------------------------
+void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
+ const NMSP_RTL::OUString* pStyle, sal_uInt32
nWriteFlags )
+{
+ ImplWritePattern( rPolyPoly, NULL, &rGradient, pStyle, nWriteFlags );
+}
+
+// -----------------------------------------------------------------------------
+
void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText,
const sal_Int32* pDXArray, long nWidth,
const NMSP_RTL::OUString* pStyle )
@@ -1267,10 +1303,7 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
if( nWriteFlags & SVGWRITER_WRITE_FILL )
{
const MetaHatchAction* pA = (const MetaHatchAction*) pAction;
- GDIMetaFile aTmpMtf;
-
- mpVDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf );
- ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
+ ImplWritePattern( pA->GetPolyPolygon(), &pA->GetHatch(), NULL, pStyle,
nWriteFlags );
}
}
break;
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index dfdc559..6ec2452 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -163,6 +163,7 @@ private:
SVGAttributeWriter* mpContext;
sal_Bool mbClipAttrChanged;
sal_Int32 mnCurClipId;
+ sal_Int32 mnCurPatternId;
Stack maContextStack;
VirtualDevice* mpVDev;
MapMode maTargetMapMode;
@@ -183,6 +184,7 @@ private:
void ImplWriteRect( const Rectangle& rRect, long nRadX =
0, long nRadY = 0, const ::rtl::OUString* pStyle = NULL );
void ImplWriteEllipse( const Point& rCenter, long nRadX,
long nRadY, const ::rtl::OUString* pStyle = NULL );
void ImplWritePolyPolygon( const PolyPolygon& rPolyPoly,
sal_Bool bLineOnly, const ::rtl::OUString* pStyle = NULL );
+ void ImplWritePattern( const PolyPolygon& rPolyPoly,
const Hatch* pHatch, const Gradient* pGradient, const ::rtl::OUString* pStyle, sal_uInt32
nWriteFlags );
void ImplWriteGradientEx( const PolyPolygon& rPolyPoly,
const Gradient& rGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
void ImplWriteText( const Point& rPos, const String&
rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle = NULL );
void ImplWriteText( const Point& rPos, const String& rText, const sal_Int32*
pDXArray, long nWidth, const ::rtl::OUString* pStyle, Color aTextColor );
@@ -193,6 +195,7 @@ private:
void ImplWriteActions( const GDIMetaFile& rMtf, const
::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
sal_Int32 ImplGetNextClipId() { return mnCurClipId++; }
+ sal_Int32 ImplGetNextPatternId() { return mnCurPatternId++; }
public:
--
1.7.1
From a22a8ba96005850eeb4d44dd64d727e34b2e3c4f Mon Sep 17 00:00:00 2001
From: Kurosawa Takeshi <taken.spc@gmail.com>
Date: Fri, 11 Feb 2011 19:23:10 +0900
Subject: [PATCH 2/3] Export linear and axial gradients as SVG <linearGraidents>s
---
filter/source/svg/svgwriter.cxx | 203 +++++++++++++++++++++++++++++++++++---
filter/source/svg/svgwriter.hxx | 7 ++
2 files changed, 194 insertions(+), 16 deletions(-)
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index b0e2a0f..15a61e7 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -40,6 +40,8 @@ static const char aXMLElemG[] = "g";
static const char aXMLElemDefs[] = "defs";
static const char aXMLElemClipPath[] = "clipPath";
static const char aXMLElemPattern[] = "pattern";
+static const char aXMLElemLinearGradient[] = "linearGradient";
+static const char aXMLElemStop[] = "stop";
static const char aXMLElemLine[] = "line";
static const char aXMLElemRect[] = "rect";
static const char aXMLElemEllipse[] = "ellipse";
@@ -68,6 +70,8 @@ static const char aXMLAttrWidth[] = "width";
static const char aXMLAttrHeight[] = "height";
static const char aXMLAttrPoints[] = "points";
static const char aXMLAttrPatternUnits[] = "patternUnits";
+static const char aXMLAttrGradientUnits[] = "gradientUnits";
+static const char aXMLAttrOffset[] = "offset";
static const char aXMLAttrXLinkHRef[] = "xlink:href";
// --------------
@@ -227,6 +231,21 @@ NMSP_RTL::OUString SVGAttributeWriter::GetFontStyle( const Font& rFont )
// -----------------------------------------------------------------------------
+NMSP_RTL::OUString SVGAttributeWriter::GetColorStyle( const Color& rColor )
+{
+ FastString aStyle;
+ aStyle += B2UCONST( "rgb(" );
+ aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetRed() );
+ aStyle += B2UCONST( "," );
+ aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetGreen() );
+ aStyle += B2UCONST( "," );
+ aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rColor.GetBlue() );
+ aStyle += B2UCONST( ")" );
+ return aStyle.GetString();
+}
+
+// -----------------------------------------------------------------------------
+
NMSP_RTL::OUString SVGAttributeWriter::GetPaintStyle( const Color& rLineColor, const Color&
rFillColor, const LineInfo* pLineInfo )
{
FastString aStyle;
@@ -239,13 +258,7 @@ NMSP_RTL::OUString SVGAttributeWriter::GetPaintStyle( const Color& rLineColor,
c
else
{
// line color value in rgb
- aStyle += B2UCONST( "rgb(" );
- aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rLineColor.GetRed() );
- aStyle += B2UCONST( "," );
- aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rLineColor.GetGreen() );
- aStyle += B2UCONST( "," );
- aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rLineColor.GetBlue() );
- aStyle += B2UCONST( ")" );
+ aStyle += GetColorStyle( rLineColor );
// line color opacity in percent if neccessary
if( rLineColor.GetTransparency() )
@@ -327,13 +340,7 @@ NMSP_RTL::OUString SVGAttributeWriter::GetPaintStyle( const Color& rLineColor,
c
else
{
// fill color value in rgb
- aStyle += B2UCONST( "rgb(" );
- aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rFillColor.GetRed() );
- aStyle += B2UCONST( "," );
- aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rFillColor.GetGreen() );
- aStyle += B2UCONST( "," );
- aStyle += NMSP_RTL::OUString::valueOf( (sal_Int32) rFillColor.GetBlue() );
- aStyle += B2UCONST( ")" );
+ aStyle += GetColorStyle( rFillColor );
// fill color opacity in percent if neccessary
if( rFillColor.GetTransparency() )
@@ -382,7 +389,8 @@ SVGActionWriter::SVGActionWriter( SvXMLExport& rExport, SVGFontExport& rFontExpo
mpContext( NULL ),
mbClipAttrChanged( sal_False ),
mnCurClipId( 1 ),
- mnCurPatternId( 1 )
+ mnCurPatternId( 1 ),
+ mnCurGradientId( 1 )
{
mpVDev = new VirtualDevice;
mpVDev->EnableOutput( sal_False );
@@ -732,7 +740,170 @@ void SVGActionWriter::ImplWritePattern( const PolyPolygon& rPolyPoly,
void SVGActionWriter::ImplWriteGradientEx( const PolyPolygon& rPolyPoly, const Gradient& rGradient,
const NMSP_RTL::OUString* pStyle, sal_uInt32
nWriteFlags )
{
- ImplWritePattern( rPolyPoly, NULL, &rGradient, pStyle, nWriteFlags );
+ if ( rGradient.GetStyle() == GRADIENT_LINEAR ||
+ rGradient.GetStyle() == GRADIENT_AXIAL )
+ {
+ ImplWriteGradientLinear( rPolyPoly, rGradient );
+ }
+ else
+ {
+ ImplWritePattern( rPolyPoly, NULL, &rGradient, pStyle, nWriteFlags );
+ }
+}
+
+void SVGActionWriter::ImplWriteGradientLinear( const PolyPolygon& rPolyPoly,
+ const Gradient& rGradient )
+{
+ if( rPolyPoly.Count() )
+ {
+ SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
+
+ FastString aGradientId;
+ aGradientId += B2UCONST( "gradient" );
+ aGradientId += GetValueString( ImplGetNextGradientId() );
+
+ {
+ SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, TRUE, TRUE );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aGradientId.GetString() );
+ {
+ Rectangle aTmpRect;
+ Point aTmpCenter;
+ rGradient.GetBoundRect( rPolyPoly.GetBoundRect(), aTmpRect, aTmpCenter );
+ const Rectangle aRect( ImplMap( aTmpRect) );
+ const Point aCenter( ImplMap( aTmpCenter) );
+ const sal_uInt16 nAngle = rGradient.GetAngle() % 3600;
+
+ Polygon aPoly( 2 );
+ // Setting x value of a gradient vector to rotation center to
+ // place a gradient vector in a target polygon.
+ // This would help editing it in SVG editors like inkscape.
+ aPoly[ 0 ].X() = aPoly[ 1 ].X() = aCenter.X();
+ aPoly[ 0 ].Y() = aRect.Top();
+ aPoly[ 1 ].Y() = aRect.Bottom();
+ aPoly.Rotate( aCenter, nAngle );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX1, GetValueString( aPoly[ 0
].X() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY1, GetValueString( aPoly[ 0
].Y() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrX2, GetValueString( aPoly[ 1
].X() ) );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrY2, GetValueString( aPoly[ 1
].Y() ) );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrGradientUnits,
+ NMSP_RTL::OUString( RTL_CONSTASCII_USTRINGPARAM(
"userSpaceOnUse" ) ) );
+ }
+
+ {
+ SvXMLElementExport aElemLinearGradient( mrExport, XML_NAMESPACE_NONE,
aXMLElemLinearGradient, TRUE, TRUE );
+
+ const Color aStartColor = ImplGetColorWithIntensity( rGradient.GetStartColor(),
rGradient.GetStartIntensity() );
+ const Color aEndColor = ImplGetColorWithIntensity( rGradient.GetEndColor(),
rGradient.GetEndIntensity() );
+ double fBorderOffset = rGradient.GetBorder() / 100.0;
+ const sal_uInt16 nSteps = rGradient.GetSteps();
+ if( rGradient.GetStyle() == GRADIENT_LINEAR )
+ {
+ // Emulate non-smooth gradient
+ if( 0 < nSteps && nSteps < 100 )
+ {
+ double fOffsetStep = ( 1.0 - fBorderOffset ) / (double)nSteps;
+ for( sal_uInt16 i = 0; i < nSteps; i++ ) {
+ Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i /
(double) nSteps );
+ ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep
);
+ aColor = ImplGetGradientColor( aStartColor, aEndColor, ( i + 1 ) /
(double) nSteps );
+ ImplWriteGradientStop( aColor, fBorderOffset + ( i + 1 ) * fOffsetStep
);
+ }
+ }
+ else
+ {
+ ImplWriteGradientStop( aStartColor, fBorderOffset );
+ ImplWriteGradientStop( aEndColor, 1.0 );
+ }
+ }
+ else
+ {
+ fBorderOffset /= 2;
+ // Emulate non-smooth gradient
+ if( 0 < nSteps && nSteps < 100 )
+ {
+ double fOffsetStep = ( 0.5 - fBorderOffset ) / (double)nSteps;
+ // Upper half
+ for( sal_uInt16 i = 0; i < nSteps; i++ )
+ {
+ Color aColor = ImplGetGradientColor( aEndColor, aStartColor, i /
(double) nSteps );
+ ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
+ aColor = ImplGetGradientColor( aEndColor, aStartColor, (i + 1 ) /
(double) nSteps );
+ ImplWriteGradientStop( aColor, fBorderOffset + i * fOffsetStep );
+ }
+ // Lower half
+ for( sal_uInt16 i = 0; i < nSteps; i++ )
+ {
+ Color aColor = ImplGetGradientColor( aStartColor, aEndColor, i /
(double) nSteps );
+ ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
+ aColor = ImplGetGradientColor( aStartColor, aEndColor, (i + 1 ) /
(double) nSteps );
+ ImplWriteGradientStop( aColor, 0.5 + (i + 1) * fOffsetStep );
+ }
+ }
+ else
+ {
+ ImplWriteGradientStop( aEndColor, fBorderOffset );
+ ImplWriteGradientStop( aStartColor, 0.5 );
+ ImplWriteGradientStop( aEndColor, 1.0 - fBorderOffset );
+ }
+ }
+ }
+ }
+
+ FastString aGradientStyle;
+ aGradientStyle += B2UCONST( "fill:" );
+ aGradientStyle += B2UCONST( "url(#" );
+ aGradientStyle += aGradientId.GetString();
+ aGradientStyle += B2UCONST( ")" );
+
+ {
+ ImplWritePolyPolygon( rPolyPoly, sal_False, &aGradientStyle.GetString() );
+ }
+ }
+}
+
+void SVGActionWriter::ImplWriteGradientStop( const Color& rColor, double fOffset )
+{
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrOffset, NMSP_RTL::OUString::valueOf(
fOffset ) );
+
+ FastString aStyle;
+ aStyle += B2UCONST( "stop-color:" );
+ aStyle += mpContext->GetColorStyle ( rColor );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aStyle.GetString() );
+ {
+ SvXMLElementExport aElemStartStop( mrExport, XML_NAMESPACE_NONE, aXMLElemStop, TRUE, TRUE
);
+ }
+}
+
+Color SVGActionWriter::ImplGetColorWithIntensity( const Color& rColor,
+ sal_uInt16 nIntensity )
+{
+ sal_uInt8 nNewRed = (sal_uInt8)( (long)rColor.GetRed() * nIntensity / 100L );
+ sal_uInt8 nNewGreen = (sal_uInt8)( (long)rColor.GetGreen() * nIntensity / 100L );
+ sal_uInt8 nNewBlue = (sal_uInt8)( (long)rColor.GetBlue() * nIntensity / 100L );
+ return Color( nNewRed, nNewGreen, nNewBlue);
+}
+
+Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
+ const Color& rEndColor,
+ double fOffset )
+{
+ long nRedStep = rEndColor.GetRed() - rStartColor.GetRed();
+ long nNewRed = rStartColor.GetRed() + (long)( nRedStep * fOffset );
+ nNewRed = ( nNewRed < 0 ) ? 0 : ( nNewRed > 0xFF) ? 0xFF : nNewRed;
+
+ long nGreenStep = rEndColor.GetGreen() - rStartColor.GetGreen();
+ long nNewGreen = rStartColor.GetGreen() + (long)( nGreenStep * fOffset );
+ nNewGreen = ( nNewGreen < 0 ) ? 0 : ( nNewGreen > 0xFF) ? 0xFF : nNewGreen;
+
+ long nBlueStep = rEndColor.GetBlue() - rStartColor.GetBlue();
+ long nNewBlue = rStartColor.GetBlue() + (long)( nBlueStep * fOffset );
+ nNewBlue = ( nNewBlue < 0 ) ? 0 : ( nNewBlue > 0xFF) ? 0xFF : nNewBlue;
+
+ return Color( (sal_uInt8)nNewRed, (sal_uInt8)nNewGreen, (sal_uInt8)nNewBlue );
}
// -----------------------------------------------------------------------------
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index 6ec2452..f5928d1 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -140,6 +140,7 @@ public:
virtual ~SVGAttributeWriter();
::rtl::OUString GetFontStyle( const Font& rFont );
+ ::rtl::OUString GetColorStyle( const Color& rColor );
::rtl::OUString GetPaintStyle( const Color& rLineColor, const Color&
rFillColor, const LineInfo* pLineInfo );
void SetFontAttr( const Font& rFont );
@@ -164,6 +165,7 @@ private:
sal_Bool mbClipAttrChanged;
sal_Int32 mnCurClipId;
sal_Int32 mnCurPatternId;
+ sal_Int32 mnCurGradientId;
Stack maContextStack;
VirtualDevice* mpVDev;
MapMode maTargetMapMode;
@@ -186,6 +188,10 @@ private:
void ImplWritePolyPolygon( const PolyPolygon& rPolyPoly,
sal_Bool bLineOnly, const ::rtl::OUString* pStyle = NULL );
void ImplWritePattern( const PolyPolygon& rPolyPoly,
const Hatch* pHatch, const Gradient* pGradient, const ::rtl::OUString* pStyle, sal_uInt32
nWriteFlags );
void ImplWriteGradientEx( const PolyPolygon& rPolyPoly,
const Gradient& rGradient, const ::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
+ void ImplWriteGradientLinear( const PolyPolygon&
rPolyPoly, const Gradient& rGradient );
+ void ImplWriteGradientStop( const Color& rColor, double
fOffset );
+ Color ImplGetColorWithIntensity( const Color& rColor,
USHORT nIntensity );
+ Color ImplGetGradientColor( const Color& rStartColor,
const Color& rEndColor, double fOffset );
void ImplWriteText( const Point& rPos, const String&
rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle = NULL );
void ImplWriteText( const Point& rPos, const String& rText, const sal_Int32*
pDXArray, long nWidth, const ::rtl::OUString* pStyle, Color aTextColor );
void ImplWriteBmp( const BitmapEx& rBmpEx, const Point&
rPt, const Size& rSz, const Point& rSrcPt, const Size& rSrcSz, const ::rtl::OUString* pStyle = NULL
);
@@ -196,6 +202,7 @@ private:
void ImplWriteActions( const GDIMetaFile& rMtf, const
::rtl::OUString* pStyle, sal_uInt32 nWriteFlags );
sal_Int32 ImplGetNextClipId() { return mnCurClipId++; }
sal_Int32 ImplGetNextPatternId() { return mnCurPatternId++; }
+ sal_Int32 ImplGetNextGradientId() { return mnCurGradientId++; }
public:
--
1.7.1
From fc8d029f88c2f7ec67db8122249f23f889a4f707 Mon Sep 17 00:00:00 2001
From: Kurosawa Takeshi <taken.spc@gmail.com>
Date: Fri, 11 Feb 2011 19:29:41 +0900
Subject: [PATCH 3/3] Export transparencies as SVG <mask>s
With this patch, SVG export filter supports solid and gradient tranparencies in all sill styles.
---
filter/source/svg/svgwriter.cxx | 95 +++++++++++++++++++++++++++++---------
filter/source/svg/svgwriter.hxx | 3 +
2 files changed, 75 insertions(+), 23 deletions(-)
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 15a61e7..c3f459b 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -39,6 +39,7 @@
static const char aXMLElemG[] = "g";
static const char aXMLElemDefs[] = "defs";
static const char aXMLElemClipPath[] = "clipPath";
+static const char aXMLElemMask[] = "mask";
static const char aXMLElemPattern[] = "pattern";
static const char aXMLElemLinearGradient[] = "linearGradient";
static const char aXMLElemStop[] = "stop";
@@ -390,7 +391,8 @@ SVGActionWriter::SVGActionWriter( SvXMLExport& rExport, SVGFontExport& rFontExpo
mbClipAttrChanged( sal_False ),
mnCurClipId( 1 ),
mnCurPatternId( 1 ),
- mnCurGradientId( 1 )
+ mnCurGradientId( 1 ),
+ mnCurMaskId( 1 )
{
mpVDev = new VirtualDevice;
mpVDev->EnableOutput( sal_False );
@@ -908,6 +910,73 @@ Color SVGActionWriter::ImplGetGradientColor( const Color& rStartColor,
// -----------------------------------------------------------------------------
+void SVGActionWriter::ImplWriteMask( GDIMetaFile& rMtf,
+ const Point& rDestPt,
+ const Size& rDestSize,
+ const Gradient& rGradient,
+ const NMSP_RTL::OUString* pStyle,
+ sal_uInt32 nWriteFlags )
+{
+ Point aSrcPt( rMtf.GetPrefMapMode().GetOrigin() );
+ const Size aSrcSize( rMtf.GetPrefSize() );
+ const double fScaleX = aSrcSize.Width() ? (double) rDestSize.Width() / aSrcSize.Width() :
1.0;
+ const double fScaleY = aSrcSize.Height() ? (double) rDestSize.Height() / aSrcSize.Height() :
1.0;
+ long nMoveX, nMoveY;
+
+ if( fScaleX != 1.0 || fScaleY != 1.0 )
+ {
+ rMtf.Scale( fScaleX, fScaleY );
+ aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY );
+ }
+
+ nMoveX = rDestPt.X() - aSrcPt.X(), nMoveY = rDestPt.Y() - aSrcPt.Y();
+
+ if( nMoveX || nMoveY )
+ rMtf.Move( nMoveX, nMoveY );
+
+ FastString aMaskId;
+ aMaskId += B2UCONST( "mask" );
+ aMaskId += GetValueString( ImplGetNextMaskId() );
+
+ {
+ SvXMLElementExport aElemDefs( mrExport, XML_NAMESPACE_NONE, aXMLElemDefs, TRUE, TRUE );
+
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrId, aMaskId.GetString() );
+ {
+ SvXMLElementExport aElemMask( mrExport, XML_NAMESPACE_NONE, aXMLElemMask, TRUE, TRUE );
+
+ const PolyPolygon aPolyPolygon( PolyPolygon( Rectangle( rDestPt, rDestSize ) ) );
+ Gradient aGradient( rGradient );
+
+ // swap gradient stops to adopt SVG mask
+ Color aTmpColor( aGradient.GetStartColor() );
+ sal_uInt16 nTmpIntensity( aGradient.GetStartIntensity() );
+ aGradient.SetStartColor( aGradient.GetEndColor() );
+ aGradient.SetStartIntensity( aGradient.GetEndIntensity() ) ;
+ aGradient.SetEndColor( aTmpColor );
+ aGradient.SetEndIntensity( nTmpIntensity );
+
+ ImplWriteGradientEx( aPolyPolygon, aGradient, pStyle, nWriteFlags );
+ }
+ }
+
+ FastString aMaskStyle;
+ aMaskStyle += B2UCONST( "mask:url(#" );
+ aMaskStyle += aMaskId.GetString();
+ aMaskStyle += B2UCONST( ")" );
+ mrExport.AddAttribute( XML_NAMESPACE_NONE, aXMLAttrStyle, aMaskStyle.GetString() );
+
+ {
+ SvXMLElementExport aElemG( mrExport, XML_NAMESPACE_NONE, aXMLElemG, TRUE, TRUE );
+
+ mpVDev->Push();
+ ImplWriteActions( rMtf, pStyle, nWriteFlags );
+ mpVDev->Pop();
+ }
+}
+
+// -----------------------------------------------------------------------------
+
void SVGActionWriter::ImplWriteText( const Point& rPos, const String& rText,
const sal_Int32* pDXArray, long nWidth,
const NMSP_RTL::OUString* pStyle )
@@ -1508,28 +1577,8 @@ void SVGActionWriter::ImplWriteActions( const GDIMetaFile& rMtf,
{
const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*)
pAction;
GDIMetaFile aTmpMtf(
pA->GetGDIMetaFile() );
- Point aSrcPt(
aTmpMtf.GetPrefMapMode().GetOrigin() );
- const Size aSrcSize(
aTmpMtf.GetPrefSize() );
- const Point aDestPt(
pA->GetPoint() );
- const Size aDestSize(
pA->GetSize() );
- const double fScaleX =
aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0;
- const double fScaleY =
aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0;
- long nMoveX,
nMoveY;
-
- if( fScaleX != 1.0 || fScaleY != 1.0 )
- {
- aTmpMtf.Scale( fScaleX, fScaleY );
- aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound(
aSrcPt.Y() * fScaleY );
- }
-
- nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y();
-
- if( nMoveX || nMoveY )
- aTmpMtf.Move( nMoveX, nMoveY );
-
- mpVDev->Push();
- ImplWriteActions( aTmpMtf, pStyle, nWriteFlags );
- mpVDev->Pop();
+ ImplWriteMask( aTmpMtf, pA->GetPoint(), pA->GetSize(),
+ pA->GetGradient(), pStyle, nWriteFlags );
}
}
break;
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index f5928d1..26470af 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -166,6 +166,7 @@ private:
sal_Int32 mnCurClipId;
sal_Int32 mnCurPatternId;
sal_Int32 mnCurGradientId;
+ sal_Int32 mnCurMaskId;
Stack maContextStack;
VirtualDevice* mpVDev;
MapMode maTargetMapMode;
@@ -192,6 +193,7 @@ private:
void ImplWriteGradientStop( const Color& rColor, double
fOffset );
Color ImplGetColorWithIntensity( const Color& rColor,
USHORT nIntensity );
Color ImplGetGradientColor( const Color& rStartColor,
const Color& rEndColor, double fOffset );
+ void ImplWriteMask( GDIMetaFile& rMtf, const Point&
rDestPt, const Size& rDestSize, const Gradient& rGradient, const ::rtl::OUString* pStyle,
sal_uInt32 nWriteFlags );
void ImplWriteText( const Point& rPos, const String&
rText, const sal_Int32* pDXArray, long nWidth, const ::rtl::OUString* pStyle = NULL );
void ImplWriteText( const Point& rPos, const String& rText, const sal_Int32*
pDXArray, long nWidth, const ::rtl::OUString* pStyle, Color aTextColor );
void ImplWriteBmp( const BitmapEx& rBmpEx, const Point&
rPt, const Size& rSz, const Point& rSrcPt, const Size& rSrcSz, const ::rtl::OUString* pStyle = NULL
);
@@ -203,6 +205,7 @@ private:
sal_Int32 ImplGetNextClipId() { return mnCurClipId++; }
sal_Int32 ImplGetNextPatternId() { return mnCurPatternId++; }
sal_Int32 ImplGetNextGradientId() { return mnCurGradientId++; }
+ sal_Int32 ImplGetNextMaskId() { return mnCurMaskId++; }
public:
--
1.7.1
Context
Privacy Policy |
Impressum (Legal Info) |
Copyright information: Unless otherwise specified, all text and images
on this website are licensed under the
Creative Commons Attribution-Share Alike 3.0 License.
This does not include the source code of LibreOffice, which is
licensed under the Mozilla Public License (
MPLv2).
"LibreOffice" and "The Document Foundation" are
registered trademarks of their corresponding registered owners or are
in actual use as trademarks in one or more countries. Their respective
logos and icons are also subject to international copyright laws. Use
thereof is explained in our
trademark policy.