1 package org
.argeo
.app
.swt
.osgi
;
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
;
13 import java
.util
.Objects
;
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
.argeo
.cms
.swt
.osgi
.BundleCmsSwtTheme
;
21 import org
.eclipse
.swt
.graphics
.Image
;
22 import org
.eclipse
.swt
.graphics
.ImageData
;
23 import org
.eclipse
.swt
.widgets
.Display
;
24 import org
.osgi
.framework
.BundleContext
;
26 /** Theme which can dynamically create icons from SVG data. */
27 public class BundleSvgTheme
extends BundleCmsSwtTheme
{
28 private final static Logger logger
= System
.getLogger(BundleSvgTheme
.class.getName());
30 private Map
<String
, Map
<Integer
, ImageData
>> imageDataCache
= Collections
.synchronizedMap(new HashMap
<>());
32 private Map
<Integer
, ImageTranscoder
> transcoders
= Collections
.synchronizedMap(new HashMap
<>());
34 private final static String IMAGE_CACHE_KEY
= BundleSvgTheme
.class.getName() + ".imageCache";
37 public Image
getIcon(String name
, Integer preferredSize
) {
38 String path
= "icons/types/svg/" + name
+ ".svg";
39 return createImageFromSvg(path
, preferredSize
);
42 @SuppressWarnings("unchecked")
43 protected Image
createImageFromSvg(String path
, Integer preferredSize
) {
44 Display display
= Display
.getCurrent();
45 Objects
.requireNonNull(display
, "Not a user interface thread");
47 Map
<String
, Map
<Integer
, Image
>> imageCache
= (Map
<String
, Map
<Integer
, Image
>>) display
48 .getData(IMAGE_CACHE_KEY
);
49 if (imageCache
== null)
50 display
.setData(IMAGE_CACHE_KEY
, new HashMap
<String
, Map
<Integer
, Image
>>());
51 imageCache
= (Map
<String
, Map
<Integer
, Image
>>) display
.getData(IMAGE_CACHE_KEY
);
54 if (imageCache
.containsKey(path
)) {
55 image
= imageCache
.get(path
).get(preferredSize
);
59 ImageData imageData
= loadFromSvg(path
, preferredSize
);
60 image
= new Image(display
, imageData
);
61 if (!imageCache
.containsKey(path
))
62 imageCache
.put(path
, Collections
.synchronizedMap(new HashMap
<>()));
63 imageCache
.get(path
).put(preferredSize
, image
);
67 protected ImageData
loadFromSvg(String path
, int size
) {
68 ImageData imageData
= null;
69 if (imageDataCache
.containsKey(path
))
70 imageData
= imageDataCache
.get(path
).get(size
);
71 if (imageData
!= null)
74 ImageTranscoder transcoder
= null;
76 transcoder
= transcoders
.get(size
);
77 if (transcoder
== null) {
78 transcoder
= new PNGTranscoder();
79 transcoder
.addTranscodingHint(PNGTranscoder
.KEY_WIDTH
, (float) size
);
80 transcoder
.addTranscodingHint(PNGTranscoder
.KEY_HEIGHT
, (float) size
);
81 transcoder
.addTranscodingHint(PNGTranscoder
.KEY_BACKGROUND_COLOR
, new Color(255, 255, 255, 0));
82 transcoders
.put(size
, transcoder
);
85 try (InputStream in
= getResourceAsStream(path
); ByteArrayOutputStream out
= new ByteArrayOutputStream();) {
87 throw new IllegalArgumentException(path
+ " not found");
88 TranscoderInput input
= new TranscoderInput(in
);
89 TranscoderOutput output
= new TranscoderOutput(out
);
90 transcoder
.transcode(input
, output
);
91 try (InputStream imageIn
= new ByteArrayInputStream(out
.toByteArray())) {
92 imageData
= new ImageData(imageIn
);
94 logger
.log(Level
.DEBUG
, () -> "Generated " + size
+ "x" + size
+ " PNG icon from " + path
);
95 } catch (IOException
| TranscoderException e
) {
96 throw new RuntimeException("Cannot transcode SVG " + path
, e
);
100 if (!imageDataCache
.containsKey(path
))
101 imageDataCache
.put(path
, Collections
.synchronizedMap(new HashMap
<>()));
102 imageDataCache
.get(path
).put(size
, imageData
);
108 public void init(BundleContext bundleContext
, Map
<String
, String
> properties
) {
109 super.init(bundleContext
, properties
);
112 // paths: for (String p : getImagesPaths()) {
113 // if (!p.endsWith(".svg"))
115 // createImageFromSvg(p, getDefaultIconSize());
120 // public void destroy(BundleContext bundleContext, Map<String, String> properties) {
121 // Display display = Display.getDefault();
122 // if (display != null)
123 // for (String path : imageCache.keySet()) {
124 // for (Image image : imageCache.get(path).values()) {
125 // display.syncExec(() -> image.dispose());
128 // super.destroy(bundleContext, properties);