简体   繁体   English

Swing&Batik:从SVG文件创建ImageIcon?

[英]Swing & Batik: Create an ImageIcon from an SVG file?

Simply put, I'm looking for a way to make an ImageIcon from an SVG file using the batik library. 简单地说,我正在寻找一种使用batik库从SVG文件制作ImageIcon的方法。 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光栅转换为磁盘,我只是希望能够从jar文件中提取svg并将其作为UI元素。

I feel like this should be reasonably easy, but the batik javadocs aren't telling me what I need to know. 我觉得这应该相当容易,但蜡染javadocs并没有告诉我我需要知道什么。

(Why batik? Well, we're already using it, so we don't have to run another library past legal.) (为什么选择蜡染?好吧,我们已经在使用它了,所以我们不必经营另一个合法的图书馆。)

It's really quite easy, just not very intuitive. 这真的很容易,只是不太直观。

You need to extend ImageTranscoder . 您需要扩展ImageTranscoder In the createImage method you allocate a BufferedImage , cache it as a member variable, and return it. createImage方法中,您可以分配BufferedImage ,将其作为成员变量进行缓存,然后将其返回。 The writeImage method is empty. writeImage方法为空。 And you'll need to add a getter to retrieve the BufferedImage . 并且您需要添加一个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 . 现在,要创建一个图像,您需要创建一个转码器的实例,并通过设置TranscodingHints将其传递给所需的宽度和高度。 Finally you transcode from a TranscoderInput to a null target. 最后,您从TranscoderInput转码为空目标。 Then call the getter on your transcoder to obtain the image. 然后调用代码转换器上的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.) (是的,没错。只花了我两个星期的时间来解决这个问题。叹了口气。)

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. 它生成的图标类大小与压缩的SVG文件大小相当。 The code generated has no external dependency. 生成的代码没有外部依赖。

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. 好像在batik的XMLAbstractTranscoder( http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/transcoder/XMLAbstractTranscoder.java )中更新了一些版本1.7。

为了避免传递dom参数: transcoder.setTranscodingHints((Map<?, ?>) hints);

I tried using Devon's and John's suggestions, which nearly worked for me. 我尝试使用Devon和John的建议,这几乎对我有用。 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;
    }
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM