Skip to content

Commit 102010a

Browse files
Adds some caching when inlining PlantUML, Mermaid, and Kroki images.
1 parent 1e7a9c2 commit 102010a

File tree

5 files changed

+60
-32
lines changed

5 files changed

+60
-32
lines changed

structurizr-core/src/main/java/com/structurizr/util/ImageUtils.java

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import java.net.http.HttpResponse;
1414
import java.nio.file.Files;
1515
import java.util.Base64;
16+
import java.util.HashMap;
17+
import java.util.Map;
1618

1719
/**
1820
* Some utility methods for dealing with images.
@@ -28,6 +30,8 @@ public class ImageUtils {
2830
public static final String CONTENT_TYPE_IMAGE_JPG = "image/jpeg";
2931
public static final String CONTENT_TYPE_IMAGE_SVG = "image/svg+xml";
3032

33+
private static final Map<String,String> imageCache = new HashMap<>();
34+
3135
/**
3236
* Gets the content type of the specified file representing an image.
3337
*
@@ -128,33 +132,57 @@ public static String getImageAsDataUri(File file) throws IOException {
128132
}
129133

130134
public static String getSvgAsDataUri(@Nonnull URL url) throws Exception {
131-
HttpRequest request = HttpRequest.newBuilder()
132-
.uri(url.toURI())
133-
.header("accept", CONTENT_TYPE_IMAGE_SVG)
134-
.build();
135-
HttpClient client = HttpClient.newBuilder()
136-
.followRedirects(HttpClient.Redirect.ALWAYS)
137-
.build();
138-
139-
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
140-
String svg = response.body();
141-
142-
return DATA_URI_PREFIX + CONTENT_TYPE_IMAGE_SVG + ";base64," + Base64.getEncoder().encodeToString(svg.getBytes());
135+
return getSvgAsDataUri(url, false);
136+
}
137+
138+
public static String getSvgAsDataUri(@Nonnull URL url, boolean cache) throws Exception {
139+
String urlAsString = url.toString();
140+
String dataUri = cache ? imageCache.get(urlAsString) : null;
141+
142+
if (StringUtils.isNullOrEmpty(dataUri)) {
143+
HttpRequest request = HttpRequest.newBuilder()
144+
.uri(url.toURI())
145+
.header("accept", CONTENT_TYPE_IMAGE_SVG)
146+
.build();
147+
HttpClient client = HttpClient.newBuilder()
148+
.followRedirects(HttpClient.Redirect.ALWAYS)
149+
.build();
150+
151+
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
152+
String svg = response.body();
153+
154+
dataUri = DATA_URI_PREFIX + CONTENT_TYPE_IMAGE_SVG + ";base64," + Base64.getEncoder().encodeToString(svg.getBytes());
155+
imageCache.put(urlAsString, dataUri);
156+
}
157+
158+
return dataUri;
143159
}
144160

145161
public static String getPngAsDataUri(@Nonnull URL url) throws Exception {
146-
HttpRequest request = HttpRequest.newBuilder()
147-
.uri(url.toURI())
148-
.header("accept", CONTENT_TYPE_IMAGE_PNG)
149-
.build();
150-
HttpClient client = HttpClient.newBuilder()
151-
.followRedirects(HttpClient.Redirect.ALWAYS)
152-
.build();
153-
154-
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
155-
byte[] png = response.body();
156-
157-
return DATA_URI_PREFIX + CONTENT_TYPE_IMAGE_PNG + ";base64," + Base64.getEncoder().encodeToString(png);
162+
return getPngAsDataUri(url, false);
163+
}
164+
165+
public static String getPngAsDataUri(@Nonnull URL url, boolean cache) throws Exception {
166+
String urlAsString = url.toString();
167+
String dataUri = cache ? imageCache.get(urlAsString) : null;
168+
169+
if (StringUtils.isNullOrEmpty(dataUri)) {
170+
HttpRequest request = HttpRequest.newBuilder()
171+
.uri(url.toURI())
172+
.header("accept", CONTENT_TYPE_IMAGE_PNG)
173+
.build();
174+
HttpClient client = HttpClient.newBuilder()
175+
.followRedirects(HttpClient.Redirect.ALWAYS)
176+
.build();
177+
178+
HttpResponse<byte[]> response = client.send(request, HttpResponse.BodyHandlers.ofByteArray());
179+
byte[] png = response.body();
180+
181+
dataUri = DATA_URI_PREFIX + CONTENT_TYPE_IMAGE_PNG + ";base64," + Base64.getEncoder().encodeToString(png);
182+
imageCache.put(urlAsString, dataUri);
183+
}
184+
185+
return dataUri;
158186
}
159187

160188
public static void validateImage(String imageDescriptor) {

structurizr-import/src/main/java/com/structurizr/importer/diagrams/image/ImageImporter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ public void importDiagram(ImageView view, String url) throws Exception {
2828
}
2929

3030
if (imageFormat.equals(CONTENT_TYPE_IMAGE_SVG)) {
31-
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url)));
31+
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url), false));
3232
} else {
33-
view.setContent(ImageUtils.getPngAsDataUri(new URL(url)));
33+
view.setContent(ImageUtils.getPngAsDataUri(new URL(url), false));
3434
}
3535

3636
view.setContentType(imageFormat);

structurizr-import/src/main/java/com/structurizr/importer/diagrams/kroki/KrokiImporter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ public void importDiagram(ImageView view, String format, String content) throws
4444
String inline = getViewOrViewSetProperty(view, KROKI_INLINE_PROPERTY);
4545
if ("true".equals(inline)) {
4646
if (imageFormat.equals(SVG_FORMAT)) {
47-
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url)));
47+
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url), true));
4848
} else {
49-
view.setContent(ImageUtils.getPngAsDataUri(new URL(url)));
49+
view.setContent(ImageUtils.getPngAsDataUri(new URL(url), true));
5050
}
5151
} else {
5252
view.setContent(url);

structurizr-import/src/main/java/com/structurizr/importer/diagrams/mermaid/MermaidImporter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ public void importDiagram(ImageView view, String content) throws Exception {
5555
String inline = getViewOrViewSetProperty(view, MERMAID_INLINE_PROPERTY);
5656
if ("true".equals(inline)) {
5757
if (format.equals(SVG_FORMAT)) {
58-
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url)));
58+
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url), true));
5959
} else {
60-
view.setContent(ImageUtils.getPngAsDataUri(new URL(url)));
60+
view.setContent(ImageUtils.getPngAsDataUri(new URL(url), true));
6161
}
6262
} else {
6363
view.setContent(url);

structurizr-import/src/main/java/com/structurizr/importer/diagrams/plantuml/PlantUMLImporter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ public void importDiagram(ImageView view, String content) throws Exception {
4747
String inline = getViewOrViewSetProperty(view, PLANTUML_INLINE_PROPERTY);
4848
if ("true".equals(inline)) {
4949
if (format.equals(SVG_FORMAT)) {
50-
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url)));
50+
view.setContent(ImageUtils.getSvgAsDataUri(new URL(url), true));
5151
} else {
52-
view.setContent(ImageUtils.getPngAsDataUri(new URL(url)));
52+
view.setContent(ImageUtils.getPngAsDataUri(new URL(url), true));
5353
}
5454
} else {
5555
view.setContent(url);

0 commit comments

Comments
 (0)