mirror of
https://github.com/SimpleMobileTools/Simple-Draw.git
synced 2025-03-26 00:20:12 +01:00
Merge pull request #51 from XyLoNaMiyX/master
Allow opening existing .svg files
This commit is contained in:
commit
c99b6a0935
app/src/main/java/com/simplemobiletools/draw
@ -98,6 +98,11 @@ public class MyCanvas extends View {
|
|||||||
return mPaths;
|
return mPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addPath(MyPath path, PaintOptions options) {
|
||||||
|
mPaths.put(path, options);
|
||||||
|
pathsUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDraw(Canvas canvas) {
|
protected void onDraw(Canvas canvas) {
|
||||||
super.onDraw(canvas);
|
super.onDraw(canvas);
|
||||||
|
@ -10,6 +10,7 @@ import com.simplemobiletools.draw.actions.Quad;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -26,12 +27,47 @@ class MyPath extends Path implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void readObject(String pathData) throws InvalidParameterException {
|
||||||
|
String[] tokens = pathData.split("\\s+");
|
||||||
|
for (int i = 0; i < tokens.length; ++i) {
|
||||||
|
switch (tokens[i].charAt(0)) {
|
||||||
|
case 'M':
|
||||||
|
addAction(new Move(tokens[i]));
|
||||||
|
break;
|
||||||
|
case 'L':
|
||||||
|
addAction(new Line(tokens[i]));
|
||||||
|
break;
|
||||||
|
case 'Q':
|
||||||
|
// Quad actions are of the following form:
|
||||||
|
// "Qx1,y1 x2,y2"
|
||||||
|
// Since we split the tokens by whitespace, we need to join them again
|
||||||
|
if (i+1 >= tokens.length)
|
||||||
|
throw new InvalidParameterException("Error parsing the data for a Quad.");
|
||||||
|
|
||||||
|
addAction(new Quad(tokens[i]+" "+tokens[i+1]));
|
||||||
|
++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
actions.clear();
|
actions.clear();
|
||||||
super.reset();
|
super.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addAction(Action action) {
|
||||||
|
if (action instanceof Move) {
|
||||||
|
moveTo(((Move)action).x, ((Move)action).y);
|
||||||
|
} else if (action instanceof Line) {
|
||||||
|
lineTo(((Line)action).x, ((Line)action).y);
|
||||||
|
} else if (action instanceof Quad) {
|
||||||
|
final Quad q = (Quad)action;
|
||||||
|
quadTo(q.x1, q.y1, q.x2, q.y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moveTo(float x, float y) {
|
public void moveTo(float x, float y) {
|
||||||
actions.add(new Move(x, y));
|
actions.add(new Move(x, y));
|
||||||
|
@ -1,18 +1,32 @@
|
|||||||
package com.simplemobiletools.draw;
|
package com.simplemobiletools.draw;
|
||||||
|
|
||||||
|
import android.graphics.Color;
|
||||||
import android.graphics.drawable.ColorDrawable;
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.sax.Element;
|
||||||
|
import android.sax.RootElement;
|
||||||
|
import android.sax.StartElementListener;
|
||||||
|
import android.util.Xml;
|
||||||
|
|
||||||
import com.simplemobiletools.draw.actions.Action;
|
import com.simplemobiletools.draw.actions.Action;
|
||||||
|
|
||||||
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class Svg {
|
public class Svg {
|
||||||
|
|
||||||
|
//region Saving
|
||||||
|
|
||||||
public static void saveSvg(File output, MyCanvas canvas) throws Exception {
|
public static void saveSvg(File output, MyCanvas canvas) throws Exception {
|
||||||
int backgroundColor = ((ColorDrawable) canvas.getBackground()).getColor();
|
int backgroundColor = ((ColorDrawable) canvas.getBackground()).getColor();
|
||||||
|
|
||||||
@ -57,4 +71,121 @@ public class Svg {
|
|||||||
writer.write(String.valueOf(options.strokeWidth));
|
writer.write(String.valueOf(options.strokeWidth));
|
||||||
writer.write("\" stroke-linecap=\"round\"/>");
|
writer.write("\" stroke-linecap=\"round\"/>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Loading
|
||||||
|
|
||||||
|
public static void loadSvg(File file, MyCanvas canvas) throws Exception {
|
||||||
|
SSvg svg = parseSvg(file);
|
||||||
|
|
||||||
|
canvas.clearCanvas();
|
||||||
|
canvas.setBackgroundColor(svg.background.color);
|
||||||
|
|
||||||
|
for (SPath sp : svg.paths) {
|
||||||
|
MyPath path = new MyPath();
|
||||||
|
path.readObject(sp.data);
|
||||||
|
PaintOptions options = new PaintOptions(sp.color, sp.strokeWidth);
|
||||||
|
|
||||||
|
canvas.addPath(path, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SSvg parseSvg(File file) throws Exception {
|
||||||
|
InputStream is = null;
|
||||||
|
final SSvg svg = new SSvg();
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(file);
|
||||||
|
|
||||||
|
// Actual parsing (http://stackoverflow.com/a/4828765)
|
||||||
|
final String ns = "http://www.w3.org/2000/svg";
|
||||||
|
RootElement root = new RootElement(ns, "svg");
|
||||||
|
Element rectElement = root.getChild(ns, "rect");
|
||||||
|
final Element pathElement = root.getChild(ns, "path");
|
||||||
|
|
||||||
|
root.setStartElementListener(new StartElementListener() {
|
||||||
|
@Override
|
||||||
|
public void start(Attributes attributes) {
|
||||||
|
int width = Integer.parseInt(attributes.getValue("width"));
|
||||||
|
int height = Integer.parseInt(attributes.getValue("height"));
|
||||||
|
svg.setSize(width, height);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rectElement.setStartElementListener(new StartElementListener() {
|
||||||
|
@Override
|
||||||
|
public void start(Attributes attributes) {
|
||||||
|
int width = Integer.parseInt(attributes.getValue("width"));
|
||||||
|
int height = Integer.parseInt(attributes.getValue("height"));
|
||||||
|
int color = Color.parseColor(attributes.getValue("fill"));
|
||||||
|
if (svg.background != null)
|
||||||
|
throw new UnsupportedOperationException("Unsupported SVG, should only have one <rect>.");
|
||||||
|
|
||||||
|
svg.background = new SRect(width, height, color);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
pathElement.setStartElementListener(new StartElementListener() {
|
||||||
|
public void start(Attributes attributes) {
|
||||||
|
String d = attributes.getValue("d");
|
||||||
|
int color = Color.parseColor(attributes.getValue("stroke"));
|
||||||
|
float width = Float.parseFloat(attributes.getValue("stroke-width"));
|
||||||
|
svg.paths.add(new SPath(d, color, width));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Once the parsing is set up, parse this InputStream
|
||||||
|
Xml.parse(is, Xml.Encoding.UTF_8, root.getContentHandler());
|
||||||
|
} finally {
|
||||||
|
if (is != null)
|
||||||
|
is.close();
|
||||||
|
}
|
||||||
|
return svg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//region Svg serializable classes
|
||||||
|
|
||||||
|
private static class SSvg implements Serializable {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
SRect background;
|
||||||
|
final ArrayList<SPath> paths;
|
||||||
|
|
||||||
|
SSvg() {
|
||||||
|
paths = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSize(int w, int h) {
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SRect implements Serializable {
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
final int color;
|
||||||
|
|
||||||
|
SRect(int w, int h, int c) {
|
||||||
|
width = w;
|
||||||
|
height = h;
|
||||||
|
color = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SPath implements Serializable {
|
||||||
|
String data;
|
||||||
|
int color;
|
||||||
|
float strokeWidth;
|
||||||
|
|
||||||
|
SPath(String d, int c, float w) {
|
||||||
|
data = d;
|
||||||
|
color = c;
|
||||||
|
strokeWidth = w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//endregion
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,24 @@ import android.graphics.Path;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
|
||||||
public final class Line implements Action {
|
public final class Line implements Action {
|
||||||
|
|
||||||
private final float x, y;
|
public final float x, y;
|
||||||
|
|
||||||
|
public Line(String data) {
|
||||||
|
if (data.startsWith("L"))
|
||||||
|
throw new InvalidParameterException("The Line data should start with 'L'.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
String[] xy = data.substring(1).split(",");
|
||||||
|
x = Float.parseFloat(xy[0].trim());
|
||||||
|
y = Float.parseFloat(xy[1].trim());
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
throw new InvalidParameterException("Error parsing the given Line data.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Line(float x, float y) {
|
public Line(float x, float y) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
|
@ -4,10 +4,24 @@ import android.graphics.Path;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
|
||||||
public final class Move implements Action {
|
public final class Move implements Action {
|
||||||
|
|
||||||
private final float x, y;
|
public final float x, y;
|
||||||
|
|
||||||
|
public Move(String data) throws InvalidParameterException {
|
||||||
|
if (data.startsWith("M"))
|
||||||
|
throw new InvalidParameterException("The Move data should start with 'M'.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
String[] xy = data.substring(1).split(",");
|
||||||
|
x = Float.parseFloat(xy[0].trim());
|
||||||
|
y = Float.parseFloat(xy[1].trim());
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
throw new InvalidParameterException("Error parsing the given Move data.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Move(float x, float y) {
|
public Move(float x, float y) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
|
@ -4,10 +4,29 @@ import android.graphics.Path;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
|
|
||||||
public final class Quad implements Action {
|
public final class Quad implements Action {
|
||||||
|
|
||||||
private final float x1, y1, x2, y2;
|
public final float x1, y1, x2, y2;
|
||||||
|
|
||||||
|
public Quad(String data) {
|
||||||
|
if (data.startsWith("Q"))
|
||||||
|
throw new InvalidParameterException("The Quad data should start with 'Q'.");
|
||||||
|
|
||||||
|
try {
|
||||||
|
String[] parts = data.split("\\s+");
|
||||||
|
String[] xy1 = parts[0].substring(1).split(",");
|
||||||
|
String[] xy2 = parts[1].split(","); // No need to skip the 'Q' here
|
||||||
|
|
||||||
|
x1 = Float.parseFloat(xy1[0].trim());
|
||||||
|
y1 = Float.parseFloat(xy1[1].trim());
|
||||||
|
x2 = Float.parseFloat(xy2[0].trim());
|
||||||
|
y2 = Float.parseFloat(xy2[1].trim());
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
throw new InvalidParameterException("Error parsing the given Quad data.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Quad(float x1, float y1, float x2, float y2) {
|
public Quad(float x1, float y1, float x2, float y2) {
|
||||||
this.x1 = x1;
|
this.x1 = x1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user