Swing & Batik: Создайте ImageIcon из SVG файла?
Проще говоря, я ищу способ сделать ImageIcon из SVG файла, используя библиотеку batik. Я не хочу, чтобы сначала растрировать SVG на диск, я просто хочу, чтобы вытащить svg из файла jar и принести его как элемент пользовательского интерфейса.
Я чувствую, что это должно быть достаточно легко, но батика javadocs не сообщают мне, что мне нужно знать.
(Почему батик? Ну, мы уже его используем, поэтому нам не нужно запускать другую библиотеку, прошедшую юридическую проверку.)
Ответы
Ответ 1
Это действительно очень просто, просто не очень интуитивно.
Вам нужно расширить ImageTranscoder
. В методе createImage
вы выделяете BufferedImage
, кешируете его как переменную-член и возвращаете. Метод writeImage
пуст. И вам нужно будет добавить getter для получения BufferedImage
.
Он будет выглядеть примерно так:
class MyTranscoder extends ImageTranscoder {
private BufferedImage image = null;
public BufferedImage createImage(int w, int h) {
image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
return image;
}
public void writeImage(BufferedImage img, TranscoderOutput out) {
}
public BufferedImage getImage() {
return image;
}
}
Теперь, чтобы создать образ, вы создаете экземпляр вашего транскодера и передаете ему требуемую ширину и высоту, установив TranscodingHints
. Наконец, вы перекодируете из TranscoderInput в нулевую цель. Затем позвоните получателю на транскодер, чтобы получить изображение.
Вызов выглядит примерно так:
MyTranscoder transcoder = new MyTransCoder();
TranscodingHints hints = new TranscodingHints();
hints.put(ImageTranscoder.KEY_WIDTH, width);
hints.put(ImageTranscoder.KEY_HEIGHT, height);
transcoder.setTranscodingHints(hints);
transcoder.transcode(new TranscoderInput(url), null);
BufferedImage image = transcoder.getImage();
Простой, не так ли? (Да, правильно. Мне потребовалось всего 2 недели, чтобы понять это. Вздох.)
Ответ 2
Я только что последовал Devon с Batik-1.7
Однако для того, чтобы заставить его работать, мне пришлось сделать следующие дополнения к объекту подсказок:
MyTranscoder transcoder =new MyTranscoder()
DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
TranscodingHints hints = new TranscodingHints();
hints.put(ImageTranscoder.KEY_WIDTH, width); // e.g. width=new Float(300)
hints.put(ImageTranscoder.KEY_HEIGHT,height);// e.g. height=new Float(75)
hints.put(ImageTranscoder.KEY_DOM_IMPLEMENTATION, impl.getDOMImplementation());
hints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,SVGConstants.SVG_NAMESPACE_URI);
hints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI,SVGConstants.SVG_NAMESPACE_URI);
hints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT, SVGConstants.SVG_SVG_TAG);
hints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, false);
transcoder.setTranscodingHints(hints);
TranscoderInput ti=new TranscoderInput(uri)
transcoder.transcode(ti, null);
BufferedImage image = transcoder.getImage();
Кажется, что что-то обновлено в batik XMLAbstractTranscoder (http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/transcoder/XMLAbstractTranscoder.java) с версией 1.7.
Ответ 3
Если вы больше не хотите включать зависимость от Batik в своем приложении, вы можете преобразовать SVG файл непосредственно в Java2D с помощью Transcoder Flamingo SVG:
http://ebourg.github.com/flamingo-svg-transcoder
Он генерирует классы значков, примерно эквивалентные по размеру сжатому SVG файлу. Сгенерированный код не имеет внешней зависимости.
Ответ 4
Чтобы избежать прохождения параметров dom:
transcoder.setTranscodingHints((Map<?, ?>) hints);
Ответ 5
Я пробовал использовать предложения Девона и Джона, которые почти сработали для меня. Я должен был сделать некоторые трюки следующим образом, не стесняйтесь использовать:
package com.corp.util;
import static org.apache.batik.transcoder.SVGAbstractTranscoder.KEY_WIDTH;
import static org.apache.batik.transcoder.XMLAbstractTranscoder.KEY_DOCUMENT_ELEMENT;
import static org.apache.batik.transcoder.XMLAbstractTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI;
import static org.apache.batik.transcoder.XMLAbstractTranscoder.KEY_DOM_IMPLEMENTATION;
import static org.apache.batik.util.SVGConstants.SVG_NAMESPACE_URI;
import static org.apache.batik.util.SVGConstants.SVG_SVG_TAG;
import com.google.common.flogger.GoogleLogger;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.TranscodingHints;
import org.apache.batik.transcoder.image.ImageTranscoder;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Singleton;
/** Loads SVG images from disk. See https://en.wikipedia.org/wiki/Scalable_Vector_Graphics. */
@Singleton
@ThreadSafe
public class SvgImageLoader {
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
/**
* Reads in an SVG image file and return it as a BufferedImage with the given width and a height
* where the original aspect ratio is preserved.
*
* @param url URL referencing the SVG image file, which is typically an XML file
* @param width width in pixels the returned BufferedImage should be
*
* @return a valid image representing the SVG file
* @throws IOException if the file cannot be parsed as valid SVG
*/
public static BufferedImage loadSvg(URL url, float width) throws IOException {
SvgTranscoder transcoder = new SvgTranscoder();
transcoder.setTranscodingHints(getHints(width));
try {
TranscoderInput input = new TranscoderInput(url.openStream());
transcoder.transcode(input, null);
} catch (TranscoderException e) {
throw new IOException("Error parsing SVG file " + url, e);
}
BufferedImage image = transcoder.getImage();
logger.atInfo().log("Read '%s' SVG image from disk requested with width=%.1f, sized as %dx%d pixels.",
new File(url.getFile()).getName(), width, image.getWidth(), image.getHeight());
return image;
}
private static TranscodingHints getHints(float width) {
TranscodingHints hints = new TranscodingHints();
hints.put(KEY_DOM_IMPLEMENTATION, SVGDOMImplementation.getDOMImplementation());
hints.put(KEY_DOCUMENT_ELEMENT_NAMESPACE_URI, SVG_NAMESPACE_URI);
hints.put(KEY_DOCUMENT_ELEMENT, SVG_SVG_TAG);
hints.put(KEY_WIDTH, width);
return hints;
}
private static class SvgTranscoder extends ImageTranscoder {
private BufferedImage image = null;
@Override
public BufferedImage createImage(int width, int height) {
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
return image;
}
@Override
public void writeImage(BufferedImage img, TranscoderOutput out) {}
BufferedImage getImage() {
return image;
}
}
}