由SVG直接绘制成BufferedImage

最近在写一个程序小工具AppIconTools,使用网阿里图标库和一个SVG字体图标来生成APP图标。需要将SVG文件直接生成BufferedImage。

经过搜索比较,最终选择使用org.apache.batik来生成BufferedImage。但batik只提供了将SVG转化为PNG的例子,没有直接生成BufferedImage的例子。后经不断搜索查找,终于在另外一个项目中找到了能够完成我的需求的一个类。

核心代码如下

 public BufferedImage renderToImage(SVGDocument document, int width, int height, boolean stretch){ 
   
  ImageRendererFactory rendererFactory; 
  rendererFactory = new ConcreteImageRendererFactory(); 
  ImageRenderer renderer = rendererFactory.createStaticImageRenderer(); 
 
  GVTBuilder builder = new GVTBuilder(); 
  BridgeContext ctx = new BridgeContext(new UserAgentAdapter()); 
  ctx.setDynamicState(BridgeContext.STATIC); 
  GraphicsNode rootNode = builder.build(ctx, document); 
 
  renderer.setTree(rootNode); 
   
  float docWidth  = (float) ctx.getDocumentSize().getWidth(); 
  float docHeight = (float) ctx.getDocumentSize().getHeight(); 
   
  float xscale = width/docWidth; 
  float yscale = height/docHeight; 
  if(!stretch){ 
   float scale = Math.min(xscale, yscale); 
   xscale = scale; 
   yscale = scale; 
  } 
   
  AffineTransform px  = AffineTransform.getScaleInstance(xscale, yscale); 
   
  double tx = -0 + (width/xscale - docWidth)/2; 
  double ty = -0 + (height/yscale - docHeight)/2; 
  px.translate(tx, ty); 
  //cgn.setViewingTransform(px); 
   
  renderer.updateOffScreen(width, height); 
  renderer.setTree(rootNode); 
  renderer.setTransform(px); 
  //renderer.clearOffScreen(); 
  renderer.repaint(new Rectangle(0, 0, width, height)); 
 
  return renderer.getOffScreen(); 
 
 } 

上面的代码使用 org.apache.batik.gvt.renderer来将SVG的路径直接绘制到图形中,最后返回BufferedImage


完整的类代码也贴出来


package appicontools;

import java.awt.Color; 
import java.awt.Rectangle; 
import java.awt.geom.AffineTransform; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.io.StringReader; 
 
import org.apache.batik.bridge.BridgeContext; 
import org.apache.batik.bridge.GVTBuilder; 
import org.apache.batik.bridge.UserAgentAdapter; 
import org.apache.batik.anim.dom.SAXSVGDocumentFactory; 
import org.apache.batik.gvt.GraphicsNode; 
import org.apache.batik.gvt.renderer.ConcreteImageRendererFactory; 
import org.apache.batik.gvt.renderer.ImageRenderer; 
import org.apache.batik.gvt.renderer.ImageRendererFactory; 
import org.w3c.dom.NodeList; 
import org.w3c.dom.svg.SVGDocument; 
import org.w3c.dom.svg.SVGElement; 
 
public class OffScreenSVGRenderer { 
   
 private static final boolean DEBUG = false; 
  
 public BufferedImage renderXMLToImage(String xmlContent, int width, int height) throws IOException { 
  return renderXMLToImage(xmlContent, width, height, false, null, null); 
 } 
  
 public BufferedImage renderXMLToImage(String xmlContent, int width, int height, boolean stretch, String idRegex, Color replacementColor) throws IOException { 
  // the following is necessary so that batik knows how to resolve URI fragments 
  // (#myLinearGradient). Otherwise the resolution fails and you cannot render. 
   
  String uri = "file:/fake.svg"; 
   
  SAXSVGDocumentFactory df = new SAXSVGDocumentFactory("org.apache.xerces.parsers.SAXParser"); 
  SVGDocument document = df.createSVGDocument(uri, new StringReader(xmlContent)); 
  if(idRegex != null && replacementColor != null) 
   replaceFill(document, idRegex, replacementColor); 
  return renderToImage(document, width, height, stretch);   
 } 
  
 public BufferedImage renderToImage(String uri, int width, int height) throws IOException { 
  return renderToImage(uri, width, height, false, null, null); 
 } 
  
 public BufferedImage renderToImage(String uri, int width, int height, boolean stretch, String idRegex, Color replacementColor) throws IOException { 
  SAXSVGDocumentFactory df = new SAXSVGDocumentFactory("org.apache.xerces.parsers.SAXParser"); 
  SVGDocument document = df.createSVGDocument(uri); 
  if(idRegex != null && replacementColor != null) 
   replaceFill(document, idRegex, replacementColor); 
  return renderToImage(document, width, height, stretch); 
 } 
  
 public BufferedImage renderToImage(SVGDocument document, int width, int height){ 
  return renderToImage(document, width, height, false); 
 } 
  
 public void replaceFill(SVGDocument document, String idRegex, Color color){ 
  String colorCode = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());  
   
  if(DEBUG) System.out.println("color code: "+colorCode); 
   
  NodeList children = document.getElementsByTagName("*"); 
  for(int i = 0; i < children.getLength(); i++){ 
   if(children.item(i) instanceof SVGElement){ 
    SVGElement element = (SVGElement) children.item(i); 
    if(element.getId().matches(idRegex)){ 
     if(DEBUG) System.out.println("child>>> "+element+", "+element.getId()); 
     String style = element.getAttributeNS(null, "style"); 
     style = style.replaceFirst("fill:#[a-zA-z0-9]+", "fill:"+colorCode); 
     if(DEBUG) System.out.println(style); 
     element.setAttributeNS(null, "style", style); 
    } 
   } 
  } 
 } 
  
 public BufferedImage renderToImage(SVGDocument document, int width, int height, boolean stretch){ 
   
  ImageRendererFactory rendererFactory; 
  rendererFactory = new ConcreteImageRendererFactory(); 
  ImageRenderer renderer = rendererFactory.createStaticImageRenderer(); 
 
  GVTBuilder builder = new GVTBuilder(); 
  BridgeContext ctx = new BridgeContext(new UserAgentAdapter()); 
  ctx.setDynamicState(BridgeContext.STATIC); 
  GraphicsNode rootNode = builder.build(ctx, document); 
 
  renderer.setTree(rootNode); 
   
  float docWidth  = (float) ctx.getDocumentSize().getWidth(); 
  float docHeight = (float) ctx.getDocumentSize().getHeight(); 
   
  float xscale = width/docWidth; 
  float yscale = height/docHeight; 
  if(!stretch){ 
   float scale = Math.min(xscale, yscale); 
   xscale = scale; 
   yscale = scale; 
  } 
   
  AffineTransform px  = AffineTransform.getScaleInstance(xscale, yscale); 
   
  double tx = -0 + (width/xscale - docWidth)/2; 
  double ty = -0 + (height/yscale - docHeight)/2; 
  px.translate(tx, ty); 
  //cgn.setViewingTransform(px); 
   
  renderer.updateOffScreen(width, height); 
  renderer.setTree(rootNode); 
  renderer.setTransform(px); 
  //renderer.clearOffScreen(); 
  renderer.repaint(new Rectangle(0, 0, width, height)); 
 
  return renderer.getOffScreen(); 
 
 } 
}

AppIconTools源码已开源,可从https://code.csdn.net/do168/appicontools/tree/master 下载


你可能感兴趣的:(JAVA)