com.googlecode.blaisemath.graphics.svg.SVGElementGraphicConverter Maven / Gradle / Ivy
/**
* SVGElementGraphicConverter.java
* Created Sep 27, 2014
*/
package com.googlecode.blaisemath.graphics.svg;
/*
* #%L
* BlaiseSVG
* --
* Copyright (C) 2014 - 2017 Elisha Peterson
* --
* Licensed 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.google.common.base.Converter;
import com.google.common.base.Strings;
import com.googlecode.blaisemath.graphics.core.Graphic;
import com.googlecode.blaisemath.graphics.core.GraphicComposite;
import com.googlecode.blaisemath.graphics.core.PrimitiveArrayGraphicSupport;
import com.googlecode.blaisemath.graphics.core.PrimitiveGraphicSupport;
import com.googlecode.blaisemath.graphics.swing.JGraphicComponent;
import com.googlecode.blaisemath.graphics.swing.JGraphics;
import com.googlecode.blaisemath.graphics.swing.LabeledShapeGraphic;
import com.googlecode.blaisemath.graphics.swing.PanAndZoomHandler;
import com.googlecode.blaisemath.graphics.swing.TextRenderer;
import com.googlecode.blaisemath.graphics.swing.WrappedTextRenderer;
import com.googlecode.blaisemath.style.AttributeSet;
import com.googlecode.blaisemath.style.AttributeSets;
import com.googlecode.blaisemath.style.ObjectStyler;
import com.googlecode.blaisemath.style.Renderer;
import com.googlecode.blaisemath.style.Styles;
import com.googlecode.blaisemath.style.xml.AttributeSetAdapter;
import com.googlecode.blaisemath.svg.SVGCircle;
import com.googlecode.blaisemath.svg.SVGElement;
import com.googlecode.blaisemath.svg.SVGElements;
import com.googlecode.blaisemath.svg.SVGEllipse;
import com.googlecode.blaisemath.svg.SVGGroup;
import com.googlecode.blaisemath.svg.SVGImage;
import com.googlecode.blaisemath.svg.SVGLine;
import com.googlecode.blaisemath.svg.SVGPath;
import com.googlecode.blaisemath.svg.SVGPolygon;
import com.googlecode.blaisemath.svg.SVGPolyline;
import com.googlecode.blaisemath.svg.SVGRectangle;
import com.googlecode.blaisemath.svg.SVGRoot;
import com.googlecode.blaisemath.svg.SVGText;
import com.googlecode.blaisemath.util.AnchoredIcon;
import com.googlecode.blaisemath.util.AnchoredImage;
import com.googlecode.blaisemath.util.AnchoredText;
import com.googlecode.blaisemath.util.Colors;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.RectangularShape;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
/**
* Adapter for converting SVG objects to/from Blaise {@link PrimitiveGraphicSupport} objects.
* The conversion is imperfect in this implementation. Supported SVG types include:
*
* - {@link SVGRectangle}, {@link SVGEllipse}, {@link SVGCircle}, {@link SVGPolygon}
* - {@link SVGLine}, {@link SVGPolyline}
* - {@link SVGPath}
* - {@link SVGImage}
* - {@link SVGText}
* - {@link SVGGroup}
*
* This adapter also converts {@link SVGGroup} to/from {@link GraphicComposite}.
*
* @author elisha
*/
public class SVGElementGraphicConverter extends Converter> {
private static final Logger LOG = Logger.getLogger(SVGElementGraphicConverter.class.getName());
private static final SVGElementGraphicConverter INST = new SVGElementGraphicConverter();
/**
* Get global instance of the converter.
* @return instance
*/
public static Converter> getInstance() {
return INST;
}
/**
* Convert a graphic component to an SVG object, including a view box.
* @param compt component to convert
* @return result
*/
public static SVGRoot componentToSvg(JGraphicComponent compt) {
SVGRoot root = new SVGRoot();
root.setWidth(compt.getWidth());
root.setHeight(compt.getHeight());
root.setViewBox(PanAndZoomHandler.getLocalBounds(compt));
root.getStyle().put("background", Colors.stringConverter().convert(compt.getBackground()));
root.getStyle().put(Styles.FONT_SIZE, Styles.DEFAULT_TEXT_STYLE.get(Styles.FONT_SIZE));
SVGGroup group = (SVGGroup) SVGElementGraphicConverter.getInstance().reverse()
.convert(compt.getGraphicRoot());
group.getElements().forEach(root::addElement);
return root;
}
/**
* Convert an {@link SVGElement} to a {@link Graphic}. The resulting object will
* be a {@link GraphicComposite} if the argument is an instance of {@link SVGGroup}
* or {@link SVGRoot}, and otherwise a {@link PrimitiveGraphicSupport}. In the case of
* a group, recursive calls are made to convert all elements in the group.
*
* @param sh the element to convert
* @return the corresponding graphic
*/
@Override
public Graphic doForward(SVGElement sh) {
Graphic prim = null;
AttributeSet style = aggregateStyle(sh);
if (sh instanceof SVGRectangle) {
RectangularShape rsh = SVGRectangle.shapeConverter().convert((SVGRectangle) sh);
prim = JGraphics.shape(rsh, style);
} else if (sh instanceof SVGEllipse) {
Shape rsh = SVGEllipse.shapeConverter().convert((SVGEllipse) sh);
prim = JGraphics.shape(rsh, style);
} else if (sh instanceof SVGCircle) {
Shape rsh = SVGCircle.shapeConverter().convert((SVGCircle) sh);
prim = JGraphics.shape(rsh, style);
} else if (sh instanceof SVGPolygon) {
Shape rsh = SVGPolygon.shapeConverter().convert((SVGPolygon) sh);
prim = JGraphics.shape(rsh, style);
} else if (sh instanceof SVGLine) {
Line2D line = SVGLine.shapeConverter().convert((SVGLine) sh);
prim = JGraphics.path(line, style);
} else if (sh instanceof SVGPolyline) {
Shape rsh = SVGPolyline.shapeConverter().convert((SVGPolyline) sh);
prim = JGraphics.shape(rsh, style);
} else if (sh instanceof SVGPath) {
Shape rsh = SVGPath.shapeConverter().convert((SVGPath) sh);
prim = JGraphics.shape(rsh, style);
} else if (sh instanceof SVGImage) {
AnchoredImage img = SVGImage.imageConverter().convert((SVGImage) sh);
prim = JGraphics.image(img);
prim.setMouseEnabled(false);
} else if (sh instanceof SVGText) {
AnchoredText text = SVGText.textConverter().convert((SVGText) sh);
prim = JGraphics.text(text, style);
prim.setMouseEnabled(false);
} else if (sh instanceof SVGGroup || sh instanceof SVGRoot) {
prim = new GraphicComposite();
((GraphicComposite)prim).setStyle(style);
for (SVGElement el : ((SVGGroup)sh).getElements()) {
((GraphicComposite)prim).addGraphic(doForward(el));
}
} else {
throw new IllegalStateException("Unexpected SVG element: "+sh);
}
prim.setDefaultTooltip(sh.getId());
return prim;
}
private AttributeSet aggregateStyle(SVGElement element) {
AttributeSet shapeStyle = element.getStyle();
AttributeSet res = shapeStyle == null
? new AttributeSet()
: shapeStyle.copy();
Map attr = element.getOtherAttributes();
if (attr != null) {
for (Entry en : attr.entrySet()) {
Object val = AttributeSets.valueFromString((String) en.getValue());
res.put(en.getKey().toString(), val);
}
}
if (element.getId() != null) {
res.put(Styles.ID, element.getId());
}
AttributeSetAdapter.updateColorFields(res);
return res;
}
@Override
public SVGElement doBackward(Graphic v) {
return graphicToSvg(v);
}
//
/** Converts a graphic element to an SVG element */
private static SVGElement graphicToSvg(Graphic v) {
SVGElement res = null;
if (v instanceof LabeledShapeGraphic) {
res = labeledShapeToSvg((LabeledShapeGraphic) v);
} else if (v instanceof PrimitiveGraphicSupport) {
PrimitiveGraphicSupport pgs = (PrimitiveGraphicSupport) v;
res = primitiveStyleToSvg(pgs.getPrimitive(), v.getStyle(), pgs.getRenderer());
} else if (v instanceof GraphicComposite) {
res = compositeToSvg((GraphicComposite) v);
} else if (v instanceof PrimitiveArrayGraphicSupport) {
res = primitiveArrayToSvg((PrimitiveArrayGraphicSupport) v);
} else {
throw new IllegalArgumentException("Graphic conversion not supported for "+v.getClass());
}
String id = v.renderStyle().getString(Styles.ID, null);
if (id != null && res != null) {
res.setId(id);
}
if (res != null && res.getStyle() != null && res.getStyle().getAttributes().isEmpty()) {
res.setStyle(null);
}
if (res != null && res.getStyle() != null) {
for (String c : res.getStyle().getAttributes()) {
Object col = res.getStyle().get(c);
if (col instanceof Color) {
res.getStyle().put(c, Colors.alpha((Color) col, 255));
}
}
}
return res;
}
/** Converts a blaise composite to an SVG group */
private static SVGElement compositeToSvg(GraphicComposite gc) {
SVGGroup grp = new SVGGroup();
if (gc.getStyle() != null) {
grp.setStyle(AttributeSet.create(gc.getStyle().getAttributeMap()));
}
for (Graphic g : gc.getGraphics()) {
try {
SVGElement el = graphicToSvg(g);
if (el != null) {
grp.addElement(el);
} else {
LOG.log(Level.WARNING, "Null graphic for {0}", g);
}
} catch (IllegalArgumentException x) {
LOG.log(Level.WARNING, "Graphic not added to result", x);
}
}
return grp;
}
/** Converts a blaise array graphic to SVG group */
private static SVGElement primitiveArrayToSvg(PrimitiveArrayGraphicSupport pags) {
SVGGroup grp = new SVGGroup();
grp.setStyle(pags.renderStyle().flatCopy());
for (Object o : pags.getPrimitive()) {
grp.addElement(primitiveStyleToSvg(o, pags.renderStyle().flatCopy(), pags.getRenderer()));
}
return grp;
}
/** Creates an SVG element from given primitive/style */
private static SVGElement primitiveStyleToSvg(Object primitive, AttributeSet sty, Renderer rend) {
if (primitive instanceof Shape) {
return SVGElements.create(null, (Shape) primitive, sty);
} else if (primitive instanceof AnchoredText) {
return SVGElements.create(null, (AnchoredText) primitive, sty, rend);
} else if (primitive instanceof AnchoredImage) {
return SVGElements.create(null, (AnchoredImage) primitive, sty);
} else if (primitive instanceof AnchoredIcon) {
return SVGElements.create(null, (AnchoredIcon) primitive, sty);
} else if (primitive instanceof Point2D) {
return SVGElements.create(null, (Point2D) primitive, sty);
} else {
throw new IllegalArgumentException("Graphic conversion not supported for primitive "+primitive);
}
}
/** Converts a labeled shape to svg */
private static SVGElement labeledShapeToSvg(LabeledShapeGraphic gfc) {
SVGElement shape = primitiveStyleToSvg(gfc.getPrimitive(), gfc.renderStyle().flatCopy(), gfc.getRenderer());
SVGElement text = labelToSvg(gfc);
return text == null ? shape : SVGGroup.create(shape, text);
}
/** Generates element for object label */
private static SVGElement labelToSvg(LabeledShapeGraphic gfc) {
ObjectStyler styler = gfc.getObjectStyler();
if (styler == null) {
return null;
}
String label = styler.label(gfc.getSourceObject());
AttributeSet style = styler.labelStyle(gfc.getSourceObject());
if (Strings.isNullOrEmpty(label) || style == null) {
return null;
}
Renderer textRend = gfc.getTextRenderer();
if (textRend instanceof WrappedTextRenderer) {
return SVGElements.createWrappedText(label, style, LabeledShapeGraphic.wrappedLabelBounds(gfc.getPrimitive()));
} else if (textRend instanceof TextRenderer) {
return primitiveStyleToSvg(new AnchoredText(label), style.flatCopy(), textRend);
} else {
LOG.log(Level.WARNING, "Unsupported text renderer: {0}", textRend);
return null;
}
}
//
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy