Sony RAW画像フォーマット(ARW)のマジックバイト検出を追加
marcelにimage/x-raw-sonyのコンテンツベース検出が追加され、ファイル拡張子に依存せずSony ARWファイルを正確に識別できるようになりました。
背景
image/x-raw-sony はSonyカメラが生成するRAW画像フォーマットで、.arw拡張子を持つ image/tiff の独自拡張です。marcelはすでに拡張子ベースでのMIMEタイプ識別をサポートしていましたが、ファイルの内容(マジックバイト)を使った検出には対応していませんでした。
拡張子ベースの検出は、拡張子が変更された場合や拡張子なしでファイルが渡された場合に正確な識別ができません。ARWはTIFFのバイナリ構造を基盤としつつSONYタグを含む独自仕様のため、TIFFと区別するためにはファイル内容の検査が不可欠です。
また、実サンプルの入手が困難であることもこの実装の課題でした。PR著者によると、Sonyが提供するサンプルファイルの最小サイズが16MBと大きく、リポジトリへのコミットに適しません。そのため、実際のARWファイルを先頭8KBに切り詰めたものがテストフィクスチャとして使用されています。画像ビューアでは開けませんが、MIMEタイプ検出に必要なマジックバイト領域として十分な内容を保持しています。
技術的な変更
マジックバイト検出のコアロジックは lib/marcel/tables.rb のマジックテーブルに1行追加されました。ARWはTIFFのバイトオーダーマーカーを共有しつつ、ファイル内にSONY文字列を持つことで識別できます。
変更後(追加行):
['image/x-raw-sony', [[0, b["II*\000"], [[0..4096, b['SONY']]]], [0, b["MM\000*"], [[0..4096, b['SONY']]]]]],
['image/tiff', [[0, b["MM\000*"]], [0, b["II*\000"]], [0, b["MM\000+"]]]],
このエントリは2つの検出パターンを組み合わせています。1つ目の条件はTIFFのリトルエンディアン識別子 II*\000(Intelバイトオーダー)で、2つ目は MM\000*(Motorolaバイトオーダー)です。どちらのケースも、バイトオフセット0〜4096の範囲内に文字列 SONY が存在することを追加条件としています。
マジックテーブルにおいてimage/x-raw-sonyのエントリがimage/tiffより前に配置されている点が重要です。marcelはテーブルを上から順に評価するため、TIFFヘッダを持ちかつSONYタグを含むファイルはimage/tiffではなくimage/x-raw-sonyとして先に一致します。
テスト面では test/magic_test.rb のアサーションメッセージが改善されました。
変更前:
assert_equal content_type, Marcel::MimeType.for(file)
変更後:
actual_type = Marcel::MimeType.for(file)
assert_equal content_type, actual_type, "Expected #{file} to be #{content_type}, but was #{actual_type}"
これにより、テスト失敗時に期待値・実際値・対象ファイルがすべて出力されるようになり、デバッグが容易になります。
設計判断
TIFFヘッダへの依存とSONYタグによる絞り込みという二段階検出方式が採用されました。
ARWはTIFFの構造を持つため、TIFFの識別子(II*\000 / MM\000*)を1次条件とし、SONY文字列の存在を2次条件とすることで、一般的なTIFFとの衝突を避けています。検索範囲を 0..4096(先頭4KB)に限定しているのは、実用的なパフォーマンスを維持しながら、SONYタグが通常ファイルの早い段階に存在することを前提とした設計です。テストフィクスチャも8KBに切り詰めたファイルを使用しており、この検索範囲を十分にカバーしています。
また、拡張子ベースのエントリ(tables.rbの上部テーブル)はすでに存在していたため、今回の変更はマジック検出テーブルへの追加のみです。既存の拡張子検出との組み合わせにより、拡張子とコンテンツの両方からARWを識別できるようになっています。
まとめ
ARWのマジック検出は、TIFFとの構造的類似を逆手に取り、2段階の条件でSony独自フォーマットを正確に識別する実装です。マジックテーブルのエントリ順序という既存の仕組みを活かしつつ、最小限のコード追加で拡張子不要なコンテンツベース識別を実現しています。