java Swing & Batik:从 SVG 文件创建一个 ImageIcon?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2495501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Swing & Batik: Create an ImageIcon from an SVG file?
提问by Electrons_Ahoy
Simply put, I'm looking for a way to make an ImageIcon from an SVG file using the batik library. I don't want to have to raster the SVG to disk first, I just want to be able to pull an svg out of the jar file and have it land as a UI element.
简而言之,我正在寻找一种使用蜡染库从 SVG 文件制作 ImageIcon 的方法。我不想先将 SVG 光栅化到磁盘,我只想能够从 jar 文件中提取一个 svg 并将其作为 UI 元素放置。
I feel like this should be reasonably easy, but the batik javadocs aren't telling me what I need to know.
我觉得这应该相当容易,但蜡染 javadoc 并没有告诉我我需要知道什么。
(Why batik? Well, we're already using it, so we don't have to run another library past legal.)
(为什么是蜡染?嗯,我们已经在使用它了,所以我们不必运行另一个合法的图书馆。)
回答by Devon_C_Miller
It's really quite easy, just not very intuitive.
这真的很容易,只是不是很直观。
You need to extend ImageTranscoder. In the createImagemethod you allocate a BufferedImage, cache it as a member variable, and return it. The writeImagemethod is empty. And you'll need to add a getter to retrieve the BufferedImage.
您需要扩展ImageTranscoder. 在createImage分配 a的方法中,将其BufferedImage缓存为成员变量,然后返回它。该writeImage方法为空。并且您需要添加一个 getter 来检索BufferedImage.
It will look something like this:
它看起来像这样:
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;
}
}
Now, to create an image you create an instance of your transcoder and pass it the desired width and height by setting TranscodingHints. Finally you transcode from a TranscoderInput to a null target. Then call the getter on your transcoder to obtain the image.
现在,要创建图像,您需要创建转码器的一个实例,并通过设置TranscodingHints. 最后,您从 TranscoderInput 转码为空目标。然后调用转码器上的 getter 来获取图像。
The call looks something like this:
调用看起来像这样:
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();
Simple, right? (Yeah, right. Only took me 2 weeks to figure that out. Sigh.)
很简单吧?(是的,对。我只花了 2 周的时间才弄明白。叹气。)
回答by John Doppelmann
I have just followed Devon's approach with Batik-1.7
我刚刚按照德文的方法使用 Batik-1.7
However, in order to make it work I had to make the following additions to the hints object:
但是,为了使其工作,我必须对提示对象进行以下添加:
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();
Seems like something has been updated in batik's XMLAbstractTranscoder( http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/transcoder/XMLAbstractTranscoder.java) with version 1.7.
似乎蜡染的 XMLAbstractTranscoder( http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/transcoder/XMLAbstractTranscoder.java) 中的某些内容已更新为版本1.7.
回答by Emmanuel Bourg
If ever you no longer wish to include the dependency on Batik in your application you can transform a SVG file directly into Java2D with the Flamingo SVG Transcoder:
如果您不再希望在您的应用程序中包含对 Batik 的依赖,您可以使用 Flamingo SVG Transcoder 将 SVG 文件直接转换为 Java2D:
http://ebourg.github.com/flamingo-svg-transcoder
http://ebourg.github.com/flamingo-svg-transcoder
It generates icon classes roughly equivalent in size to a compressed SVG file. The code generated has no external dependency.
它生成大小与压缩 SVG 文件大致相同的图标类。生成的代码没有外部依赖。
回答by hadf
To avoid passing dom parameters :transcoder.setTranscodingHints((Map<?, ?>) hints);
为避免传递 dom 参数:transcoder.setTranscodingHints((Map<?, ?>) hints);
回答by Dov Wasserman
I tried using Devon's and John's suggestions, which nearly worked for me. I had to make some tweaks as follows, feel free to use:
我尝试使用德文和约翰的建议,这几乎对我有用。我不得不做一些调整如下,随意使用:
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;
}
}
}

