Java + Apache Batik で SVG を編集して PNG や JPEG に変換する

## 概要

- Java + Apache Batik で SVG を編集して PNG や JPEG に変換して出力する
- 環境: Apache Batik 1.13 + Java 15 (AdoptOpenJDK 15+36) + Gradle 6.6.1

## サンプルコード

### build.gradle

Gradle で実行するように記述する。使用するライブラリを記載する。

```groovy
plugins {
  id 'java'
  id 'application'
}

repositories {
  mavenCentral()
}

dependencies {
  // SVG を他のフォーマットに変換するための Apache Batik のコアモジュール
  implementation 'org.apache.xmlgraphics:batik-transcoder:1.13'

  // PNG や JPEG の出力に必要なモジュール
  runtimeOnly 'org.apache.xmlgraphics:batik-codec:1.13'
}

application {
  mainClassName = 'MyApp'
}
```

### MyApp.java

SVG ファイルを読み込んで編集して PNG, JPEG, SVG で出力する。

```java
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import org.w3c.dom.Element;

// Apache Batik
import org.apache.batik.anim.dom.SAXSVGDocumentFactory;
import org.apache.batik.anim.dom.SVGDOMImplementation;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.transcoder.svg2svg.SVGTranscoder;
import org.apache.batik.util.XMLResourceDescriptor;

// Apache XML Commons External Components XML APIs Extensions (xml-apis-ext)
import org.w3c.dom.svg.SVGDocument;

public class MyApp {

  public static void main(String[] args) throws IOException, TranscoderException {

    // 入力する SVG のファイルパスから URI を構築
    URI inputUri = new File("input.svg").toURI();

    // SVGDocument は org.w3c.dom.Document を extends している interface
    SVGDocument doc = new SAXSVGDocumentFactory(
      XMLResourceDescriptor.getXMLParserClassName())
      .createSVGDocument(inputUri.toString());

    // SVG を編集することも可能
    // ここでは path 要素を追加してみる
    Element path = doc.createElementNS(SVGDOMImplementation.SVG_NAMESPACE_URI, "path");
    path.setAttribute("id", "foo");
    path.setAttribute("d", "M 1000,2000 h 1000 v 1000 h -1000 z"); // 正方形を描く
    path.setAttribute("style", "fill: #ff0000; stroke: #0000ff; stroke-width: 100");
    doc.getFirstChild().appendChild(path);

    // 変換用の入力オブジェクトを生成
    TranscoderInput input = new TranscoderInput(doc);

    // 各種フォーマットで出力する
    outputPng(input, new File("output.png"));
    outputJpg(input, new File("output.jpg"));
    outputSvg(input, new File("output.svg"));
  }

  // PNG で出力する
  private static void outputPng(TranscoderInput input, File outFile) throws IOException, TranscoderException {
    PNGTranscoder t = new PNGTranscoder();
    try (OutputStream os = new FileOutputStream(outFile)) {
      TranscoderOutput output = new TranscoderOutput(os);
      t.transcode(input, output);
    }
  }

  // JPEG で出力する
  private static void outputJpg(TranscoderInput input, File outFile) throws IOException, TranscoderException {
    JPEGTranscoder t = new JPEGTranscoder();
    t.addTranscodingHint(JPEGTranscoder.KEY_QUALITY, .8f);
    try (OutputStream os = new FileOutputStream(outFile)) {
      TranscoderOutput output = new TranscoderOutput(os);
      t.transcode(input, output);
    }
  }

  // SVG で出力する
  private static void outputSvg(TranscoderInput input, File outFile) throws IOException, TranscoderException {
    SVGTranscoder t = new SVGTranscoder();
    try (OutputStream os = new FileOutputStream(outFile)) {
      OutputStreamWriter writer = new OutputStreamWriter(os, StandardCharsets.UTF_8);
      TranscoderOutput output = new TranscoderOutput(writer);
      t.transcode(input, output);
    }
  }
}
```

## 実行方法

同じディレクトリに任意の入力ファイル input.svg を置いて gradle run で実行。

```
$ gradle run
```

## 参考資料

### Apache Batik

- [Apache\(tm\) Batik SVG Toolkit \- a Java\-based toolkit for applications or applets that want to use images in the Scalable Vector Graphics \(SVG\)](https://xmlgraphics.apache.org/batik/)
  - [Architecture overview](https://xmlgraphics.apache.org/batik/using/architecture.html)
  - [Transcoder API](https://xmlgraphics.apache.org/batik/using/transcoder.html)
  - [SVG DOM API](https://xmlgraphics.apache.org/batik/using/dom-api.html)
- [Apache Batik API Specification 1.9 \(Apache Batik Javadoc\)](https://xmlgraphics.apache.org/batik/javadoc/)
- [Maven Repository: org\.apache\.xmlgraphics » batik\-transcoder » 1\.13](https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-transcoder/1.13)
- [Maven Repository: org\.apache\.xmlgraphics » batik\-codec » 1\.13](https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-codec/1.13)

### Apache XML Commons External Components XML APIs Extensions

- [Maven Repository: xml\-apis » xml\-apis\-ext » 1\.3\.04](https://mvnrepository.com/artifact/xml-apis/xml-apis-ext/1.3.04)
- [\[Apache\-SVN\] Index of /xerces/xml\-commons/tags/xml\-commons\-external\-1\_3\_04/java/external](http://svn.apache.org/viewvc/xerces/xml-commons/tags/xml-commons-external-1_3_04/java/external/)
- [\[Apache\-SVN\] Contents of /xerces/xml\-commons/tags/xml\-commons\-external\-1\_3\_04/java/external/src/org/w3c/dom/svg/SVGDocument\.java](http://svn.apache.org/viewvc/xerces/xml-commons/tags/xml-commons-external-1_3_04/java/external/src/org/w3c/dom/svg/SVGDocument.java?revision=478305&view=markup)