我听说过蜡染,我知道它很受欢迎,但我从未使用过它。过去,我不得不在我的程序中以编程方式生成/更改 SVG 几次,无论是在 Java、Javascript 还是 C++ 中。我总是用手做,这意味着:
- 使用 Java 的标准 org.w3c.dom 或其他一些 DOM 库;
- 使用 Java 的标准 org.xml.sax 或其他一些 SAX 库。
SVG 是一个 XML 应用程序,因此使用上面列出的两个通用 XML API 非常容易操作。您基本上加载 SVG 文件并通过调用 API 的适当方法开始添加/删除/更改元素。
这是一个使用 SAX for Java 的小例子。我意识到我有点生疏了;该代码似乎可以工作,但欢迎 SAX/XML/Java 大师进行清理。它对使用 Inkscape(矢量编辑程序)生成的 SVG 文件进行操作,但这里讨论的概念适用于任何 SVG(甚至一般的 XML)文档。基本上,它通过改变 XML 元素流来工作;它在图形中的每个对象附近插入一个渐进式标签。
SAX 是基于事件的;在 XML 解析期间引发事件。该代码处理 3 个不同的事件:
- startDocument在 XML 文档的开头引发;我们使用这个事件来重置累进计数器。
- startElement在 XML 元素的开头引发;如果元素是路径(在 SVG 中描述形状的常用元素),我们会记下它的位置(cx,cy;限定词sodipodi是 Inkscape 的旧名称)。
endElement在 XML 元素的末尾引发;如果元素是路径,我们会引发导致标签生成的事件。我们使用 SVG 元素文本将标签添加到文档中。
import java.io.File;
import java.io.FileInputStream;
import javax.xml.transform.Result;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.helpers.XMLReaderFactory;
public class SVGMod {
public static void main(String argv[]) {
try {
SAXTransformerFactory factory = (SAXTransformerFactory)SAXTransformerFactory.newInstance();
TransformerHandler serializer = factory.newTransformerHandler();
Result result = new StreamResult(new File("Output.svg"));
serializer.setResult(result);
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://xml.org/sax/features/namespaces", true);
reader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
XMLFilter filter = new XMLFilterImpl() {
private int x;
private int y;
private int cnt;
@Override
public void startDocument() throws SAXException {
super.startDocument();
cnt = 0;
}
@Override
public void startElement(String uri, String localName,
String qName, Attributes atts) throws SAXException {
super.startElement(uri, localName, qName, atts);
if (qName.equals("path")) {
int xIndex = atts.getIndex("sodipodi:cx");
int yIndex = atts.getIndex("sodipodi:cy");
if (xIndex != -1 && yIndex != -1) {
x = (int)Float.parseFloat(atts.getValue(xIndex));
y = (int)Float.parseFloat(atts.getValue(yIndex));
++cnt;
}
}
}
@Override
public void endElement(String uri, String localName,
String qName) throws SAXException {
super.endElement(uri, localName, qName);
if (qName.equals("path")) {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute(uri, "", "x", "CDATA", new Integer(x).toString());
atts.addAttribute(uri, "", "y", "CDATA", new Integer(y).toString());
atts.addAttribute(uri, "", "fill", "CDATA", "red");
super.startElement(uri, "", "text", atts);
char[] chars = ("Object #: " + cnt).toCharArray();
super.characters(chars, 0, chars.length);
super.endElement(uri, "", "text");
}
}
};
filter.setContentHandler(serializer);
filter.setParent(reader);
filter.parse(new InputSource(new FileInputStream("Input.svg")));
} catch (Exception e) {
e.printStackTrace();
}
}
}