diff --git a/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGGenerator.java b/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGGenerator.java
index 4f6cebf..eec7360 100644
--- a/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGGenerator.java
+++ b/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGGenerator.java
@@ -134,6 +134,7 @@ private SVGGenerator (StringBuffer sb, Component c) {
sb.append("\" height=\"");
sb.append(c.getHeight());
sb.append("\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n");
+ sb.append("\n");
c.paint(new SVGGraphics());
@@ -237,7 +238,7 @@ public void drawLine(int x1, int y1, int x2, int y2) {
sb.append(y2);
sb.append("\" stroke=\"rgb(");
appendColor();
- sb.append(")\" stroke-width=\"1\"/>\n");
+ sb.append(")\" stroke-width=\"2\"/>\n");
}
/* (non-Javadoc)
@@ -273,9 +274,9 @@ public void drawOval(int x, int y, int width, int height) {
sb.append(width);
sb.append("\" ry=\"");
sb.append(height);
- sb.append("\" style=\"fill:none;stroke:rgb(");
+ sb.append("\" fill=\"none\" stroke=\"rgb(");
appendColor();
- sb.append(");stroke-width:1\"/>\n");
+ sb.append(")\"/>\n");
}
/* (non-Javadoc)
@@ -311,9 +312,9 @@ public void fillOval(int x, int y, int width, int height) {
sb.append(width);
sb.append("\" ry=\"");
sb.append(height);
- sb.append("\" style=\"fill:rgb(");
+ sb.append("\" fill=\"rgb(");
appendColor();
- sb.append(");stroke:none\"/>\n");
+ sb.append(")\"/>\n");
}
/* (non-Javadoc)
@@ -344,7 +345,7 @@ public void drawString(String string, int x, int y) {
sb.append(y);
sb.append("\" fill=\"rgb(");
appendColor();
- sb.append(")\" font-family=\"Arial\" font-size=\"");
+ sb.append(")\" font-size=\"");
sb.append(font.getSize());
if (font.isBold()) {
sb.append("\" font-weight=\"bold");
@@ -404,8 +405,7 @@ public void drawRoundRect(int x, int y, int width, int height, int arcWidth,int
sb.append(arcWidth);
sb.append("\" ry=\"");
sb.append(arcHeight);
- sb.append("\" style=\"fill:none");
- sb.append(";stroke-width:1;stroke:rgb(");
+ sb.append("\" fill=\"none\" stroke=\"rgb(");
appendColor();
@@ -450,11 +450,11 @@ public void fillRoundRect(int x, int y, int width, int height, int arcWidth,int
sb.append("\" ry=\"");
sb.append(arcHeight);
}
- sb.append("\" style=\"fill:rgb(");
+ sb.append("\" fill=\"rgb(");
appendColor();
- sb.append(");stroke:none\"/>\n");
+ sb.append(")\"/>\n");
}
/* (non-Javadoc)
@@ -607,11 +607,11 @@ public void drawPolygon(int[] xPoints, int[] yPoints, int pointsToUse) {
sb.append(correctedYPoints[i]);
}
- sb.append("\" style=\"stroke-width:1;stroke:rgb(");
+ sb.append("\" fill=\"none\" stroke=\"rgb(");
appendColor();
- sb.append(");fill:none\"/>\n");
+ sb.append(")\"/>\n");
}
/* (non-Javadoc)
@@ -661,11 +661,11 @@ public void fillPolygon(int[] xPoints, int[] yPoints, int pointsToUse) {
sb.append(correctedYPoints[i]);
}
- sb.append("\" style=\"fill:rgb(");
+ sb.append("\" fill=\"rgb(");
appendColor();
- sb.append(");stroke:none\"/>\n");
+ sb.append(")\"/>\n");
}
diff --git a/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGImageSaver.java b/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGImageSaver.java
index 5e4443f..7dd244f 100644
--- a/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGImageSaver.java
+++ b/uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGImageSaver.java
@@ -22,6 +22,9 @@
import java.awt.Component;
import java.io.OutputStream;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
@@ -31,14 +34,135 @@
*/
public class SVGImageSaver {
+ private static final Pattern LINE_PATTERN = Pattern.compile(
+ ""
+ );
+
+ private static final Pattern RECT_PATTERN = Pattern.compile(
+ ""
+ );
+
public static String saveImage (Component c, OutputStream os) {
PrintWriter pr = new PrintWriter(os);
String svgData = SVGGenerator.writeSVG(c);
+ svgData = optimizeSvg(svgData);
pr.write(svgData);
pr.flush();
return(svgData);
}
-
-
-
+
+ private static String optimizeSvg(String svg) {
+ svg = mergeLinesToPolylines(svg);
+ svg = mergeRects(svg);
+ return svg;
+ }
+
+ /** Merge consecutive same-colour line elements into polyline elements. */
+ private static String mergeLinesToPolylines(String svg) {
+ String[] lines = svg.split("\n");
+ StringBuilder result = new StringBuilder(svg.length());
+ ArrayList group = new ArrayList<>();
+ String groupStroke = null;
+ String groupWidth = null;
+
+ for (String line : lines) {
+ Matcher m = LINE_PATTERN.matcher(line.trim());
+ if (m.matches()) {
+ String stroke = m.group(5);
+ String width = m.group(6);
+ if ("rgb(0,0,0)".equals(stroke) || "rgb(180,180,180)".equals(stroke)) {
+ flushLineGroup(result, group, groupStroke, groupWidth);
+ group.clear();
+ groupStroke = null;
+ result.append(line).append("\n");
+ } else if (stroke.equals(groupStroke) && width.equals(groupWidth)) {
+ group.add(new String[]{m.group(1), m.group(2), m.group(3), m.group(4)});
+ } else {
+ flushLineGroup(result, group, groupStroke, groupWidth);
+ group.clear();
+ groupStroke = stroke;
+ groupWidth = width;
+ group.add(new String[]{m.group(1), m.group(2), m.group(3), m.group(4)});
+ }
+ } else {
+ flushLineGroup(result, group, groupStroke, groupWidth);
+ group.clear();
+ groupStroke = null;
+ result.append(line).append("\n");
+ }
+ }
+ flushLineGroup(result, group, groupStroke, groupWidth);
+ return result.toString();
+ }
+
+ private static void flushLineGroup(StringBuilder sb, ArrayList group, String stroke, String width) {
+ if (group.size() <= 2) {
+ for (String[] seg : group) {
+ sb.append("\n");
+ }
+ return;
+ }
+ StringBuilder points = new StringBuilder();
+ points.append(group.get(0)[0]).append(",").append(group.get(0)[1]);
+ for (String[] seg : group) {
+ points.append(" ").append(seg[2]).append(",").append(seg[3]);
+ }
+ sb.append("\n");
+ }
+
+ /** Merge consecutive same-colour filled rects on the same row into wider rects. */
+ private static String mergeRects(String svg) {
+ String[] lines = svg.split("\n");
+ StringBuilder result = new StringBuilder(svg.length());
+ ArrayList group = new ArrayList<>();
+ String groupFill = null;
+
+ for (String line : lines) {
+ Matcher m = RECT_PATTERN.matcher(line.trim());
+ if (m.matches()) {
+ int w = Integer.parseInt(m.group(1));
+ int h = Integer.parseInt(m.group(2));
+ int x = Integer.parseInt(m.group(3));
+ int y = Integer.parseInt(m.group(4));
+ String fill = m.group(5);
+ if (w > 100 || h > 100) {
+ flushRectGroup(result, group, groupFill);
+ group.clear();
+ groupFill = null;
+ result.append(line).append("\n");
+ } else if (fill.equals(groupFill) && !group.isEmpty()
+ && y == group.get(0)[3] && h == group.get(0)[1]
+ && x == group.get(0)[2] + group.get(0)[0] * group.size()) {
+ group.add(new int[]{w, h, x, y});
+ } else {
+ flushRectGroup(result, group, groupFill);
+ group.clear();
+ groupFill = fill;
+ group.add(new int[]{w, h, x, y});
+ }
+ } else {
+ flushRectGroup(result, group, groupFill);
+ group.clear();
+ groupFill = null;
+ result.append(line).append("\n");
+ }
+ }
+ flushRectGroup(result, group, groupFill);
+ return result.toString();
+ }
+
+ private static void flushRectGroup(StringBuilder sb, ArrayList group, String fill) {
+ if (group.isEmpty()) return;
+ int mergedWidth = group.get(0)[0] * group.size();
+ int[] first = group.get(0);
+ sb.append("\n");
+ }
+
}