Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for multiple color changing: #32

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 85 additions & 25 deletions src/com/larvalabs/svgandroid/SVGParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Stack;
import java.util.StringTokenizer;

Expand Down Expand Up @@ -77,7 +79,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more
/**
* Entry point for parsing SVG files for Android.
* Use one of the various static methods for parsing SVGs by resource, asset or input stream.
* Optionally, a single color can be searched and replaced in the SVG while parsing.
* Optionally, a single or more colors can be searched and replaced in the SVG while parsing.
* You can also parse an svg path directly.
*
* @see #getSVGFromResource(android.content.res.Resources, int)
Expand All @@ -99,17 +101,17 @@ public class SVGParser {
* @throws SVGParseException if there is an error while parsing.
*/
public static SVG getSVGFromInputStream(InputStream svgData) throws SVGParseException {
return SVGParser.parse(svgData, 0, 0, false, false, DPI);
return SVGParser.parse(svgData, null, false, false, DPI);
}

/**
/**
* Parse SVG data from a string.
* @param svgData the string containing SVG XML data.
* @return the parsed SVG.
* @throws SVGParseException if there is an error while parsing.
*/
public static SVG getSVGFromString(String svgData) throws SVGParseException {
return SVGParser.parse(new ByteArrayInputStream(svgData.getBytes()), 0, 0, false, false, DPI);
return SVGParser.parse(new ByteArrayInputStream(svgData.getBytes()), null, false, false, DPI);
}

/**
Expand All @@ -120,7 +122,7 @@ public static SVG getSVGFromString(String svgData) throws SVGParseException {
* @throws SVGParseException if there is an error while parsing.
*/
public static SVG getSVGFromResource(Resources resources, int resId) throws SVGParseException {
return SVGParser.parse(resources.openRawResource(resId), 0, 0, false, false, DPI);
return SVGParser.parse(resources.openRawResource(resId), null, false, false, DPI);
}

/**
Expand Down Expand Up @@ -192,7 +194,57 @@ public static SVG getSVGFromAsset(AssetManager assetMngr, String svgPath, int se
return svg;
}

/**
/**
* Parse SVG data from an input stream, replacing a single color with another color.
* @param svgData the input stream, with SVG XML data in UTF-8 character encoding.
* @param replaceColors map of colors to be changed: key is to be changed with value.
* @return the parsed SVG.
* @throws SVGParseException if there is an error while parsing.
*/
public static SVG getSVGFromInputStream(InputStream svgData, Map<Integer, Integer> replaceColors) throws SVGParseException {
return SVGParser.parse(svgData, replaceColors, false, false, DPI);
}

/**
* Parse SVG data from a string.
* @param svgData the string containing SVG XML data.
* @param replaceColors map of colors to be changed: key is to be changed with value.
* @return the parsed SVG.
* @throws SVGParseException if there is an error while parsing.
*/
public static SVG getSVGFromString(String svgData, Map<Integer, Integer> replaceColors) throws SVGParseException {
return SVGParser.parse(new ByteArrayInputStream(svgData.getBytes()), replaceColors, false, false, DPI);
}

/**
* Parse SVG data from an Android application resource.
* @param resources the Android context
* @param resId the ID of the raw resource SVG.
* @param replaceColors map of colors to be changed: key is to be changed with value.
* @return the parsed SVG.
* @throws SVGParseException if there is an error while parsing.
*/
public static SVG getSVGFromResource(Resources resources, int resId, Map<Integer, Integer> replaceColors) throws SVGParseException {
return SVGParser.parse(resources.openRawResource(resId), replaceColors, false, false, DPI);
}

/**
* Parse SVG data from an Android application asset.
* @param assetMngr the Android asset manager.
* @param svgPath the path to the SVG file in the application's assets.
* @param replaceColors map of colors to be changed: key is to be changed with value.
* @return the parsed SVG.
* @throws SVGParseException if there is an error while parsing.
* @throws IOException if there was a problem reading the file.
*/
public static SVG getSVGFromAsset(AssetManager assetMngr, String svgPath, Map<Integer, Integer> replaceColors) throws SVGParseException, IOException {
InputStream inputStream = assetMngr.open(svgPath);
SVG svg = getSVGFromInputStream(inputStream, replaceColors);
inputStream.close();
return svg;
}

/**
* Parses a single SVG path and returns it as a <code>android.graphics.Path</code> object.
* An example path is <code>M250,150L150,350L350,350Z</code>, which draws a triangle.
*
Expand Down Expand Up @@ -222,28 +274,31 @@ public static Path parsePath(String pathString) {

public static class Builder {
private InputStream in;
private Integer searchColor;
private Integer replaceColor;
private Map<Integer, Integer> replaceColors;
private boolean whiteMode;
private boolean ignoreDefs;
private boolean shouldClose;
private float dpi;

public Builder() {
in = null;
searchColor = null;
replaceColor = null;
replaceColors = null;
whiteMode = false;
ignoreDefs = false;
dpi = DPI;
shouldClose = false;
}

public Builder replaceColors(Integer searchColor, Integer replaceColor) {
this.searchColor = searchColor;
this.replaceColor = replaceColor;
// Log.i(TAG, String.format("Replace: color 0x%x -> 0x%x", searchColor, replaceColor));
return this;
Map<Integer, Integer> map = new Hashtable<>(1);
map.put(searchColor, replaceColor);
return replaceColors(map);
}

public Builder replaceColors(Map<Integer, Integer> replaceColors) {
this.replaceColors = replaceColors;
// Log.i(TAG, String.format("Replace: color 0x%x -> 0x%x", searchColor, replaceColor));
return this;
}

public Builder ignoreDefs(boolean ignoreDefs) {
Expand Down Expand Up @@ -297,7 +352,7 @@ public SVG build() throws SVGParseException {
if (in == null) {
throw new IllegalStateException("No input SVG provided");
}
SVG result = parse(in, searchColor, replaceColor, whiteMode, ignoreDefs, dpi);
SVG result = parse(in, replaceColors, whiteMode, ignoreDefs, dpi);
if (shouldClose) {
try {
in.close();
Expand All @@ -310,7 +365,13 @@ public SVG build() throws SVGParseException {
}
}

private static SVG parse(InputStream in, Integer searchColor, Integer replaceColor, boolean whiteMode, boolean ignoreDefs, float dpi) throws SVGParseException {
private static SVG parse(InputStream in, int searchColor, int replaceColor, boolean whiteMode, boolean ignoreDefs, float dpi) throws SVGParseException {
Map<Integer, Integer> swaps = new Hashtable<>(1);
swaps.put(searchColor, replaceColor);
return parse(in, swaps, whiteMode, ignoreDefs, dpi);
}

private static SVG parse(InputStream in, Map<Integer, Integer> replaceColors, boolean whiteMode, boolean ignoreDefs, float dpi) throws SVGParseException {
// Log.i(TAG, "parsing svg");
SVGHandler svgHandler = null;
long start = System.currentTimeMillis();
Expand All @@ -320,7 +381,7 @@ private static SVG parse(InputStream in, Integer searchColor, Integer replaceCol
XMLReader xr = sp.getXMLReader();
final Picture picture = new Picture();
svgHandler = new SVGHandler(picture);
svgHandler.setColorSwap(searchColor, replaceColor);
svgHandler.setColorSwaps(replaceColors);
svgHandler.setWhiteMode(whiteMode);
svgHandler.setDpi(dpi);
if (ignoreDefs) {
Expand Down Expand Up @@ -1156,8 +1217,7 @@ private static class SVGHandler extends DefaultHandler {
RectF bounds = null;
RectF limits = new RectF(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);

Integer searchColor = null;
Integer replaceColor = null;
Map<Integer, Integer> replaceColors;

boolean whiteMode = false;

Expand Down Expand Up @@ -1190,10 +1250,9 @@ public void setDpi(float dpi) {
this.dpi = dpi;
}

public void setColorSwap(Integer searchColor, Integer replaceColor) {
this.searchColor = searchColor;
this.replaceColor = replaceColor;
}
public void setColorSwaps(Map<Integer, Integer> swaps) {
this.replaceColors = swaps;
}

public void setWhiteMode(boolean whiteMode) {
this.whiteMode = whiteMode;
Expand Down Expand Up @@ -1401,8 +1460,9 @@ private void doColor(Properties atts, Integer color, boolean fillMode, Paint pai
private int replaceColor(int color) {
// Log.d(TAG, String.format("Replace color? 0x%x", color));
color &= 0xFFFFFF;
if (searchColor != null && searchColor.intValue() == color && replaceColor != null) {
Log.d(TAG, String.format("Replacing color: 0x%x->0x%x", color, replaceColor));
if (replaceColors != null && replaceColors.containsKey(color)) {
int replaceColor = replaceColors.get(color);
Log.d(TAG, String.format("Replacing color: 0x%x->0x%x", color, replaceColor));
return replaceColor;
} else {
return color;
Expand Down