パッケージ製品開発担当の大です。こんにちは。

次期版のJava SEはJava 9になりますね。スケジュールはいつも通りちょっとづつ遅れ、いまのところ2017年7月のリリース予定な感じです。Java 9といえばProject Jigsawによるモジュールシステムや、jshellの搭載などがよく話題になってますが、実装される予定の機能を眺めていたら、どうやらTIFF入出力が正式に入ることになりそうなのに気がつきました。

これは弊社製品でTIFFを出力する際にも使えるかも?ということで、今回はこれを調査してみます。

test

Java 8まで

これまでJavaでTIFFを出力するには、JAI(Java Advanced Imaging API)を使用するか、JAI Image I/O Toolsを使用するしか、手段はありませんでした。しかし、JAIもJAI Image I/O Toolsも何年もメンテナンスされていない状態が続いていました。SunからOracleに管理が変わった頃、一時はダウンロードすらできない状態になっていましたが、現在はダウンロードは再開されています。

Java 9で入るTIFF対応は、JAI Image I/O Toolsに入っていたTIFF出力機能の移植ということのようですね。

Image I/Oが対応している画像のフォーマットは、以下のようにして取得できます。現行のJava 8だとこんな感じです。

C:\>"c:\Program Files\Java\jdk1.8.0_112\bin\jrunscript.exe"
nashorn> java.util.Arrays.toString(javax.imageio.ImageIO.getReaderFormatNames())
[JPG, jpg, bmp, BMP, gif, GIF, WBMP, png, PNG, jpeg, wbmp, JPEG]
nashorn> java.util.Arrays.toString(javax.imageio.ImageIO.getWriterFormatNames())
[JPG, jpg, bmp, BMP, gif, GIF, WBMP, png, PNG, wbmp, jpeg, JPEG]

Java 8だとTIFFは入っていません。ちなみにImageI/O Tools を追加するとこんな感じになります。

c:\>"c:\Program Files\Java\jdk1.8.0_112\bin\jrunscript.exe" -classpath "path/to/jai_imageio.jar"
nashorn> java.util.Arrays.toString(javax.imageio.ImageIO.getReaderFormatNames())
[JPG, jpg, JPEG 2000, JPEG2000, tiff, bmp, BMP, gif, GIF, WBMP, png, PNG, raw, RAW, JPEG, pnm, PNM, tif, TIF, TIFF, jpeg2000, wbmp, jpeg, jpeg 2000]
nashorn> java.util.Arrays.toString(javax.imageio.ImageIO.getWriterFormatNames())
[JPG, jpg, JPEG 2000, JPEG2000, tiff, bmp, BMP, gif, GIF, WBMP, png, PNG, raw, RAW, JPEG, pnm, PNM, tif, TIF, TIFF, jpeg2000, wbmp, jpeg, jpeg 2000]

外部ライブラリ追加でJPEG 2000やTIFFなどに対応できることがわかりますね。

Java 9

Java 9はEarly Access版が以下からダウンロード・インストールできます。お手軽ですね。

今回試したのは JDK 9 Build 140、Windows 64ビット版でした。

Java 9は、せっかくなのでjshellで確認してみます。

C:\>"c:\Program Files\Java\jdk-9\bin\jshell.exe"
|  JShellへようこそ -- バージョン9-ea
|  概要については、次を入力してください: /help intro


jshell> javax.imageio.ImageIO.getReaderFormatNames()
$1 ==> String[16] { "JPG", "jpg", "tiff", "bmp", "BMP", "gif", "GIF", "WBMP", "png", "PNG", "JPEG", "tif", "TIF", "TIFF", "jpeg", "wbmp" }

jshell> javax.imageio.ImageIO.getWriterFormatNames()
$2 ==> String[16] { "JPG", "jpg", "tiff", "bmp", "BMP", "gif", "GIF", "WBMP", "png", "PNG", "JPEG", "tif", "TIF", "TIFF", "jpeg", "wbmp" }

おお、たしかにTIFFが追加されていますね!

余談ですが、jrunscriptだと配列の表示はArrays.toString()してやらないといけませんがjshellだと勝手に整形して表示してくれますね。タブでの入力補完もしてくれるし、いい感じ。

では、TIFFの入出力を試してみます。その前に、わずらわしくなるのでimport追加。

jshell> import java.awt.image.*

jshell> import javax.imageio.*

設定されているimportは、/importsで確認できます。

jshell> /imports
|    import java.util.*
|    import java.io.*
|    import java.math.*
|    import java.net.*
|    import java.util.concurrent.*
|    import java.util.prefs.*
|    import java.util.regex.*
|    import java.awt.image.*
|    import javax.imageio.*

では、既存のPNGファイルをTIFFに変換してみます。

PNG→TIFF変換(変換前PNG)

PNG→TIFF変換(変換前PNG)

jshell> BufferedImage png = ImageIO.read(new File("tmp/test.png"))
png ==> BufferedImage@2f112965: type = 6 ColorModel: #pixelBits = 32 numComponents = ...

jshell> ImageIO.write(png, "tif", new File("tmp/new.tif"))
$4 ==> true

問題なく変換されました!

では逆に、既存のTIFFファイルを読み込んでPNGに変換してみます。

jshell> BufferedImage tif = ImageIO.read(new File("tmp/test.tif"))
tif ==> BufferedImage@70be0a2b: type = 0 ColorModel: #pixelBits = 24 numComponents = ...

jshell> ImageIO.write(tif, "png", new File("tmp/new.png"))
$6 ==> true

こちらも問題ないようですね!ちなみのこのTIFFファイルはシーオーリポーツ for Javaで作成したものです。

TIFF→PNG変換(変換後PNG)

TIFF→PNG変換(変換後PNG)

というわけで、読み書きどちらもできることは確認できました。

今後、シーオーリポーツ for Java・帳票クリエータ for Javaでは、Java 9のこの機能を使うことで、外部ライブラリなしでTIFFが扱えるようになるかもしれません(まだ未定ですが……)。ただ、ざっと見た感じImage I/O Toolsのときにはあったクラスがなくなってたりするみたい(TIFFImageWriteParamなど)なので、完全に同じように使えるわけではなさそうです。また、もともとImage I/O ToolsでTIFF出力を行った場合、JAIで行った場合に比べて若干サイズが大きくなるとか、失敗時にテンポラリファイルが削除されない場合があるなどの問題もあり、それらが解消されているかも検証する必要がありそうです。