[JME3] (static) SVG Texture Loader

I post this here and not in user contribution because the requirements are a bit heavy: the loader uses batik and that alone weights 8 megabytes. Anyway i’m using it for a game, why not to share.



Project Type: JME3 Texture loader plugin

Project License: MIT

Status: completed

Required libraries: JME3, Batik







The project is made of 2 little classes, all the job is done by batik.


package jme3svg;

import com.jme3.asset.AssetInfo;
import com.jme3.asset.AssetLoader;
import com.jme3.texture.plugins.AWTLoader;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.IOException;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.ImageTranscoder;

/**
 * A texture loader for svg images.
 * @author pgi
 */
public class SVGLoader implements AssetLoader {
    private static final class BufferedImageTranscoderOutput extends TranscoderOutput {
   private BufferedImage buffer;
    }
    private static final class BufferedImageTranscoder extends ImageTranscoder {

   @Override
   public BufferedImage createImage(int w, int h) {
       return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
   }

   @Override
   public void writeImage(BufferedImage bi, TranscoderOutput to) throws TranscoderException {
       ((BufferedImageTranscoderOutput) to).buffer = bi;
   }

    }

    /**
     * Transforms a svg image in a jme texture
     * @param assetInfo the resource to load (better if it is a svg image)
     * @return a jme3 texture object
     * @throws IOException if something goes really bad.
     */
    public Object load(AssetInfo assetInfo) throws IOException {
   TranscoderInput input = new TranscoderInput(assetInfo.openStream());
   BufferedImageTranscoderOutput output = new BufferedImageTranscoderOutput();
   BufferedImageTranscoder transcoder = new BufferedImageTranscoder();
   if(assetInfo.getKey() instanceof SVGTextureKey) {
       SVGTextureKey key = (SVGTextureKey) assetInfo.getKey();
       Dimension size = key.getRequiredSize();
       if(size != null) {
      transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH, new Float(size.width));
      transcoder.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, new Float(size.height));
       }
   }
   try {
       transcoder.transcode(input, output);
       return new AWTLoader().load(output.buffer, true);
   } catch (TranscoderException ex) {
       throw new IOException(ex);
   }
    }

}



package jme3svg;

import com.jme3.asset.TextureKey;
import java.awt.Dimension;

/**
 * A texture key that can be used to specify the output dimension of a svg image.
 * Using this key is required only if you want to scale the image specified in
 * a svg document.
 * @author pgi
 */
public class SVGTextureKey extends TextureKey {
    private final Dimension SIZE;
    private final int hash;

    /**
     * Initializes this SVGTextureKey
     * @param name the name of the svg resource to load
     * @param outputImageSize the size of the image produced by the svg loader
     */
    public SVGTextureKey(String name, Dimension outputImageSize) {
   super(name);
   this.SIZE = new Dimension(outputImageSize);
   hash = new Long((((long)name.hashCode()) << 32) + (long) SIZE.hashCode()).hashCode();
    }

    /**
     * Returns the hash code of this key, based on the name of the resource and
     * the size of the requested image
     * @return the hash code of this key.
     */
    @Override
    public int hashCode() {
   return hash;
    }

    /**
     * True if the given object is a SVGTextureKey instance denoting the same
     * image at the same size
     * @param obj the object to test for equality
     * @return true if that object equals this.
     */
    @Override
    public boolean equals(Object obj) {
   if (obj == null) {
       return false;
   }
   if (getClass() != obj.getClass()) {
       return false;
   }
   final SVGTextureKey other = (SVGTextureKey) obj;
   if (this.hash != other.hash) {
       return false;
   }
   return true;
    }

    public Dimension getRequiredSize() {
   return SIZE;
    }
}



Usage:

assetManager.registerLoader(SVGLoader.class.getName(), "svg");
Texture textureOriginal = assetManager.loadTexture("a svg resource");
Texture textureScaled = assetManager.loadTexture(new SVGTextureKey("a svg resource", new Dimension(64, 64));

pgi said:

I post this here and not in user contribution because the requirements are a bit heavy: the loader uses batik and that alone weights 8 megabytes. Anyway i'm using it for a game, why not to share.


Wow, that's a large library.  Great work though!

Unfortunately i couldn't find a lighter library to render svg on buffered images. Embedding support for svg images in JME3, even if only static, would be great.