l'essentiel est invisible pour les yeux

Wednesday, May 23, 2007

[Ruby] EXIFのGPS情報も取得できるExtExif 1.0をリリースした

extexif

RubyにはEXIF(Exchangeable image file format)を扱うための実装がいくつかあるが、全て開発がとまっている。Pure Rubyで実装されたruby-exifは、Ruby1.8だとパッチを当てないとコンパイルが通らない。二つ目はCで書かれたlibexifをRubyから呼び出せるように拡張ライブラリで実装されたruby-libexifであるが、2007年5月23日現在サーバが落ちている。幸いローカルにキャッシュがあったためコンパイルを試みたが、Ruby1.8.5ではコンパイルが通らない。Debainパッケージではコンパイルが通るように修正が施されているが、このライブラリはEXIFのGPSデータの取得をサポートしていない。

exif.c


#if 0
/* GPS tags are not supported in this library */
#endif


RubyのEXIF関連ライブラリはどれも開発がとまっている状況みたいなので、EXIFのGPS情報の取得もサポートするExtExifを作った。(RubyForge申請中なのでもう少し時間がかかりそう。)

インストール

% sudo gem install extexif


ドキュメント
ruby-libexifに実装されているExifクラスはそのまま利用可能であるが、もう一段抽象的な操作を提供するクラスとしてExtExifを実装している。現在のところは機能は少ないがこちらにEXIF関連で便利なメソッドとかを実装していく。

画像のパスを与えてクラスを生成して配列のようにEXIF Tag IDを使用してアクセスするだけです。

require 'rubygems'
require 'extexif'

# print EXIF data
IMG_FILE = 'image_with_exif.jpg'
image = ExtExif.new(IMG_FILE)
puts IMG_FILE
print "%-15s: %s\n" % ["Make", image["Make"]]
print "%-15s: %s\n" % ["GPSLatitude", image["GPSLatitude"]]
print "%-15s: %s\n" % ["GPSLongitude", image["GPSLongitude"]]



% ruby test_extexif.rb
image_with_exif.jpg
Make : KDDI-CA
GPSLatitude : 35.00, 39.00, 45.38
GPSLongitude : 139.00, 41.00, 16.89
%


EXIF Tag IDについては以下のサイトを参考に。
ExifTAG

exif.cに対するパッチのみいる人は以下。

< #include <ruby.h>
< #include <libexif/exif-tag.h>
---
> #include "ruby.h"
> #include <libexif/exif-ifd.h>
15a14
> #include <libexif/exif-tag.h>
137d135
< char value[1024];
142c140
< v = rb_str_new2(exif_entry_get_value(entry, value, sizeof(value)));
---
> v = rb_str_new2(exif_entry_get_value(entry));
219d216
< char value[1024];
246c243
< return rb_str_new2(exif_entry_get_value(e, value, sizeof(value)));
---
> return rb_str_new2(exif_entry_get_value(e));
253c250
< found = exif_entry_get_value(e, value, sizeof(value));
---
> found = exif_entry_get_value(e);
356c353
< rb_funcall(dest, rb_intern("<<"), 1, rb_str_new((char *)exif->ed->data, exif->ed->size));
---
> rb_funcall(dest, rb_intern("<<"), 1, rb_str_new(exif->ed->data, exif->ed->size));
379d375
< #define GPS_SUPPORT
457,488c453,454
< #ifdef GPS_SUPPORT
< {EXIF_TAG_GPS_VERSION_ID, "GPSVersionID", N_("GPS tag version")},
< {EXIF_TAG_GPS_LATITUDE_REF, "GPSLatutideRef", N_("North or South latitude")},
< {EXIF_TAG_GPS_LATITUDE, "GPSLatitude", N_("Latitude")},
< {EXIF_TAG_GPS_LONGITUDE_REF, "GPSLongitudeRef", N_("East or West longitude")},
< {EXIF_TAG_GPS_LONGITUDE, "GPSLongitude", N_("Longitude")},
< {EXIF_TAG_GPS_ALTITUDE_REF, "GPSAltitudeRef", N_("Altitude reference")},
< {EXIF_TAG_GPS_ALTITUDE , "GPSAltitude", N_("Altitude")},
< {EXIF_TAG_GPS_TIME_STAMP, "GPSTimeStamp", N_("GPS time (atomic clock)")},
< {EXIF_TAG_GPS_SATELLITES, "GPSSatellites", N_("GPS satellites used for measurement")},
< {EXIF_TAG_GPS_STATUS, "GPSStatus", N_(" GPS receiver status")},
< {EXIF_TAG_GPS_MEASURE_MODE, "GPSMessureMode", N_("GPS measurement mode")},
< {EXIF_TAG_GPS_DOP, "GPSDOP", N_("Measurement precision")},
< {EXIF_TAG_GPS_SPEED_REF, "GPSSpeedRef", N_("Speed unit")},
< {EXIF_TAG_GPS_SPEED, "GPSSpeed", N_("Speed of GPS receiver")},
< {EXIF_TAG_GPS_TRACK_REF, "GPSTrackRef", N_("Reference for direction of movement")},
< {EXIF_TAG_GPS_TRACK, "GPSTrack", N_("Direction of movement")},
< {EXIF_TAG_GPS_IMG_DIRECTION_REF, "GPSImgDirectionRef", N_("Reference for direction of image")},
< {EXIF_TAG_GPS_IMG_DIRECTION, "GPSImgDirection", N_("Direction of image")},
< {EXIF_TAG_GPS_MAP_DATUM, "GPSMapDatum", N_("Geodetic survey data used")},
< {EXIF_TAG_GPS_DEST_LATITUDE_REF, "GPSDestLatitudeRef", N_("Reference for latitude of destination")},
< {EXIF_TAG_GPS_DEST_LATITUDE, "GPSDestLatitude", N_("Latitude of destination")},
< {EXIF_TAG_GPS_DEST_LONGITUDE_REF, "GPSDestLongitudeRef", N_("Reference for longitude of destination")},
< {EXIF_TAG_GPS_DEST_LONGITUDE, "GPSDestLongitude", N_("Longitude of destination")},
< {EXIF_TAG_GPS_DEST_BEARING_REF, "GPSDestBearingRef", N_("Reference for bearing of destination")},
< {EXIF_TAG_GPS_DEST_BEARING, "GPSDestBearing", N_("Bearing of destination")},
< {EXIF_TAG_GPS_DEST_DISTANCE_REF, "GPSDestDistanceRef", N_("Reference for distance to destination")},
< {EXIF_TAG_GPS_DEST_DISTANCE, "GPSDestDistance", N_("Distance to destination")},
< {EXIF_TAG_GPS_PROCESSING_METHOD, "GPSProcessingMethod", N_("Name of GPS processing method")},
< {EXIF_TAG_GPS_AREA_INFORMATION, "GPSAreaInformation", N_("Name of GPS area")},
< {EXIF_TAG_GPS_DATE_STAMP, "GPSDateStamp", N_("GPS date")},
< {EXIF_TAG_GPS_DIFFERENTIAL, "GPSDifferential", N_("GPS differential correction")},
---
> #if 0
> /* GPS tags are not supported in this library */
490d455
<
567c532
< {-1, NULL, NULL}
---
> {0, NULL, NULL}
592c557
< for (i = 0; ExifTagTable[i].tag != -1; i++) {
---
> for (i = 0; ExifTagTable[i].tag != 0; i++) {


gemパッケージの中の写真はGOLDRU$Hの金曜限定ランチ1ポンドバーグ(450g)だというのは秘密。