2010-03-22 19 views
15

Nói một cách đơn giản, tôi đang tìm cách tạo một ImageIcon từ một tệp SVG bằng thư viện batik. Tôi không muốn phải raster SVG vào đĩa đầu tiên, tôi chỉ muốn có thể kéo một svg ra khỏi tập tin jar và có nó đất như là một yếu tố giao diện người dùng.Swing & Batik: Tạo một ImageIcon từ một tệp SVG?

Tôi cảm thấy điều này nên hợp lý dễ dàng, nhưng batj javadocs không cho tôi biết những gì tôi cần biết.

(Tại sao batik? Vâng, chúng tôi đã sử dụng nó, vì vậy chúng tôi không cần phải chạy một thư viện qua quy phạm pháp luật.)

Trả lời

18

Nó thực sự khá dễ dàng, chỉ cần không phải là rất trực quan.

Bạn cần gia hạn ImageTranscoder. Trong phương thức createImage, bạn phân bổ BufferedImage, hãy lưu nó làm biến thành viên và trả lại. Phương thức writeImage trống. Và bạn sẽ cần phải thêm một getter để lấy BufferedImage.

Nó sẽ giống như thế này:

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

Bây giờ, để tạo ra một hình ảnh mà bạn tạo ra một thể hiện của chuyển mã của bạn và vượt qua nó với chiều rộng và chiều cao mong muốn bằng cách thiết lập TranscodingHints. Cuối cùng, bạn chuyển mã từ TranscoderInput thành một mục tiêu rỗng. Sau đó, gọi bộ thu phát trên bộ chuyển mã của bạn để lấy hình ảnh.

Cuộc gọi trông giống như sau:

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(); 

đơn giản, phải không? (Ừ, đúng vậy. Chỉ đưa tôi 2 tuần để con số đó ra. Thở dài).

+3

Đúng vậy, những gì Devon nói. :) Đây là lớp SVGIcon của tôi mà khá nhiều hiện rằng: http://mcc.id.au/2005/04/SVGIcon.java – heycam

+0

Dòng mở của câu trả lời này niêm phong nó cho tôi. Tại sao tôi không thể cung cấp nhiều hơn 1 cho câu trả lời này? Đây là ** chính xác ** những gì làm cho SO rất tốt. – kevinarpe

3

Tôi vừa đi theo cách tiếp cận của Devon với Batik-1,7

Tuy nhiên, để làm cho nó làm việc tôi đã phải thực hiện những điều sau đây bổ sung vào các gợi ý phản đối:

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(); 

có vẻ như một cái gì đó đã được cập nhật trong XMLAbstractTranscoder batik của (http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/transcoder/XMLAbstractTranscoder.java) với phiên bản 1.7.

2

Nếu bao giờ bạn không còn muốn bao gồm sự phụ thuộc vào Batik trong ứng dụng của bạn, bạn có thể chuyển đổi một tập tin SVG trực tiếp vào Java2D với Transcoder Flamingo SVG:

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

Nó tạo lớp biểu tượng tương đương trong kích thước cho tệp SVG được nén. Mã được tạo không có sự phụ thuộc bên ngoài.

+0

Để xác minh, câu trả lời của bạn là thay vì cố gắng đọc và hiển thị svg khi chạy (và bao gồm tất cả các phụ thuộc) một cách tiếp cận khác là chuyển mã SVG thành tệp lớp tại thời gian biên dịch (chỉ hệ thống xây dựng cần batik). Tệp lớp sau đó được đóng gói cùng với ứng dụng. – Ryan

+0

Vâng, đó chính xác là mục đích của bộ chuyển mã. –

0

Để tránh các thông số qua dom: transcoder.setTranscodingHints((Map<?, ?>) hints);

+0

Đó phải là một bình luận cho @ John Doppelmann phải không? Sau đó, không "trả lời", vui lòng sử dụng bình luận nếu có thể. – Manuel

0

tôi đã cố gắng sử dụng Devon và John đề nghị, mà gần như làm việc cho tôi. Tôi phải thực hiện một số chỉnh sửa như sau, vui lòng sử dụng:

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