2010-03-22 164 views
15

簡而言之,我正在尋找一種方法來使用蠟染庫從SVG文件製作ImageIcon。我不想先將SVG光柵化到磁盤上,我只是希望能夠從jar文件中拉出一個svg,並將其作爲UI元素登陸。Swing&Batik:從SVG文件創建一個ImageIcon?

我覺得這應該是相當容易的,但蠟染javadocs並沒有告訴我我需要知道什麼。

(蠟染爲什麼?嗯,我們已經在使用它,所以我們不必再跑過去圖書館法律。)

回答

18

這真的很容易,只要不是很直觀。您需要延長ImageTranscoder。在createImage方法中,您分配一個BufferedImage,將其緩存爲成員變量並返回。 writeImage方法爲空。並且您需要添加一個吸氣器來檢索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(); 

簡單,對不對? (是的,沒錯。我只用了2個星期明白這一點。嘆了口氣。)

+3

是的,德文說什麼。 :)這是我的SVGIcon類,它幾乎是這樣做的:http://mcc.id.au/2005/04/SVGIcon.java – heycam 2010-03-22 22:31:17

+0

這個答案的開頭一行對我來說是封閉的。爲什麼我不能給這個答案+1以上?這完全**是什麼讓SO如此好。 – kevinarpe 2013-07-29 08:20:42

3

我剛纔跟着德文郡與蠟染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(); 

好像有什麼東西被蠟染的XMLAbstractTranscoder(http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/transcoder/XMLAbstractTranscoder.java)1.7版本更新。

2

要是你不再希望包括蠟染的依賴在你的應用程序,你可以將一個SVG文件直接導入的Java2D與火烈鳥SVG轉碼器:

http://ebourg.github.com/flamingo-svg-transcoder

它生成圖標班大約相當於大小轉換爲壓縮的SVG文件。生成的代碼沒有外部依賴性。

+0

爲了驗證,你的答案是,不要試圖在運行時讀取和渲染svg(幷包含所有依賴),另一種方法是在編譯時將SVG轉換爲類文件(只有構建系統需要蠟染)。類文件隨後與應用程序打包在一起。 – Ryan 2015-04-15 20:46:33

+0

是的,這正是轉碼器的目的。 – 2015-04-16 22:16:28

0

避免將DOM參數: transcoder.setTranscodingHints((Map<?, ?>) hints);

+0

這應該是@John Doppelmann的評論吧?那麼請不要「回答」它,如果可能的話使用評論。 – Manuel 2013-08-03 17:56:23

0

我試着用德文郡和約翰的建議,這幾乎爲我工作。我不得不做一些調整如下,隨意使用:

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