com.cburch.draw.shapes.SvgReader.java Source code

Java tutorial

Introduction

Here is the source code for com.cburch.draw.shapes.SvgReader.java

Source

/* Copyright (c) 2010, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */

package com.cburch.draw.shapes;

import java.awt.Color;
import java.awt.Font;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.collections15.list.UnmodifiableList;
import org.w3c.dom.Element;

import com.cburch.draw.model.AbstractCanvasObject;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeOption;
import com.cburch.logisim.data.Location;

public class SvgReader {
    private SvgReader() {
    }

    private static final Pattern PATH_REGEX = Pattern.compile("[a-zA-Z]|[-0-9.]+");

    public static AbstractCanvasObject createShape(Element elt) {
        String name = elt.getTagName();
        AbstractCanvasObject ret;
        if (name.equals("ellipse")) {
            ret = createOval(elt);
        } else if (name.equals("line")) {
            ret = createLine(elt);
        } else if (name.equals("path")) {
            ret = createPath(elt);
        } else if (name.equals("polyline")) {
            ret = createPolyline(elt);
        } else if (name.equals("polygon")) {
            ret = createPolygon(elt);
        } else if (name.equals("rect")) {
            ret = createRectangle(elt);
        } else if (name.equals("text")) {
            ret = createText(elt);
        } else {
            return null;
        }
        List<Attribute<?>> attrs = ret.getAttributes();
        if (attrs.contains(DrawAttr.PAINT_TYPE)) {
            String stroke = elt.getAttribute("stroke");
            String fill = elt.getAttribute("fill");
            if (stroke.equals("") || stroke.equals("none")) {
                ret.setValue(DrawAttr.PAINT_TYPE, DrawAttr.PAINT_FILL);
            } else if (fill.equals("none")) {
                ret.setValue(DrawAttr.PAINT_TYPE, DrawAttr.PAINT_STROKE);
            } else {
                ret.setValue(DrawAttr.PAINT_TYPE, DrawAttr.PAINT_STROKE_FILL);
            }
        }
        attrs = ret.getAttributes(); // since changing paintType could change it
        if (attrs.contains(DrawAttr.STROKE_WIDTH) && elt.hasAttribute("stroke-width")) {
            Integer width = Integer.valueOf(elt.getAttribute("stroke-width"));
            ret.setValue(DrawAttr.STROKE_WIDTH, width);
        }
        if (attrs.contains(DrawAttr.STROKE_COLOR)) {
            String color = elt.getAttribute("stroke");
            String opacity = elt.getAttribute("stroke-opacity");
            if (!color.equals("none")) {
                ret.setValue(DrawAttr.STROKE_COLOR, getColor(color, opacity));
            }
        }
        if (attrs.contains(DrawAttr.FILL_COLOR)) {
            String color = elt.getAttribute("fill");
            if (color.equals(""))
                color = "#000000";
            String opacity = elt.getAttribute("fill-opacity");
            if (!color.equals("none")) {
                ret.setValue(DrawAttr.FILL_COLOR, getColor(color, opacity));
            }
        }
        return ret;
    }

    private static AbstractCanvasObject createRectangle(Element elt) {
        int x = Integer.parseInt(elt.getAttribute("x"));
        int y = Integer.parseInt(elt.getAttribute("y"));
        int w = Integer.parseInt(elt.getAttribute("width"));
        int h = Integer.parseInt(elt.getAttribute("height"));
        if (elt.hasAttribute("rx")) {
            AbstractCanvasObject ret = new RoundRectangle(x, y, w, h);
            int rx = Integer.parseInt(elt.getAttribute("rx"));
            ret.setValue(DrawAttr.CORNER_RADIUS, Integer.valueOf(rx));
            return ret;
        } else {
            return new Rectangle(x, y, w, h);
        }
    }

    private static AbstractCanvasObject createOval(Element elt) {
        double cx = Double.parseDouble(elt.getAttribute("cx"));
        double cy = Double.parseDouble(elt.getAttribute("cy"));
        double rx = Double.parseDouble(elt.getAttribute("rx"));
        double ry = Double.parseDouble(elt.getAttribute("ry"));
        int x = (int) Math.round(cx - rx);
        int y = (int) Math.round(cy - ry);
        int w = (int) Math.round(rx * 2);
        int h = (int) Math.round(ry * 2);
        return new Oval(x, y, w, h);
    }

    private static AbstractCanvasObject createLine(Element elt) {
        int x0 = Integer.parseInt(elt.getAttribute("x1"));
        int y0 = Integer.parseInt(elt.getAttribute("y1"));
        int x1 = Integer.parseInt(elt.getAttribute("x2"));
        int y1 = Integer.parseInt(elt.getAttribute("y2"));
        return new Line(x0, y0, x1, y1);
    }

    private static AbstractCanvasObject createPolygon(Element elt) {
        return new Poly(true, parsePoints(elt.getAttribute("points")));
    }

    private static AbstractCanvasObject createPolyline(Element elt) {
        return new Poly(false, parsePoints(elt.getAttribute("points")));
    }

    private static AbstractCanvasObject createText(Element elt) {
        int x = Integer.parseInt(elt.getAttribute("x"));
        int y = Integer.parseInt(elt.getAttribute("y"));
        String text = elt.getTextContent();
        Text ret = new Text(x, y, text);

        String fontFamily = elt.getAttribute("font-family");
        String fontStyle = elt.getAttribute("font-style");
        String fontWeight = elt.getAttribute("font-weight");
        String fontSize = elt.getAttribute("font-size");
        int styleFlags = 0;
        if (fontStyle.equals("italic"))
            styleFlags |= Font.ITALIC;
        if (fontWeight.equals("bold"))
            styleFlags |= Font.BOLD;
        int size = Integer.parseInt(fontSize);
        ret.setValue(DrawAttr.FONT, new Font(fontFamily, styleFlags, size));

        String alignStr = elt.getAttribute("text-anchor");
        AttributeOption halign;
        if (alignStr.equals("start")) {
            halign = DrawAttr.ALIGN_LEFT;
        } else if (alignStr.equals("end")) {
            halign = DrawAttr.ALIGN_RIGHT;
        } else {
            halign = DrawAttr.ALIGN_CENTER;
        }
        ret.setValue(DrawAttr.ALIGNMENT, halign);

        // fill color is handled after we return
        return ret;
    }

    private static List<Location> parsePoints(String points) {
        Pattern patt = Pattern.compile("[ ,\n\r\t]+");
        String[] toks = patt.split(points);
        Location[] ret = new Location[toks.length / 2];
        for (int i = 0; i < ret.length; i++) {
            int x = Integer.parseInt(toks[2 * i]);
            int y = Integer.parseInt(toks[2 * i + 1]);
            ret[i] = Location.create(x, y);
        }
        return UnmodifiableList.decorate(Arrays.asList(ret));
    }

    private static AbstractCanvasObject createPath(Element elt) {
        Matcher patt = PATH_REGEX.matcher(elt.getAttribute("d"));
        List<String> tokens = new ArrayList<String>();
        int type = -1; // -1 error, 0 start, 1 curve, 2 polyline
        while (patt.find()) {
            String token = patt.group();
            tokens.add(token);
            if (Character.isLetter(token.charAt(0))) {
                switch (token.charAt(0)) {
                case 'M':
                    if (type == -1)
                        type = 0;
                    else
                        type = -1;
                    break;
                case 'Q':
                case 'q':
                    if (type == 0)
                        type = 1;
                    else
                        type = -1;
                    break;
                /* not supported
                case 'L': case 'l':
                case 'H': case 'h':
                case 'V': case 'v':
                   if (type == 0 || type == 2) type = 2;
                   else type = -1;
                   break;
                */
                default:
                    type = -1;
                }
                if (type == -1) {
                    throw new NumberFormatException("Unrecognized path command '" + token.charAt(0) + "'");
                }
            }
        }

        if (type == 1) {
            if (tokens.size() == 8 && tokens.get(0).equals("M") && tokens.get(3).toUpperCase().equals("Q")) {
                int x0 = Integer.parseInt(tokens.get(1));
                int y0 = Integer.parseInt(tokens.get(2));
                int x1 = Integer.parseInt(tokens.get(4));
                int y1 = Integer.parseInt(tokens.get(5));
                int x2 = Integer.parseInt(tokens.get(6));
                int y2 = Integer.parseInt(tokens.get(7));
                if (tokens.get(3).equals("q")) {
                    x1 += x0;
                    y1 += y0;
                    x2 += x0;
                    y2 += y0;
                }
                Location e0 = Location.create(x0, y0);
                Location e1 = Location.create(x2, y2);
                Location ct = Location.create(x1, y1);
                return new Curve(e0, e1, ct);
            } else {
                throw new NumberFormatException("Unexpected format for curve");
            }
        } else {
            throw new NumberFormatException("Unrecognized path");
        }
    }

    private static Color getColor(String hue, String opacity) {
        int r;
        int g;
        int b;
        if (hue == null || hue.equals("")) {
            r = 0;
            g = 0;
            b = 0;
        } else {
            r = Integer.parseInt(hue.substring(1, 3), 16);
            g = Integer.parseInt(hue.substring(3, 5), 16);
            b = Integer.parseInt(hue.substring(5, 7), 16);
        }
        int a;
        if (opacity == null || opacity.equals("")) {
            a = 255;
        } else {
            double x;
            try {
                x = Double.parseDouble(opacity);
            } catch (NumberFormatException e) {
                // some localizations use commas for decimal points
                int comma = opacity.lastIndexOf(',');
                if (comma >= 0) {
                    try {
                        String repl = opacity.substring(0, comma) + "." + opacity.substring(comma + 1);
                        x = Double.parseDouble(repl);
                    } catch (Throwable t) {
                        throw e;
                    }
                } else {
                    throw e;
                }
            }
            a = (int) Math.round(x * 255);
        }
        return new Color(r, g, b, a);
    }
}