diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/access/FilterDefinitionElement.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/access/FilterDefinitionElement.java
index c9bace8aa..74ae27d02 100644
--- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/access/FilterDefinitionElement.java
+++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/access/FilterDefinitionElement.java
@@ -33,9 +33,14 @@ abstract class FilterDefinitionElement {
* Utility method to create a Hash object from a .b32 string
*/
protected static Hash fromBase32(String b32) throws InvalidDefinitionException {
+ if (b32.length() != 60)
+ throw new InvalidDefinitionException("Invalid b32 " + b32);
if (!b32.endsWith(".b32.i2p"))
throw new InvalidDefinitionException("Invalid b32 " + b32);
- b32 = b32.substring(0, b32.length() - 8);
- return new Hash(Base32.decode(b32));
+ String s = b32.substring(0, 52);
+ byte[] b = Base32.decode(s);
+ if (b == null)
+ throw new InvalidDefinitionException("Invalid b32 " + b32);
+ return Hash.create(b);
}
}
diff --git a/apps/imagegen/build.gradle b/apps/imagegen/build.gradle
index 776a8efe3..536bc6bed 100644
--- a/apps/imagegen/build.gradle
+++ b/apps/imagegen/build.gradle
@@ -16,6 +16,7 @@ sourceSets {
dependencies {
implementation project(':core')
implementation project(':apps:jetty')
+ implementation project(':apps:jrobin')
implementation fileTree("../jetty/apache-tomcat-${tomcatVersion}")
}
diff --git a/apps/imagegen/identicon/core/src/main/java/com/docuverse/identicon/NineBlockIdenticonRenderer2.java b/apps/imagegen/identicon/core/src/main/java/com/docuverse/identicon/NineBlockIdenticonRenderer2.java
index 559e1a1a8..9a81a378b 100644
--- a/apps/imagegen/identicon/core/src/main/java/com/docuverse/identicon/NineBlockIdenticonRenderer2.java
+++ b/apps/imagegen/identicon/core/src/main/java/com/docuverse/identicon/NineBlockIdenticonRenderer2.java
@@ -153,7 +153,7 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
}
public BufferedImage render(BigInteger code, int size) {
- return renderQuilt(code.intValue(), size);
+ return renderQuilt(null, code.intValue(), size);
}
/**
@@ -172,10 +172,22 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
* @return identicon image
*/
public BufferedImage render(int code, int size) {
- return renderQuilt(code, size);
+ return renderQuilt(null, code, size);
}
- protected BufferedImage renderQuilt(int code, int size) {
+ /**
+ * @param g custom Graphics2D or null
+ * @since 0.9.64
+ */
+ public BufferedImage render(Graphics2D g, int code, int size) {
+ return renderQuilt(g, code, size);
+ }
+
+ /**
+ * @param gg custom Graphics2D or null
+ * @since 0.9.64
+ */
+ protected BufferedImage renderQuilt(Graphics2D gg, int code, int size) {
// -------------------------------------------------
// PREPARE
//
@@ -220,9 +232,15 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
// RENDER
//
- BufferedImage targetImage = new BufferedImage(size, size,
- BufferedImage.TYPE_INT_RGB);
- Graphics2D g = targetImage.createGraphics();
+ BufferedImage targetImage = null;
+ Graphics2D g;
+ if (gg != null) {
+ g = gg;
+ } else {
+ targetImage = new BufferedImage(size, size,
+ BufferedImage.TYPE_INT_RGB);
+ g = targetImage.createGraphics();
+ }
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
@@ -256,7 +274,8 @@ public class NineBlockIdenticonRenderer2 implements IdenticonRenderer {
drawPatch(g, 0, blockSize2, blockSize, cornerType, cornerTurn++,
cornerInvert, fillColor, strokeColor);
- g.dispose();
+ if (gg == null)
+ g.dispose();
return targetImage;
}
diff --git a/apps/imagegen/imagegen/build.xml b/apps/imagegen/imagegen/build.xml
index 68cb47660..39252ef8b 100644
--- a/apps/imagegen/imagegen/build.xml
+++ b/apps/imagegen/imagegen/build.xml
@@ -8,6 +8,7 @@
+
diff --git a/apps/imagegen/imagegen/webapp/src/main/java/net/i2p/imagegen/IdenticonServlet.java b/apps/imagegen/imagegen/webapp/src/main/java/net/i2p/imagegen/IdenticonServlet.java
index 63778a4cd..989009ae9 100644
--- a/apps/imagegen/imagegen/webapp/src/main/java/net/i2p/imagegen/IdenticonServlet.java
+++ b/apps/imagegen/imagegen/webapp/src/main/java/net/i2p/imagegen/IdenticonServlet.java
@@ -19,6 +19,7 @@ import com.docuverse.identicon.NineBlockIdenticonRenderer2;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
+import net.i2p.rrd4j.SimpleSVGGraphics2D;
import net.i2p.util.ConvertToHash;
import net.i2p.util.Log;
@@ -67,10 +68,10 @@ public class IdenticonServlet extends HttpServlet {
private static final String PARAM_IDENTICON_SIZE_SHORT = "s";
private static final String PARAM_IDENTICON_CODE_SHORT = "c";
private static final String IDENTICON_IMAGE_FORMAT = "PNG";
- private static final String IDENTICON_IMAGE_MIMETYPE = "image/png";
+ private static final String IDENTICON_IMAGE_MIMETYPE = "image/svg+xml";
private static final long DEFAULT_IDENTICON_EXPIRES_IN_MILLIS = 24 * 60 * 60 * 1000;
private int version = 1;
- private final IdenticonRenderer renderer = new NineBlockIdenticonRenderer2();
+ private final NineBlockIdenticonRenderer2 renderer = new NineBlockIdenticonRenderer2();
private IdenticonCache cache;
private long identiconExpiresInMillis = DEFAULT_IDENTICON_EXPIRES_IN_MILLIS;
@@ -147,6 +148,7 @@ public class IdenticonServlet extends HttpServlet {
// retrieve image bytes from either cache or renderer
if (cache == null
|| (imageBytes = cache.get(identiconETag)) == null) {
+/*
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
RenderedImage image;
try {
@@ -160,6 +162,20 @@ public class IdenticonServlet extends HttpServlet {
}
ImageIO.write(image, IDENTICON_IMAGE_FORMAT, byteOut);
imageBytes = byteOut.toByteArray();
+*/
+ SimpleSVGGraphics2D g = new SimpleSVGGraphics2D(size, size);
+ try {
+ renderer.render(g, code, size);
+ } catch (Throwable t) {
+ // java.lang.NoClassDefFoundError: Could not initialize class java.awt.GraphicsEnvironment$LocalGE
+ Log log = I2PAppContext.getGlobalContext().logManager().getLog(IdenticonServlet.class);
+ //log.logAlways(Log.WARN, "Identicon render failure: " + t);
+ log.error("Identicon render failure", t);
+ response.setStatus(403);
+ return;
+ }
+ String s = g.getSVG();
+ imageBytes = s.getBytes("UTF-8");
if (cache != null)
cache.add(identiconETag, imageBytes);
} else {
@@ -178,6 +194,7 @@ public class IdenticonServlet extends HttpServlet {
// return image bytes to requester
response.setContentType(IDENTICON_IMAGE_MIMETYPE);
+ response.setCharacterEncoding("UTF-8");
response.setHeader("X-Content-Type-Options", "nosniff");
response.setHeader("Accept-Ranges", "none");
response.setContentLength(imageBytes.length);
diff --git a/apps/jrobin/java/build.xml b/apps/jrobin/java/build.xml
index 89f931ebf..b643d308a 100644
--- a/apps/jrobin/java/build.xml
+++ b/apps/jrobin/java/build.xml
@@ -37,6 +37,9 @@
encoding="UTF-8"
includes="**/*.java" >
+
+
+
diff --git a/apps/jrobin/java/src/net/i2p/rrd4j/SimpleSVGGraphics2D.java b/apps/jrobin/java/src/net/i2p/rrd4j/SimpleSVGGraphics2D.java
new file mode 100644
index 000000000..3df1ddd96
--- /dev/null
+++ b/apps/jrobin/java/src/net/i2p/rrd4j/SimpleSVGGraphics2D.java
@@ -0,0 +1,431 @@
+package net.i2p.rrd4j;
+
+import java.text.AttributedCharacterIterator;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import static java.awt.geom.PathIterator.*;
+import java.awt.image.*;
+import java.awt.image.renderable.RenderableImage;
+
+/**
+ * Very simple SVGGraphics2D, only enough for basic rrd4j use, without dependencies.
+ * Plus a few things that rrd4j doesn't use, but not much.
+ * Unsupported things will throw UnsupportedOperationExceptions.
+ *
+ * Supports custom RenderingHints for id and class on top-level svg element.
+ * Supports custom RenderingHints for id, class, title, and arbitrary attributes
+ * on all drawn elements.
+ * Supports custom RenderingHints for inner SVG on all drawn elements except text.
+ *
+ * No standard Java AWT hints are supported.
+ * Antialiasing is done automatically.
+ * Antialiasing hints have no effect.
+ *
+ * License: Apache 2.0 (same as rrd4j)
+ *
+ * @since 0.9.64
+ * @author zzz
+ */
+public class SimpleSVGGraphics2D extends Graphics2D {
+
+ //// hints - all strings except for ATTMAP ////
+
+ /**
+ * On the top svg element.
+ * Value is a string and will be XML-escaped when rendering.
+ */
+ public static final RenderingHints.Key KEY_SVG_ID = new RHKey(1);
+ /**
+ * On the top svg element.
+ * Value is a string and will be XML-escaped when rendering.
+ */
+ public static final RenderingHints.Key KEY_SVG_CLASS = new RHKey(2);
+ /**
+ * On the top svg element.
+ * Value is a string and will be XML-escaped when rendering.
+ */
+ public static final RenderingHints.Key KEY_SVG_TITLE = new RHKey(3);
+ /**
+ * On the next element drawn, one-shot, will be removed after rendering.
+ * Value is a string and will be XML-escaped when rendering.
+ */
+ public static final RenderingHints.Key KEY_ELEMENT_ID = new RHKey(4);
+ /**
+ * On the next element drawn, one-shot, will be removed after rendering.
+ * Value is a string and will be XML-escaped when rendering.
+ */
+ public static final RenderingHints.Key KEY_ELEMENT_CLASS = new RHKey(5);
+ /**
+ * Value is a Map of String to String of extra attributes on the next element drawn, one-shot, will be removed after rendering.
+ * Map keys must be XML-escaped by caller if necessary.
+ * Map values will be XML-escaped when rendering.
+ */
+ public static final RenderingHints.Key KEY_ELEMENT_ATTMAP = new RHKey(6);
+ /**
+ * On the next element drawn, one-shot, will be removed after rendering.
+ * Value is a string and will be XML-escaped when rendering.
+ */
+ public static final RenderingHints.Key KEY_ELEMENT_TITLE = new RHKey(7);
+ /**
+ * Put "inside" the next element drawn, one-shot, will be removed after rendering.
+ * Value is an XML string and must be XML-escaped by caller if necessary.
+ */
+ public static final RenderingHints.Key KEY_ELEMENT_INNERSVG = new RHKey(8);
+
+ private final StringBuilder buf;
+ private final SimpleSVGMaker svg;
+ private final Map