Skip to content
Open
Show file tree
Hide file tree
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
28 changes: 14 additions & 14 deletions uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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("<style>text{font-family:Arial}</style>\n");

c.paint(new SVGGraphics());

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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");

}

Expand Down
130 changes: 127 additions & 3 deletions uk/ac/babraham/FastQC/Utilities/ImageSaver/SVGImageSaver.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;


/**
Expand All @@ -31,14 +34,135 @@
*/
public class SVGImageSaver {

private static final Pattern LINE_PATTERN = Pattern.compile(
"<line x1=\"(\\d+)\" y1=\"(\\d+)\" x2=\"(\\d+)\" y2=\"(\\d+)\" stroke=\"(rgb\\([^)]+\\))\" stroke-width=\"(\\d+)\"/>"
);

private static final Pattern RECT_PATTERN = Pattern.compile(
"<rect width=\"(\\d+)\" height=\"(\\d+)\" x=\"(\\d+)\" y=\"(\\d+)\" fill=\"(rgb\\([^)]+\\))\"/>"
);

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<String[]> 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<String[]> group, String stroke, String width) {
if (group.size() <= 2) {
for (String[] seg : group) {
sb.append("<line x1=\"").append(seg[0]).append("\" y1=\"").append(seg[1])
.append("\" x2=\"").append(seg[2]).append("\" y2=\"").append(seg[3])
.append("\" stroke=\"").append(stroke).append("\" stroke-width=\"").append(width)
.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("<polyline points=\"").append(points)
.append("\" stroke=\"").append(stroke).append("\" stroke-width=\"").append(width)
.append("\" fill=\"none\"/>\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<int[]> 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<int[]> group, String fill) {
if (group.isEmpty()) return;
int mergedWidth = group.get(0)[0] * group.size();
int[] first = group.get(0);
sb.append("<rect width=\"").append(mergedWidth).append("\" height=\"").append(first[1])
.append("\" x=\"").append(first[2]).append("\" y=\"").append(first[3])
.append("\" fill=\"").append(fill).append("\"/>\n");
}

}
Loading