X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=swt%2Forg.argeo.app.swt%2Fsrc%2Forg%2Fargeo%2Fapp%2Fswt%2Fosgi%2FBundleSvgTheme.java;fp=swt%2Forg.argeo.app.swt%2Fsrc%2Forg%2Fargeo%2Fapp%2Fswt%2Fosgi%2FBundleSvgTheme.java;h=15a18ae65822a33153b87f62d02063fa2298e006;hb=d7da00bfd0ae230b97abccb2cc9d091e34c11632;hp=0000000000000000000000000000000000000000;hpb=26edd36fbbd565d7459a134a20a9c60d489dbb35;p=gpl%2Fargeo-suite.git diff --git a/swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/BundleSvgTheme.java b/swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/BundleSvgTheme.java new file mode 100644 index 0000000..15a18ae --- /dev/null +++ b/swt/org.argeo.app.swt/src/org/argeo/app/swt/osgi/BundleSvgTheme.java @@ -0,0 +1,131 @@ +package org.argeo.app.swt.osgi; + +import java.awt.Color; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.System.Logger; +import java.lang.System.Logger.Level; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import org.apache.batik.transcoder.TranscoderException; +import org.apache.batik.transcoder.TranscoderInput; +import org.apache.batik.transcoder.TranscoderOutput; +import org.apache.batik.transcoder.image.ImageTranscoder; +import org.apache.batik.transcoder.image.PNGTranscoder; +import org.argeo.cms.swt.osgi.BundleCmsSwtTheme; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.widgets.Display; +import org.osgi.framework.BundleContext; + +/** Theme which can dynamically create icons from SVG data. */ +public class BundleSvgTheme extends BundleCmsSwtTheme { + private final static Logger logger = System.getLogger(BundleSvgTheme.class.getName()); + + private Map> imageDataCache = Collections.synchronizedMap(new HashMap<>()); + + private Map transcoders = Collections.synchronizedMap(new HashMap<>()); + + private final static String IMAGE_CACHE_KEY = BundleSvgTheme.class.getName() + ".imageCache"; + + @Override + public Image getIcon(String name, Integer preferredSize) { + String path = "icons/types/svg/" + name + ".svg"; + return createImageFromSvg(path, preferredSize); + } + + @SuppressWarnings("unchecked") + protected Image createImageFromSvg(String path, Integer preferredSize) { + Display display = Display.getCurrent(); + Objects.requireNonNull(display, "Not a user interface thread"); + + Map> imageCache = (Map>) display + .getData(IMAGE_CACHE_KEY); + if (imageCache == null) + display.setData(IMAGE_CACHE_KEY, new HashMap>()); + imageCache = (Map>) display.getData(IMAGE_CACHE_KEY); + + Image image = null; + if (imageCache.containsKey(path)) { + image = imageCache.get(path).get(preferredSize); + } + if (image != null) + return image; + ImageData imageData = loadFromSvg(path, preferredSize); + image = new Image(display, imageData); + if (!imageCache.containsKey(path)) + imageCache.put(path, Collections.synchronizedMap(new HashMap<>())); + imageCache.get(path).put(preferredSize, image); + return image; + } + + protected ImageData loadFromSvg(String path, int size) { + ImageData imageData = null; + if (imageDataCache.containsKey(path)) + imageData = imageDataCache.get(path).get(size); + if (imageData != null) + return imageData; + + ImageTranscoder transcoder = null; + synchronized (this) { + transcoder = transcoders.get(size); + if (transcoder == null) { + transcoder = new PNGTranscoder(); + transcoder.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) size); + transcoder.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) size); + transcoder.addTranscodingHint(PNGTranscoder.KEY_BACKGROUND_COLOR, new Color(255, 255, 255, 0)); + transcoders.put(size, transcoder); + } + } + try (InputStream in = getResourceAsStream(path); ByteArrayOutputStream out = new ByteArrayOutputStream();) { + if (in == null) + throw new IllegalArgumentException(path + " not found"); + TranscoderInput input = new TranscoderInput(in); + TranscoderOutput output = new TranscoderOutput(out); + transcoder.transcode(input, output); + try (InputStream imageIn = new ByteArrayInputStream(out.toByteArray())) { + imageData = new ImageData(imageIn); + } + logger.log(Level.DEBUG, () -> "Generated " + size + "x" + size + " PNG icon from " + path); + } catch (IOException | TranscoderException e) { + throw new RuntimeException("Cannot transcode SVG " + path, e); + } + + // cache it + if (!imageDataCache.containsKey(path)) + imageDataCache.put(path, Collections.synchronizedMap(new HashMap<>())); + imageDataCache.get(path).put(size, imageData); + + return imageData; + } + + @Override + public void init(BundleContext bundleContext, Map properties) { + super.init(bundleContext, properties); + + // preload all icons +// paths: for (String p : getImagesPaths()) { +// if (!p.endsWith(".svg")) +// continue paths; +// createImageFromSvg(p, getDefaultIconSize()); +// } + } + +// @Override +// public void destroy(BundleContext bundleContext, Map properties) { +// Display display = Display.getDefault(); +// if (display != null) +// for (String path : imageCache.keySet()) { +// for (Image image : imageCache.get(path).values()) { +// display.syncExec(() -> image.dispose()); +// } +// } +// super.destroy(bundleContext, properties); +// } + +}