简单地说,我正在寻找一种使用batik库从SVG文件制作ImageIcon的方法。我不想首先将SVG光栅转换为磁盘,我只是希望能够从jar文件中提取svg并将其作为UI元素登陆。
我觉得这应该相当容易,但蜡染javadocs并没有告诉我我需要知道什么。
(为什么选择蜡染?好吧,我们已经在使用它了,所以我们不必经过另一个合法的图书馆。)
答案 0 :(得分:19)
这真的很容易,只是不太直观。
您需要延长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转码为空目标。然后调用代码转换器上的getter来获取图像。
电话看起来像这样:
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();
简单,对吧? (是的,没错。只花了我两个星期的时间来解决这个问题。叹气。)
答案 1 :(得分:3)
我刚跟随德文与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();
似乎已经在版本为1.7的batik的XMLAbstractTranscoder(http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/transcoder/XMLAbstractTranscoder.java)中更新了某些内容。
答案 2 :(得分:3)
如果您不再希望在应用程序中包含对Batik的依赖性,您可以使用Flamingo SVG Transcoder将SVG文件直接转换为Java2D:
http://ebourg.github.com/flamingo-svg-transcoder
它生成的图标类大小与压缩的SVG文件大小相当。生成的代码没有外部依赖。
答案 3 :(得分:0)
避免传递dom参数:
transcoder.setTranscodingHints((Map<?, ?>) hints);
答案 4 :(得分:0)
我尝试使用Devon和John的建议,这几乎对我有用。我不得不做如下调整,随意使用:
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;
}
}
}