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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 21:28:45  来源:igfitidea点击:

Swing & Batik: Create an ImageIcon from an SVG file?

javaswingsvgiconsbatik

提问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;
    }
  }
}