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

前端 未结 5 2180
我寻月下人不归
我寻月下人不归 2021-01-31 19:35

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

相关标签:
5条回答
  • 2021-01-31 20:01

    I have just followed Devon's approach with 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.

    0 讨论(0)
  • 2021-01-31 20:03

    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:

    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.

    0 讨论(0)
  • 2021-01-31 20:06

    It's really quite easy, just not very intuitive.

    You need to extend ImageTranscoder. In the createImage method you allocate a BufferedImage, cache it as a member variable, and return it. The writeImage method is empty. And you'll need to add a getter to retrieve the 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.

    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.)

    0 讨论(0)
  • 2021-01-31 20:06

    To avoid passing dom parameters : transcoder.setTranscodingHints((Map<?, ?>) hints);

    0 讨论(0)
  • 2021-01-31 20:17

    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;
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题