Created
January 11, 2013 09:05
-
-
Save msteiger/4509119 to your computer and use it in GitHub Desktop.
An ExtensionHandler for Apache Batik's svggen part that uses SVGGraphics2D to convert Swing drawing routines to SVG elements. Currently supports LinearGradientPaint and RadialGradientPaint. Feel free to comment and extend ..
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import static org.apache.batik.util.SVGConstants.*; | |
import java.awt.Color; | |
import java.awt.LinearGradientPaint; | |
import java.awt.MultipleGradientPaint; | |
import java.awt.Paint; | |
import java.awt.RadialGradientPaint; | |
import java.awt.geom.AffineTransform; | |
import java.awt.geom.Point2D; | |
import org.apache.batik.svggen.DefaultExtensionHandler; | |
import org.apache.batik.svggen.SVGColor; | |
import org.apache.batik.svggen.SVGGeneratorContext; | |
import org.apache.batik.svggen.SVGPaintDescriptor; | |
import org.w3c.dom.Element; | |
/** | |
* Extension of Batik's {@link DefaultExtensionHandler} which | |
* handles different kinds of Paint objects | |
* | |
* I wonder why this is not part of the svggen library. | |
* @author Martin Steiger | |
*/ | |
public class GradientExtensionHandler extends DefaultExtensionHandler | |
{ | |
@Override | |
public SVGPaintDescriptor handlePaint(Paint paint, SVGGeneratorContext genCtx) | |
{ | |
// Handle LinearGradientPaint | |
if (paint instanceof LinearGradientPaint) | |
return getLgpDescriptor((LinearGradientPaint) paint, genCtx); | |
// Handle RadialGradientPaint | |
if (paint instanceof RadialGradientPaint) | |
return getRgpDescriptor((RadialGradientPaint) paint, genCtx); | |
return super.handlePaint(paint, genCtx); | |
} | |
private SVGPaintDescriptor getRgpDescriptor(RadialGradientPaint gradient, SVGGeneratorContext genCtx) | |
{ | |
Element gradElem = genCtx.getDOMFactory().createElementNS(SVG_NAMESPACE_URI, SVG_RADIAL_GRADIENT_TAG); | |
// Create and set unique XML id | |
String id = genCtx.getIDGenerator().generateID("gradient"); | |
gradElem.setAttribute(SVG_ID_ATTRIBUTE, id); | |
// Set x,y pairs | |
Point2D centerPt = gradient.getCenterPoint(); | |
gradElem.setAttribute("cx", String.valueOf(centerPt.getX())); | |
gradElem.setAttribute("cy", String.valueOf(centerPt.getY())); | |
Point2D focusPt = gradient.getFocusPoint(); | |
gradElem.setAttribute("fx", String.valueOf(focusPt.getX())); | |
gradElem.setAttribute("fy", String.valueOf(focusPt.getY())); | |
gradElem.setAttribute("r", String.valueOf(gradient.getRadius())); | |
addMgpAttributes(gradElem, genCtx, gradient); | |
return new SVGPaintDescriptor("url(#" + id + ")", SVG_OPAQUE_VALUE, gradElem); | |
} | |
private SVGPaintDescriptor getLgpDescriptor(LinearGradientPaint gradient, SVGGeneratorContext genCtx) | |
{ | |
Element gradElem = genCtx.getDOMFactory().createElementNS(SVG_NAMESPACE_URI, SVG_LINEAR_GRADIENT_TAG); | |
// Create and set unique XML id | |
String id = genCtx.getIDGenerator().generateID("gradient"); | |
gradElem.setAttribute(SVG_ID_ATTRIBUTE, id); | |
// Set x,y pairs | |
Point2D startPt = gradient.getStartPoint(); | |
gradElem.setAttribute("x1", String.valueOf(startPt.getX())); | |
gradElem.setAttribute("y1", String.valueOf(startPt.getY())); | |
Point2D endPt = gradient.getEndPoint(); | |
gradElem.setAttribute("x2", String.valueOf(endPt.getX())); | |
gradElem.setAttribute("y2", String.valueOf(endPt.getY())); | |
addMgpAttributes(gradElem, genCtx, gradient); | |
return new SVGPaintDescriptor("url(#" + id + ")", SVG_OPAQUE_VALUE, gradElem); | |
} | |
private void addMgpAttributes(Element gradElem, SVGGeneratorContext genCtx, MultipleGradientPaint gradient) | |
{ | |
gradElem.setAttribute(SVG_GRADIENT_UNITS_ATTRIBUTE, SVG_USER_SPACE_ON_USE_VALUE); | |
// Set cycle method | |
switch (gradient.getCycleMethod()) | |
{ | |
case REFLECT: | |
gradElem.setAttribute(SVG_SPREAD_METHOD_ATTRIBUTE, SVG_REFLECT_VALUE); | |
break; | |
case REPEAT: | |
gradElem.setAttribute(SVG_SPREAD_METHOD_ATTRIBUTE, SVG_REPEAT_VALUE); | |
break; | |
case NO_CYCLE: | |
gradElem.setAttribute(SVG_SPREAD_METHOD_ATTRIBUTE, SVG_PAD_VALUE); // this is the default | |
break; | |
} | |
// Set color space | |
switch (gradient.getColorSpace()) | |
{ | |
case LINEAR_RGB: | |
gradElem.setAttribute(SVG_COLOR_INTERPOLATION_ATTRIBUTE, SVG_LINEAR_RGB_VALUE); | |
break; | |
case SRGB: | |
gradElem.setAttribute(SVG_COLOR_INTERPOLATION_ATTRIBUTE, SVG_SRGB_VALUE); | |
break; | |
} | |
// Set transform matrix if not identity | |
AffineTransform tf = gradient.getTransform(); | |
if (!tf.isIdentity()) | |
{ | |
String matrix = "matrix(" + | |
tf.getScaleX() + " " + tf.getShearX() + " " + tf.getTranslateX() + " " + | |
tf.getScaleY() + " " + tf.getShearY() + " " + tf.getTranslateY() + ")"; | |
gradElem.setAttribute(SVG_TRANSFORM_ATTRIBUTE, matrix); | |
} | |
// Convert gradient stops | |
Color[] colors = gradient.getColors(); | |
float[] fracs = gradient.getFractions(); | |
for (int i = 0; i < colors.length; i++) | |
{ | |
Element stop = genCtx.getDOMFactory().createElementNS(SVG_NAMESPACE_URI, SVG_STOP_TAG); | |
SVGPaintDescriptor pd = SVGColor.toSVG(colors[i], genCtx); | |
stop.setAttribute(SVG_OFFSET_ATTRIBUTE, (int) (fracs[i] * 100.0f) + "%"); | |
stop.setAttribute(SVG_STOP_COLOR_ATTRIBUTE, pd.getPaintValue()); | |
if (colors[i].getAlpha() != 255) | |
{ | |
stop.setAttribute(SVG_STOP_OPACITY_ATTRIBUTE, pd.getOpacityValue()); | |
} | |
gradElem.appendChild(stop); | |
} | |
} | |
} |
hello Martin,
I fixed my problem with this change in the transform (transform->gradientTransform, change order of parameters):
fnatter/svgtest@bb5b87a
Could you review this?
Cheers and Best Regards,
Felix
hi Martin,
with the above change it seems to work fine :-)
Can I use this code in the Freeplane project under the GPL (or less restrictive, like Apache/Mozilla/...) conditions?
Cheers and Best Regards,
Felix
Hello, sorry, I didn't see your comments until now. You can use the code under the MIT license if it is still relevant for you.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hello Martin,
I find your batik ExtensionHandler for java.awt.(Linear|Radial)GradientPaint very useful, as I am part of the
freeplane project where we render SVGs using svgSalamander which generates these "Multiple" GradientPaints.
Setting your "GradientExtensionHandler" as an ExtensionHandler does improve things
(better color rendering), but gradients are still not rendered completely.
Here is a simple example (including use of "GradientExtensionHandler"):
https://github.com/fnatter/svgtest
In order to test this, please do:
Could you help me fix this?
Many Thanks and Best Regards,
Felix