]> git.argeo.org Git - lgpl/argeo-commons.git/blob - BundleSvgTheme.java
74de83e09ce895ce442e214ef64e5bb835163f9f
[lgpl/argeo-commons.git] / BundleSvgTheme.java
1 package org.argeo.cms.swt.osgi;
2
3 import java.awt.Color;
4 import java.io.ByteArrayInputStream;
5 import java.io.ByteArrayOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.lang.System.Logger;
9 import java.lang.System.Logger.Level;
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.Map;
13 import java.util.Objects;
14
15 import org.apache.batik.transcoder.TranscoderException;
16 import org.apache.batik.transcoder.TranscoderInput;
17 import org.apache.batik.transcoder.TranscoderOutput;
18 import org.apache.batik.transcoder.image.ImageTranscoder;
19 import org.apache.batik.transcoder.image.PNGTranscoder;
20 import org.eclipse.swt.graphics.Image;
21 import org.eclipse.swt.graphics.ImageData;
22 import org.eclipse.swt.widgets.Display;
23 import org.osgi.framework.BundleContext;
24
25 /** Theme which can dynamically create icons from SVG data. */
26 public class BundleSvgTheme extends BundleCmsSwtTheme {
27 private final static Logger logger = System.getLogger(BundleSvgTheme.class.getName());
28
29 private Map<String, Map<Integer, ImageData>> imageDataCache = Collections.synchronizedMap(new HashMap<>());
30
31 private Map<Integer, ImageTranscoder> transcoders = Collections.synchronizedMap(new HashMap<>());
32
33 private final static String IMAGE_CACHE_KEY = BundleSvgTheme.class.getName() + ".imageCache";
34
35 @Override
36 public Image getIcon(String name, Integer preferredSize) {
37 String path = "icons/types/svg/" + name + ".svg";
38 return createImageFromSvg(path, preferredSize);
39 }
40
41 @SuppressWarnings("unchecked")
42 protected Image createImageFromSvg(String path, Integer preferredSize) {
43 Display display = Display.getCurrent();
44 Objects.requireNonNull(display, "Not a user interface thread");
45
46 Map<String, Map<Integer, Image>> imageCache = (Map<String, Map<Integer, Image>>) display
47 .getData(IMAGE_CACHE_KEY);
48 if (imageCache == null)
49 display.setData(IMAGE_CACHE_KEY, new HashMap<String, Map<Integer, Image>>());
50 imageCache = (Map<String, Map<Integer, Image>>) display.getData(IMAGE_CACHE_KEY);
51
52 Image image = null;
53 if (imageCache.containsKey(path)) {
54 image = imageCache.get(path).get(preferredSize);
55 }
56 if (image != null)
57 return image;
58 ImageData imageData = loadFromSvg(path, preferredSize);
59 image = new Image(display, imageData);
60 if (!imageCache.containsKey(path))
61 imageCache.put(path, Collections.synchronizedMap(new HashMap<>()));
62 imageCache.get(path).put(preferredSize, image);
63 return image;
64 }
65
66 protected ImageData loadFromSvg(String path, int size) {
67 ImageData imageData = null;
68 if (imageDataCache.containsKey(path))
69 imageData = imageDataCache.get(path).get(size);
70 if (imageData != null)
71 return imageData;
72
73 ImageTranscoder transcoder = null;
74 synchronized (this) {
75 transcoder = transcoders.get(size);
76 if (transcoder == null) {
77 transcoder = new PNGTranscoder();
78 transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) size);
79 transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) size);
80 transcoder.addTranscodingHint(PNGTranscoder.KEY_BACKGROUND_COLOR, new Color(255, 255, 255, 0));
81 transcoders.put(size, transcoder);
82 }
83 }
84 try (InputStream in = getResourceAsStream(path); ByteArrayOutputStream out = new ByteArrayOutputStream();) {
85 if (in == null)
86 throw new IllegalArgumentException(path + " not found");
87 TranscoderInput input = new TranscoderInput(in);
88 TranscoderOutput output = new TranscoderOutput(out);
89 transcoder.transcode(input, output);
90 try (InputStream imageIn = new ByteArrayInputStream(out.toByteArray())) {
91 imageData = new ImageData(imageIn);
92 }
93 logger.log(Level.DEBUG, () -> "Generated " + size + "x" + size + " PNG icon from " + path);
94 } catch (IOException | TranscoderException e) {
95 throw new RuntimeException("Cannot transcode SVG " + path, e);
96 }
97
98 // cache it
99 if (!imageDataCache.containsKey(path))
100 imageDataCache.put(path, Collections.synchronizedMap(new HashMap<>()));
101 imageDataCache.get(path).put(size, imageData);
102
103 return imageData;
104 }
105
106 @Override
107 public void init(BundleContext bundleContext, Map<String, String> properties) {
108 super.init(bundleContext, properties);
109
110 // preload all icons
111 // paths: for (String p : getImagesPaths()) {
112 // if (!p.endsWith(".svg"))
113 // continue paths;
114 // createImageFromSvg(p, getDefaultIconSize());
115 // }
116 }
117
118 // @Override
119 // public void destroy(BundleContext bundleContext, Map<String, String> properties) {
120 // Display display = Display.getDefault();
121 // if (display != null)
122 // for (String path : imageCache.keySet()) {
123 // for (Image image : imageCache.get(path).values()) {
124 // display.syncExec(() -> image.dispose());
125 // }
126 // }
127 // super.destroy(bundleContext, properties);
128 // }
129
130 }