如何加载和解析SVG文档 [英] How to load and parse SVG documents

查看:166
本文介绍了如何加载和解析SVG文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有很多未解决的问题与阅读和解析SVG路径有关:

There are number of unanswered questions related to reading and parsing SVG paths:

  • Easiest way to read in svg path data with Java?
  • Re: parsing a svg file using batik svg parser
  • https://stackoverflow.com/questions/16672100
  • How to convert SVG Path (SVGOMPathElement) to array of points?

此问题的答案旨在解决所有这些问题。

This question and answer aims to resolve all these questions.

SVG 路径元素包含数据属性 d )。有时需要从SVG文件中加载,解析和提取路径信息。

The SVG path element contains a data attribute (d). Sometimes it is necessary to load, parse, and extract just the path information from an SVG file.

如何使用Java从SVG文件加载,解析和提取SVG路径信息?

How do you load, parse, and extract SVG path information from an SVG file using Java?

推荐答案

概述



使用 Apache Batik 加载和解析SVG文件。该解决方案显示了将SVG文件转换为MetaPost的初步阶段的Java代码。这应该提供如何使用Java从SVG文件加载,解析和提取内容的一般概念。

Overview

Load and parse SVG files using Apache Batik. The solution shows Java code in the preliminary stages of converting an SVG file to MetaPost. This should provide a general idea for how to load, parse, and extract content from SVG files using Java.

您将需要以下库:

batik-anim.jar
batik-awt-util.jar
batik-bridge.jar
batik-css.jar
batik-dom.jar
batik-ext.jar
batik-gvt.jar
batik-parser.jar
batik-script.jar
batik-svg-dom.jar
batik-svggen.jar
batik-util.jar
batik-xml.jar
xml-apis-ext.jar



加载SVG文件



主应用程序将SVG文件加载到DOM中,然后将DOM转换为SVG DOM。 initSVGDOM()方法调用非常重要。如果不调用 initSVGDOM(),则从DOM中提取SVG DOM元素的方法将无法使用。

Load SVG File

The main application loads the SVG file into DOM, then converts the DOM to an SVG DOM. The initSVGDOM() method call is extremely important. Without calling initSVGDOM(), the methods for extracting SVG DOM elements from the DOM would not be available.

import java.io.File;
import java.io.IOException;

import java.net.URI;

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.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.dom.svg.SVGOMSVGElement;
import org.apache.batik.util.XMLResourceDescriptor;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;


/**
 * Responsible for converting all SVG path elements into MetaPost curves.
 */
public class SVGMetaPost {
  private static final String PATH_ELEMENT_NAME = "path";

  private Document svgDocument;

  /**
   * Creates an SVG Document given a URI.
   *
   * @param uri Path to the file.
   * @throws Exception Something went wrong parsing the SVG file.
   */
  public SVGMetaPost( String uri ) throws IOException {
    setSVGDocument( createSVGDocument( uri ) );
  }

  /**
   * Finds all the path nodes and converts them to MetaPost code.
   */
  public void run() {
    NodeList pathNodes = getPathElements();
    int pathNodeCount = pathNodes.getLength();

    for( int iPathNode = 0; iPathNode < pathNodeCount; iPathNode++ ) {
      MetaPostPath mpp = new MetaPostPath( pathNodes.item( iPathNode ) );
      System.out.println( mpp.toCode() );
    }
  }

  /**
   * Returns a list of elements in the SVG document with names that
   * match PATH_ELEMENT_NAME.
   * 
   * @return The list of "path" elements in the SVG document.
   */
  private NodeList getPathElements() {
    return getSVGDocumentRoot().getElementsByTagName( PATH_ELEMENT_NAME );
  }

  /**
   * Returns an SVGOMSVGElement that is the document's root element.
   * 
   * @return The SVG document typecast into an SVGOMSVGElement.
   */
  private SVGOMSVGElement getSVGDocumentRoot() {
    return (SVGOMSVGElement)getSVGDocument().getDocumentElement();
  }

  /**
   * This will set the document to parse. This method also initializes
   * the SVG DOM enhancements, which are necessary to perform SVG and CSS
   * manipulations. The initialization is also required to extract information
   * from the SVG path elements.
   *
   * @param document The document that contains SVG content.
   */
  public void setSVGDocument( Document document ) {
    initSVGDOM( document );
    this.svgDocument = document;
  }

  /**
   * Returns the SVG document parsed upon instantiating this class.
   * 
   * @return A valid, parsed, non-null SVG document instance.
   */
  public Document getSVGDocument() {
    return this.svgDocument;
  }

  /**
   * Enhance the SVG DOM for the given document to provide CSS- and SVG-specific
   * DOM interfaces.
   * 
   * @param document The document to enhance.
   * @link http://wiki.apache.org/xmlgraphics-batik/BootSvgAndCssDom
   */
  private void initSVGDOM( Document document ) {
    UserAgent userAgent = new UserAgentAdapter();
    DocumentLoader loader = new DocumentLoader( userAgent );
    BridgeContext bridgeContext = new BridgeContext( userAgent, loader );
    bridgeContext.setDynamicState( BridgeContext.DYNAMIC );

    // Enable CSS- and SVG-specific enhancements.
    (new GVTBuilder()).build( bridgeContext, document );
  }

  /**
   * Use the SAXSVGDocumentFactory to parse the given URI into a DOM.
   * 
   * @param uri The path to the SVG file to read.
   * @return A Document instance that represents the SVG file.
   * @throws Exception The file could not be read.
   */
  private Document createSVGDocument( String uri ) throws IOException {
    String parser = XMLResourceDescriptor.getXMLParserClassName();
    SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory( parser );
    return factory.createDocument( uri );
  }

  /**
   * Reads a file and parses the path elements.
   * 
   * @param args args[0] - Filename to parse.
   * @throws IOException Error reading the SVG file.
   */
  public static void main( String args[] ) throws IOException {
    URI uri = new File( args[0] ).toURI();
    SVGMetaPost converter = new SVGMetaPost( uri.toString() );
    converter.run();
  }
}

注意:调用 initSVGDOM(除非另有说明,否则应该是Batik的默认行为。唉,它不是,发现这个宝石意味着在他们的网站上阅读埋藏的文件

Note: Calling initSVGDOM() should be Batik's default behaviour unless otherwise specified. Alas, it isn't, and discovering this gem means reading documentation buried on their website.

解析SVG DOM相对来说是微不足道的。 toCode()方法是该类的主力:

Parsing the SVG DOM is then relatively trivial. The toCode() method is the workhorse of the class:

import org.apache.batik.dom.svg.SVGItem;
import org.apache.batik.dom.svg.SVGOMPathElement;

import org.w3c.dom.Node;
import org.w3c.dom.svg.SVGPathSegList;

/**
 * Responsible for converting an SVG path element to MetaPost. This
 * will convert just the bezier curve portion of the path element, not
 * its style. Typically the SVG path data is provided from the "d" attribute
 * of an SVG path node.
 */
public class MetaPostPath extends MetaPost {
  private SVGOMPathElement pathElement;

  /**
   * Use to create an instance of a class that can parse an SVG path
   * element to produce MetaPost code.
   *
   * @param pathNode The path node containing a "d" attribute (output as MetaPost code).
   */
  public MetaPostPath( Node pathNode ) {
    setPathNode( pathNode );
  }

  /**
   * Converts this object's SVG path to a MetaPost draw statement.
   * 
   * @return A string that represents the MetaPost code for a path element.
   */
  public String toCode() {
    StringBuilder sb = new StringBuilder( 16384 );
    SVGOMPathElement pathElement = getPathElement();
    SVGPathSegList pathList = pathElement.getNormalizedPathSegList();

    int pathObjects = pathList.getNumberOfItems();

    sb.append( ( new MetaPostComment( getId() ) ).toString() );

    for( int i = 0; i < pathObjects; i++ ) {
      SVGItem item = (SVGItem)pathList.getItem( i );
      sb.append( String.format( "%s%n", item.getValueAsString() ) );
    }

    return sb.toString();
  }

  /**
   * Returns the value for the id attribute of the path element. If the
   * id isn't present, this will probably throw a NullPointerException.
   * 
   * @return A non-null, but possibly empty String.
   */
  private String getId() {
    return getPathElement().getAttributes().getNamedItem( "id" ).getNodeValue();
  }

  /**
   * Typecasts the given pathNode to an SVGOMPathElement for later analysis.
   * 
   * @param pathNode The path element that contains curves, lines, and other
   * SVG instructions.
   */
  private void setPathNode( Node pathNode ) {
    this.pathElement = (SVGOMPathElement)pathNode;
  }

  /**
   * Returns an SVG document element that contains path instructions (usually
   * for drawing on a canvas).
   * 
   * @return An object that contains a list of items representing pen
   * movements.
   */
  private SVGOMPathElement getPathElement() {
    return this.pathElement;
  }
}



Build



编译因环境而异。类似于以下内容的脚本应该有所帮助:

Build

Compiling will vary from environment to environment. A script similar to the following should help:

#!/bin/bash
mkdir -p ./build
javac -cp ./lib/* -d ./build ./source/*.java

确保将所有 .jar 文件放入 ./ lib 目录中。将源文件放入 ./ source 目录。

Be sure to put all the .jar files into the ./lib directory. Put the source files into the ./source directory.

创建一个脚本(或批处理文件)来执行程序:

Create a script (or batch file) to execute the program:

#!/bin/bash
java -cp ./lib/*:./build SVGMetaPost $1



输出



当对包含有效SVG路径的文件运行时,会产生:

Output

When run against a file containing a valid SVG path, this produces:

$ ./run.sh stripe/trigon.svg 
% path8078-6
M 864.1712 779.3069
C 864.1712 779.3069 868.04065 815.6211 871.4032 833.4621
C 873.4048 844.08203 874.91724 855.0544 879.0846 864.82227
C 884.24023 876.9065 895.2377 887.9899 900.0184 897.3661
C 904.7991 906.7422 907.3466 918.3257 907.3466 918.3257
C 907.3466 918.3257 892.80817 887.6536 864.1712 887.3086
C 835.53424 886.9637 820.9958 918.3257 820.9958 918.3257
C 820.9958 918.3257 823.6176 906.59644 828.32404 897.3661
C 833.0304 888.1356 844.10223 876.9065 849.2578 864.82227
C 853.4252 855.05444 854.9376 844.08203 856.93915 833.4621
C 860.3017 815.6211 864.17114 779.3069 864.17114 779.3069
z

从此处应该清楚如何使用Java将SVG路径数据读入相应的SVG对象。

From here it should be clear how to read SVG path data into their corresponding SVG objects using Java.

注意从SVG转换为 MetaPost 的最简单方法是:

Note that the simplest way to convert from SVG to MetaPost is:


  1. 将SVG转换为PDF(例如,使用 Inkscape rsvg-convert )。

  2. 转换PDF使用 pstoedit 到MetaPost。

  1. Convert SVG to PDF (e.g., using Inkscape or rsvg-convert).
  2. Convert PDF to MetaPost using pstoedit.

这篇关于如何加载和解析SVG文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆