2014-09-24 2 views
10

배경

독서에 관한 대답없는 질문의 수와 분석 SVG 경로가 있습니다로드 및 구문 분석하는 방법 SVG 문서

이 질문과 대답은이 모든 질문을 해결하는 것을 목표로합니다.

문제

path 소자는 data attribute (d) 포함하는 SVG. 때로는 SVG 파일에서 경로 정보 만로드하고 구문 분석하고 추출해야하는 경우가 있습니다.

질문

어떻게 구문 분석,로드 및 Java를 사용하여 SVG 파일에서 SVG 경로 정보를 추출 할 수 있습니까? Apache Batik를 사용

답변

11

개요

로드 및 구문 분석 SVG 파일. 이 솔루션은 SVG 파일을 MetaPost로 변환하는 예비 단계에서 Java 코드를 보여줍니다. 이것은 Java를 사용하여 SVG 파일에서 내용을로드, 구문 분석 및 추출하는 방법에 대한 일반적인 아이디어를 제공해야합니다.

라이브러리

다음과 같은 라이브러리가 필요합니다

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 파일

주요 응용 프로그램이 DOM에 SVG 파일을로드는 다음 SVG의 DOM에 DOM을 변환합니다. initSVGDOM() 메서드 호출은 매우 중요합니다. initSVGDOM()을 호출하지 않으면 DOM에서 SVG DOM 요소를 추출하는 메소드를 사용할 수 없습니다.

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()를 호출하면 바틱의 기본 동작해야한다. 아아, 아니야,이 보석을 발견한다는 것은 자신의 웹 사이트에서 documentation buried을 읽는 것을 의미합니다. SVG DOM 파싱 파싱 SVG DOM

는 비교적 간단하다.

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

빌드 환경에 환경에 따라 다를 것입니다

컴파일 다음 toCode() 방법은 클래스의 주력이다. 다음과 유사한 스크립트는 데 도움이 될 것입니다

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

./lib 디렉토리에 모든 .jar 파일을 배치해야합니다.소스 파일을 ./source 디렉토리에 넣으십시오.

실행

프로그램을 실행하는 스크립트 (또는 배치 파일) 만들기 : 유효한 SVG 경로를 포함하는 파일에 대해 실행하면

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

출력을

,이 생산

:

$ ./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 

여기에서 SVG 경로 데이터를 해당 corr로 읽는 방법이 명확해야합니다. 자바를 사용하는 SVG 객체. 가장 간단한 방법은 MetaPost에 SVG로 변환하는 것을

부록

주입니다

  1. 변환 PDF로 SVG (예를 들어, Inkscape 또는 rsvg-convert 사용).
  2. pstoedit을 사용하여 PDF를 MetaPost로 변환하십시오.