- ベストアンサー
JPEGの縦横サイズ取得について。
立て続けの質問をお許しください。 JPEGの縦横サイズを取得するアルゴリズムを考えているのですが、以下のページを参考にしています↓ http://tohoho.wakusei.ne.jp/lng/200003/00030402.htm 縦横サイズの情報を探すためには、 ***上のURLより引用***************************** JPEG(ベースラインJPEGの場合)ファイルの場合SOFn マーカー FFC0 (Hex) を見つけてここから始まる.SoF0 セグメント FF の位置を0 として相対オフセット、位置 5 から、2Bytes に高さ 7 から 2Bytesに幅 ****引用終わり******************************* とある通り、マーカーFFC0を探さなければいけないらしいのですが、自分なりに色々調べながらマーカー位置を探すのに以下のような処理を考えました。 open(IN, "aaa.jpg") || die; binmode IN; while (1) { if(getc(IN) == 0xFF){ if(getc(IN) == 0xC0){last;} } } 上の処理は、FFC0が見つからなかったときにループを抜ける処理をかいていませんが、見つかればループは抜けるはずなので、それは書いてません。 ですが、こう書いても無限ループに陥ってしまいます。 なにがいけないやら分かりません。 どこがいけないでしょうか。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
#1です。 >1:SOI, EOI, RSTmの場合は2byteだけスキップ。 >ではなくて、「その次のバイトにスキップ」です。 そうですね。実際には、チャックしたマーカーの次のマーカーの位置に進んでますから、そのまま何もせず、次のマーカーの読み込みループに戻る事になりますね。 >こんな感じになるのでしょうか?また、セグメントの長さとは最初 >の方で書いた、....の長さということでしょうか? マーカーの次のレングスデータは、レングスデータそのものも含めた長さです。 レングス付きセグメント(SOI, EOI, RSTmじゃないと判定した時)は、マーカーに続く2バイトのレングスを拾い、レングスデータの次に進んでいるので、実際にスキップする長さは「拾ったレングス-2」になりますね。 あと、注意しないといけないのは、マーカーの次のセグメント長が「2」になってる場合。例えば、以下のようなファイルイメージ。 SOI :FF D8 APP0:FF E0 00 10 4A 46 49 46 00 01 02 01 00 48 00 48 00 00 COM :FF FE 00 02 APPD:FF ED .... COMセグメントを見付け、レングスデータの「2」を拾った後、読み込み位置は次のAPPDセグメントの所に居ます。 スキップすべきバイト数を「拾ったレングス-2」から計算し「0」になった場合、読み込み位置は次のセグメントの所になっているので、実際のスキップ処理はせず、次のマーカーの読み込みループに戻る事になります。 「コメントデータ無しでJPEG保存をすると、コメントが無くても無理矢理必ずセグメント長2のCOMセグメントを付けて保存する」と言う画像エディタがあって、これのおかげで「0バイトスキップしようとして65536バイトスキップしちゃった」と言うバグを作った事があります。
その他の回答 (2)
- osamuy
- ベストアンサー率42% (1231/2878)
> if(getc(IN) == 0xFF){ Perlのgetc()で得られるのは、文字列オブジェクトです。 Cと違って、数値として直接比較する事はできません。 perl -e 'print "a" eq "\x61" ? "OK\n" : "NG\n"' ・・のように記述してみては。
お礼
ありがとうございます~。 無事解決いたしました~
- chie65536
- ベストアンサー率41% (2512/6032)
無限ループの件はちょっと判りませんが、セグメントのスキップを正しく行わないと、思った通りのデータが拾えない場合があります。 スキップを正しく行わない場合、例えば、SoF0セグメントの前にリマークセグメントがあって、リマークデータの中に FF C0 のデータ並びがあると、プログラムは間違った結果を返すでしょう。 例えば、以下のような場合。 FF D8 FF EE 00 04 FF C0 FF E0 00 10 … これは、 FF D8 FF EE 00 04 FF C0 FF E0 00 10 … の3つのセグメントが並んでいますが、2番目のセグメント内の「FF C0」はセグメントマーカーではなく、リマークデータです。セグメントスキップを正しく行わないと、リマークデータとしての「FF C0」をマーカーと誤解します。 なお、リマークデータ以外に、セグメント内のデータには「FF xx」の組み合わせのデータが「データとして」出現する場合もあり、これもマーカーと誤解する原因になります。 実際に「リマーク内にマーカーと似たデータが居る」ようなJPEGファイルは、PhotoShopでサムネイル付きJPEGファイルを保存した場合に作成されます。 PhotoShopのJPEGのサムネイルデータはサイズが小さくなったJPEGファイルイメージで、リマークセグメントのリマークデータとしてJPEGファイル内に付加されます。 強引な言い方をすれば「JPEGファイル内に、小さいJPEGが入れ子になっている」と言えます。 JPEGのセグメント解析は「先頭から順サーチ」では出来ないので、もう少し工夫が必要です。
お礼
すいません。回答の補足に関する訂正です。 >1:…2byteだけスキップ ではなくて、「その次のバイトにスキップ」です。
補足
さっそくのご回答ありがとうございます。 http://www02.so-net.ne.jp/~koujin/jpeg/JpegMarker.html を一読し、またプログラムを組んでいるところです。 アドバイスを頂いて、先頭から検索する危険さがなんとなく分かってきました。上のURLとchie65536さんのアドバイスより、解釈したのは、 *********************************** セグメントの形式には2種類あって、 FF XX の形式と、 FF XX YY ZZ .... の形式(YY ZZ はそのセグメント本体の長さの情報が入っている) あるセグメント内の上の....以降でFF C0が出てしまったらこいつに引っかかってしまう。 だからセグメントごとにスキップする必要があって、 FFを見つけたら、 1:SOI, EOI, RSTmの場合は2byteだけスキップ。 2:それ以外の場合で、FFの後ろがC0でない場合、さらに後ろの2バイトを読み込み、そのセグメントの情報を得て、そのバイト分だけスキップ。 3:1,2の動作を繰り返し、FFの後ろがC0になったら めでたくSOFnの発見 こんな感じになるのでしょうか?また、セグメントの長さとは最初の方で書いた、....の長さということでしょうか?
お礼
ありがとうございます~ 無事解決できました! 分かりやすいアドバイス助かりました^^ またよろしくおねがいします。