2012/05/20

Apache Commons Imaging (a.k.a. Sanselan)によるExifヘッダを編集する Androidアプリの作成

Apache CommonsのCommons Sanselanは 画像処理を行なうためのPure-Java実装ですが、2009年以降は安定版がリリースされていません。

しかしSVNのリポジトリをみると、Sanselan(org.apache.commons.sanselan)からImaging(org.apache.commons.imaging)へと名前とパッケージ名をかえて、開発が進んでいるようです。

AndroidではSanselanでも問題ないようですが、別件でTiffファイルのヘッダがうまくパースできなかったので、Commons Imagingを使う事にしました。Sanselanを使ったアプリケーションはいくつかありますが、Commons Imagingを使ったサンプルはあまりないようです。

今回はSanselanとImagingを比較しながら、使い方のメモを残していきます。

SanselanによるExif日付情報の書き換え

Sanselan自体にはExifの日時情報を書き換えるような適当なサンプルがないので、Googleで探すとGPSdingsのSanselanExifWriter.java、openstreetmapのExifGPSTagger.javaなどのコードをみる事ができます。

ちなみに、これらのコードはGPLv2, GPLv3で配布されています。

ExifGPSTagger.java でのSanselanを使ったコード例 (一部変更)

  Double[] timeStamp = {
    new Double(calendar.get(Calendar.HOUR_OF_DAY)),
    new Double(calendar.get(Calendar.MINUTE)), 
    new Double(calendar.get(Calendar.SECOND))
  };
  TiffOutputField gpsTimeStamp = TiffOutputField.create(
    GPSTagConstants.GPS_TAG_GPS_TIME_STAMP, outputSet.byteOrder, timeStamp);

SanselanではTiffOutputFieldオブジェクトを作っていきますが、Commons Imagingと比べると編集対象によって値の指定方法が異なる点はすこし扱いずらいと感じました。

Commons ImagingによるExif日付情報の書き換え

SVNからコードをcheckoutすると、パッケージ名が org.apache.commons.imaging に変更されています。 これはスナップショットですが、今回は2012/05/19にチェックアウトしたコードを使っていきます。

内部構造も変更が進んでいるので、単純にパッケージ名を変更するだけでは前述のコードは動きません。 先ほどと同じ内容のコードは次のようになります。

  TiffOutputDirectory gpsDirectory = outputSet.getGPSDirectory();
  gpsDirectory.removeField(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP);
  gpsDirectory.add(GpsTagConstants.GPS_TAG_GPS_TIME_STAMP,
      RationalNumberUtilities.getRationalNumber(new Double(calendar.get(Calendar.HOUR_OF_DAY))),
      RationalNumberUtilities.getRationalNumber(new Double(calendar.get(Calendar.MINUTE))),
      RationalNumberUtilities.getRationalNumber(new Double(calendar.get(Calendar.SECOND))));

SanselanではTiffOutputFieldを作成して追加していましたが、Commons Imagingでは直接TiffOutputDirectoryのaddメソッドを使うように変更されています。

また org.apache.commons.imaging.common パッケージの RationalNumberUtilities を使い、Double型をRationalNumber型に変換するところもポイントです。

全体としては操作方法に統一性があるのでAPIドキュメントとfind, grepがあれば、必要な機能の使い方は推測できると思います。

AndroidでCommons Imagingを使う時の考慮点

パッケージのサイズが大きいので、SanselanのExif編集機能だけをAndroid用にまとめたコードsanselandroidとしてgoogle codeでホストされています。

スナップショットをビルドしてできるライブラリJARファイルは672KBなので、Sanselan-0.97と比較して200KB近く大きくなっています。 そこでsanselandoroidにならってEclipse上でライブラリプロジェクトを作成し、Androidアプリから参照するようにしました。

まだJARファイルのサイズは388KBほどあって、sanselandroidほど小さく(248KB)なっていませんが、うまくまとまればGithubにでも公開したいと思います。需要があるのが分かれば、現状のまま上げてもいいんですけどね。 とりあえずはSanselandroidで十分だと思います。

さいごに

AndroidにはExifInterfaceクラスがあって、そこそこの操作はできますが、書き換えについてはヘッダを壊してしまう場合があるように思えます。

実際の操作はandroidに組み込まれているjheadライブラリを使っているはずです。 少ないファイルを処理している範囲では、体感的なスピードはSanselanでも大差はないと感じています。

Android 2.2のソースコードではjheadのバージョンが2.87です。 そこからの変更点をみていくと、いくつか重要なfixが行なわれているようにみえるのが気になるところです。

1 件のコメント:

Kazumichi SUZUKI さんのコメント...

こんにちは!
ExifInterfaceで上手くいかず、ハマっていましたので、大変参考になります。ところで、

「まだJARファイルのサイズは388KBほどあって、sanselandroidほど小さく(248KB)なっていませんが、うまくまとまればGithubにでも公開したいと思います。」

これ、公開されたのでしょうか?もしあれば利用させて頂きたいのですが・・・