From 3ac71e9ff1ce42e835aac226e9c83341ddd24d6b Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 15 Dec 2023 16:20:25 +0200 Subject: [PATCH] Improve SVG preview generation --- .../server/dao/util/ImageUtils.java | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/ImageUtils.java b/dao/src/main/java/org/thingsboard/server/dao/util/ImageUtils.java index 29f7b32fae..146660a489 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/ImageUtils.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/ImageUtils.java @@ -20,8 +20,10 @@ import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.Tag; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.With; import lombok.extern.slf4j.Slf4j; import org.apache.batik.anim.dom.SAXSVGDocumentFactory; import org.apache.batik.bridge.BridgeContext; @@ -121,7 +123,7 @@ public class ImageUtils { image.setHeight(bufferedImage.getHeight()); ProcessedImage preview = new ProcessedImage(); - int[] thumbnailDimensions = getThumbnailDimensions(image.getWidth(), image.getHeight(), thumbnailMaxDimension); + int[] thumbnailDimensions = getThumbnailDimensions(image.getWidth(), image.getHeight(), thumbnailMaxDimension, true); preview.setWidth(thumbnailDimensions[0]); preview.setHeight(thumbnailDimensions[1]); @@ -191,8 +193,18 @@ public class ImageUtils { image.setSize(data.length); PNGTranscoder transcoder = new PNGTranscoder(); - transcoder.addTranscodingHint(PNGTranscoder.KEY_MAX_WIDTH, (float) thumbnailMaxDimension); - transcoder.addTranscodingHint(PNGTranscoder.KEY_MAX_HEIGHT, (float) thumbnailMaxDimension); + if (image.getSize() < 10240) { // if SVG is smaller than 10kB (average 250x250 PNG preview size) + return withPreviewAsOriginalImage(image); + } else if (image.getSize() > 102400 && image.getWidth() != 0) { // considering SVG image detailed after 100kB + // increasing preview dimensions + thumbnailMaxDimension = 512; + int[] thumbnailDimensions = getThumbnailDimensions(image.getWidth(), image.getHeight(), thumbnailMaxDimension, false); + transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) thumbnailDimensions[0]); + transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) thumbnailDimensions[1]); + } else { + transcoder.addTranscodingHint(PNGTranscoder.KEY_MAX_WIDTH, (float) thumbnailMaxDimension); + transcoder.addTranscodingHint(PNGTranscoder.KEY_MAX_HEIGHT, (float) thumbnailMaxDimension); + } ByteArrayOutputStream out = new ByteArrayOutputStream(); transcoder.transcode(new TranscoderInput(new ByteArrayInputStream(data)), new TranscoderOutput(out)); byte[] pngThumbnail = out.toByteArray(); @@ -214,18 +226,16 @@ public class ImageUtils { image.setSize(data.length); image.setWidth(0); image.setHeight(0); - ProcessedImage preview = new ProcessedImage(); - preview.setMediaType(mediaType); - preview.setData(null); - preview.setSize(data.length); - preview.setWidth(0); - preview.setHeight(0); - image.setPreview(preview); - return image; + return withPreviewAsOriginalImage(image); } - private static int[] getThumbnailDimensions(int originalWidth, int originalHeight, int maxDimension) { - if (originalWidth <= maxDimension && originalHeight <= maxDimension) { + public static ProcessedImage withPreviewAsOriginalImage(ProcessedImage originalImage) { + originalImage.setPreview(originalImage.withData(null)); + return originalImage; + } + + private static int[] getThumbnailDimensions(int originalWidth, int originalHeight, int maxDimension, boolean originalIfSmaller) { + if (originalWidth <= maxDimension && originalHeight <= maxDimension && originalIfSmaller) { return new int[]{originalWidth, originalHeight}; } int thumbnailWidth; @@ -242,10 +252,13 @@ public class ImageUtils { } @Data + @AllArgsConstructor + @NoArgsConstructor public static class ProcessedImage { private String mediaType; private int width; private int height; + @With private byte[] data; private long size; private ProcessedImage preview;