Java svg to bufferedimage

How to get a BufferedImage from a SVG?

So for example you just add these to your maven (or copy the needed jars):

  com.twelvemonkeys.imageio imageio-batik 3.2.1  batik batik-transcoder 1.6-1  

And then you just read it with

BufferedImage image = ImageIO.read(svg-file); 

To check if the svg reader is registered correctly you could print out the image readers:

Iterator readers = ImageIO.getImageReadersByFormatName("SVG"); while (readers.hasNext())

The lib also supports additional params, see readme on github.

Solution 3

9 years later here is an other solution with Batik :

implementation ‘org.apache.xmlgraphics:batik-all:1.14’

implementation ‘org.apache.xmlgraphics:batik-swing:1.14’

import lombok.extern.slf4j.Slf4j; import org.apache.batik.transcoder.Transcoder; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.image.PNGTranscoder; import org.springframework.stereotype.Component; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @Slf4j @Component public class SvgToRasterizeImageConverter < public BufferedImage transcodeSVGToBufferedImage(File file, int width, int height) < // Create a PNG transcoder. Transcoder t = new PNGTranscoder(); // Set the transcoding hints. t.addTranscodingHint(PNGTranscoder.KEY_WIDTH, (float) width); t.addTranscodingHint(PNGTranscoder.KEY_HEIGHT, (float) height); try (FileInputStream inputStream = new FileInputStream(file)) < // Create the transcoder input. TranscoderInput input = new TranscoderInput(inputStream); // Create the transcoder output. ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); TranscoderOutput output = new TranscoderOutput(outputStream); // Save the image. t.transcode(input, output); // Flush and close the stream. outputStream.flush(); outputStream.close(); // Convert the byte stream into an image. byte[] imgData = outputStream.toByteArray(); return ImageIO.read(new ByteArrayInputStream(imgData)); >catch (IOException | TranscoderException e) < log.error("Conversion error", e); >return null; > > 

Solution 4

This is what I use. It’s an extension of BufferedImage with its own static factory that can be used wherever a BufferedImage is used. I wrote it so that any call to getScaledInstance(w, h, hint) will render from the SVG, not the rasterized image. A side-effect of this is that the scaling hint parameter has no meaning; you can just pass 0 or DEFAULT to that. It renders lazily — only when graphics data is requested — so the load / scale cycle shouldn’t give you too much overhead.

Edit: I added support using the above CSS config for scaling quality hints. Edit 2: Lazy rendering wasn’t working consistently; I put the render() call into the constructor.

It has the following dependencies:

  • org.apache.xmlgraphics:batik-anim
  • org.apache.xmlgraphics:batik-bridge
  • org.apache.xmlgraphics:batik-gvt
  • org.apache.xmlgraphics:batik-transcoder
  • org.apache.xmlgraphics:batik-util
  • xml-apis:xml-apis-ext
  • commons-logging:commons-logging

When I made this, I used batik 1.8; YMMV.

import java.awt.AlphaComposite; import java.awt.Composite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.HashMap; import java.util.Map; import org.apache.batik.anim.dom.SAXSVGDocumentFactory; import org.apache.batik.bridge.BridgeContext; import org.apache.batik.bridge.DocumentLoader; import org.apache.batik.bridge.GVTBuilder; import org.apache.batik.bridge.UserAgent; import org.apache.batik.bridge.UserAgentAdapter; import org.apache.batik.gvt.GraphicsNode; 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 org.apache.batik.util.SVGConstants; import org.apache.batik.util.XMLResourceDescriptor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.svg.SVGDocument; public class SVGImage extends BufferedImage < private static class BufferedImageTranscoder extends ImageTranscoder < private BufferedImage image = null; @Override public BufferedImage createImage(int arg0, int arg1) < return image; >private void setImage(BufferedImage image) < this.image = image; >@Override public void writeImage(BufferedImage arg0, TranscoderOutput arg1) throws TranscoderException < >> final static GVTBuilder builder = new GVTBuilder(); final static SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName()); final static UserAgent userAgent = new UserAgentAdapter(); final static DocumentLoader loader = new DocumentLoader(userAgent); final static BridgeContext bridgeContext = new BridgeContext(userAgent, loader); static < bridgeContext.setDynamicState(BridgeContext.STATIC); >final static private Log log = LogFactory.getLog(SVGImage.class); private static final Map scaleQuality = new HashMap(); static < String css = "svg "; String precise = "geometricPrecision"; String quality = "optimizeQuality"; String speed = "optimizeSpeed"; String crisp = "crispEdges"; String legible = "optimizeLegibility"; String auto = "auto"; scaleQuality.put(SCALE_DEFAULT, String.format(css, auto, auto, auto, auto)); scaleQuality.put(SCALE_SMOOTH, String.format(css, precise, precise, quality, quality)); scaleQuality.put(SCALE_REPLICATE, String.format(css, speed, speed, speed, speed)); scaleQuality.put(SCALE_AREA_AVERAGING, String.format(css, crisp, legible, auto, auto)); scaleQuality.put(SCALE_FAST, String.format(css, speed, speed, speed, speed)); > final static BufferedImageTranscoder transcoder = new BufferedImageTranscoder(); public static SVGImage fromSvg(URL resource) throws IOException < InputStream rs = null; try < rs = resource.openStream(); SVGDocument svg = factory.createSVGDocument(resource.toString(), rs); return fromSvgDocument(resource, svg); >finally < if (rs != null) < try < rs.close(); >catch (IOException ioe) <> > > > public static SVGImage fromSvgDocument(URL resource, SVGDocument doc) < GraphicsNode graphicsNode = builder.build(bridgeContext, doc); Double width = graphicsNode.getBounds().getWidth(); Double height = graphicsNode.getBounds().getHeight(); return new SVGImage(resource, doc, width.intValue(), height.intValue(), SCALE_DEFAULT); >boolean hasRendered = false; private int scalingHint = SCALE_DEFAULT; final SVGDocument svg; final URL svgUrl; private SVGImage(URL resource, SVGDocument doc, int width, int height, int hints) < super(width, height, TYPE_INT_ARGB); scalingHint = hints; svgUrl = resource; svg = doc; render(); >@Override public void coerceData(boolean isAlphaPremultiplied) < if (!hasRendered) < render(); >super.coerceData(isAlphaPremultiplied); > @Override public WritableRaster copyData(WritableRaster outRaster) < if (!hasRendered) < render(); >return super.copyData(outRaster); > private File createCSS(String css) < FileWriter cssWriter = null; File cssFile = null; try < cssFile = File.createTempFile("batik-default-override-", ".css"); cssFile.deleteOnExit(); cssWriter = new FileWriter(cssFile); cssWriter.write(css); >catch(IOException ioe) < log.warn("Couldn't write stylesheet; SVG rendered with Batik defaults"); >finally < if (cssWriter != null) < try < cssWriter.flush(); cssWriter.close(); >catch (IOException ioe) <> > > return cssFile; > @Override public WritableRaster getAlphaRaster() < if (!hasRendered) < render(); >return super.getAlphaRaster(); > @Override public Raster getData() < if (!hasRendered) < render(); >return super.getData(); > @Override public Graphics getGraphics() < if (!hasRendered) < render(); >return super.getGraphics(); > public Image getScaledInstance(int width, int height, int hints) < SVGImage newImage = new SVGImage(svgUrl, svg, width, height, hints); return newImage; >private void render() < TranscodingHints hints = new TranscodingHints(); hints.put(ImageTranscoder.KEY_WIDTH, new Float(getWidth())); hints.put(ImageTranscoder.KEY_HEIGHT, new Float(getHeight())); hints.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.FALSE); hints.put(ImageTranscoder.KEY_DOM_IMPLEMENTATION, svg.getImplementation()); hints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT_NAMESPACE_URI, SVGConstants.SVG_NAMESPACE_URI); hints.put(ImageTranscoder.KEY_DOCUMENT_ELEMENT, "svg"); String css = scaleQuality.get(scalingHint); File cssFile = null; if (css != null) < cssFile = createCSS(css); if (cssFile != null) < hints.put(ImageTranscoder.KEY_USER_STYLESHEET_URI, cssFile.toURI().toString()); >> transcoder.setTranscodingHints(hints); transcoder.setImage(this); // This may be a re-render, if the scaling quality hint has changed. // As such, we force the image into overwrite mode, and kick it back when we're done / fail Graphics2D gfx = (Graphics2D) super.getGraphics(); Composite savedComposite = gfx.getComposite(); gfx.setComposite(AlphaComposite.Clear); try < transcoder.transcode(new TranscoderInput(svg), null); hasRendered = true; >catch (TranscoderException te) < log.warn("Could not transcode " + svgUrl.getPath() + " to raster image; you're going to get a blank BufferedImage of the correct size."); >finally < gfx.setComposite(savedComposite); if (cssFile != null) < cssFile.delete(); >> > public void setScalingHint(int hint) < this.scalingHint = hint; // Forces a re-render this.hasRendered = false; >> 

Источник

Читайте также:  Add element to array kotlin

How to get a bufferedimage from a svg in Java?

In Java, the BufferedImage class represents an image that is stored in memory, which can be manipulated and displayed in a window. On the other hand, the Scalable Vector Graphics (SVG) format is a common format for storing vector graphics, which are images that are defined by mathematical equations rather than pixels. If you want to display an SVG image in a Java application, one way to do so is to convert the SVG into a BufferedImage , which can then be displayed using the Java Graphics framework.

Method 1: Using Apache Batik Library

To get a BufferedImage from an SVG using Apache Batik Library, you can follow these steps:

dependency> groupId>org.apache.xmlgraphicsgroupId> artifactId>batik-transcoderartifactId> version>1.14version> dependency>
File svgFile = new File("path/to/your/svg/file.svg"); TranscoderInput input = new TranscoderInput(svgFile.toURI().toString());
BufferedImageTranscoder transcoder = new BufferedImageTranscoder();
transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH, (float) width); transcoder.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, (float) height);
transcoder.transcode(input, null); BufferedImage image = transcoder.getBufferedImage();
import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.image.BufferedImageTranscoder; import org.w3c.dom.Document; public class SvgToBufferedImage  public static void main(String[] args) throws IOException, TranscoderException  File svgFile = new File("path/to/your/svg/file.svg"); TranscoderInput input = new TranscoderInput(svgFile.toURI().toString()); BufferedImageTranscoder transcoder = new BufferedImageTranscoder(); transcoder.addTranscodingHint(ImageTranscoder.KEY_WIDTH, (float) width); transcoder.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, (float) height); transcoder.transcode(input, null); BufferedImage image = transcoder.getBufferedImage(); // Save the image to a file File outputFile = new File("path/to/output/image.png"); ImageIO.write(image, "png", outputFile); > >

In this example, the BufferedImage is saved as a PNG file. You can change the output format by modifying the ImageIO.write() method.

Method 2: Using JavaFX and ImageIO

Here’s how you can get a BufferedImage from an SVG using JavaFX and ImageIO:

  1. First, you need to add the necessary dependencies to your project. For JavaFX, you can add the following to your build.gradle file:
dependencies  implementation 'org.openjfx:javafx-controls:16' >

For ImageIO, you can add the following:

dependencies  implementation 'javax.media:jai-core:1.1.3' implementation 'com.github.jai-imageio:jai-imageio-core:1.4.0' implementation 'com.github.jai-imageio:jai-imageio-jpeg2000:1.3.0' >
SVGPath svgPath = new SVGPath(); svgPath.setContent(Files.readString(Paths.get("path/to/file.svg")));
double width = svgPath.getBoundsInLocal().getWidth(); double height = svgPath.getBoundsInLocal().getHeight(); WritableImage writableImage = new WritableImage((int) width, (int) height); svgPath.snapshot(null, writableImage);
BufferedImage bufferedImage = new BufferedImage((int) width, (int) height, BufferedImage.TYPE_INT_ARGB); SwingFXUtils.fromFXImage(writableImage, bufferedImage);

And that’s it! Here’s the complete code:

import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.WritableImage; import javafx.scene.shape.SVGPath; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.nio.file.Files; import java.nio.file.Paths; public class SvgToBufferedImage  public static void main(String[] args) throws Exception  SVGPath svgPath = new SVGPath(); svgPath.setContent(Files.readString(Paths.get("path/to/file.svg"))); double width = svgPath.getBoundsInLocal().getWidth(); double height = svgPath.getBoundsInLocal().getHeight(); WritableImage writableImage = new WritableImage((int) width, (int) height); svgPath.snapshot(null, writableImage); BufferedImage bufferedImage = new BufferedImage((int) width, (int) height, BufferedImage.TYPE_INT_ARGB); SwingFXUtils.fromFXImage(writableImage, bufferedImage); ImageIO.write(bufferedImage, "png", Files.newOutputStream(Paths.get("path/to/output.png"))); > >

Method 3: Using Java2D and TranscoderInput/TranscoderOutput

To get a BufferedImage from a SVG using Java2D and TranscoderInput/TranscoderOutput, you can follow these steps:

SVGConverter converter = new SVGConverter(); TranscoderInput input = new TranscoderInput(new FileInputStream(svgFile)); converter.transcode(input, null);
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = image.createGraphics(); converter.transcode(input, new TranscoderOutput(g2d)); g2d.dispose();
  1. Optionally, you can set additional parameters for the Transcoder, such as the image size or background color:
converter.setDestinationType(DestinationType.PNG); converter.setSources(new String[]svgFile.getAbsolutePath()>); converter.setWidth(width); converter.setHeight(height); converter.setBackgroundColor(Color.WHITE);

Here’s the complete code example:

import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.FileInputStream; 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; import org.apache.batik.transcoder.image.PNGTranscoder; import org.apache.batik.transcoder.image.TIFFTranscoder; import org.apache.batik.transcoder.image.JPEGTranscoder; import org.apache.batik.transcoder.image.PNGTranscoder; import org.apache.batik.transcoder.image.PNGTranscoder; import org.apache.batik.transcoder.image.PNGTranscoder; public class SVGToBufferedImage  public static BufferedImage getBufferedImageFromSVG(String svgFilePath, int width, int height) throws IOException, TranscoderException  BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = image.createGraphics(); TranscoderInput input = new TranscoderInput(new FileInputStream(svgFilePath)); ImageTranscoder converter = new PNGTranscoder(); converter.transcode(input, new TranscoderOutput(g2d)); g2d.dispose(); return image; > >

Источник

Оцените статью