• ベストアンサー

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が見つからなかったときにループを抜ける処理をかいていませんが、見つかればループは抜けるはずなので、それは書いてません。 ですが、こう書いても無限ループに陥ってしまいます。 なにがいけないやら分かりません。 どこがいけないでしょうか。

  • arcsin
  • お礼率46% (194/417)
  • CGI
  • 回答数3
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.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バイトスキップしちゃった」と言うバグを作った事があります。

arcsin
質問者

お礼

ありがとうございます~ 無事解決できました! 分かりやすいアドバイス助かりました^^ またよろしくおねがいします。

その他の回答 (2)

  • osamuy
  • ベストアンサー率42% (1231/2878)
回答No.2

>  if(getc(IN) == 0xFF){ Perlのgetc()で得られるのは、文字列オブジェクトです。 Cと違って、数値として直接比較する事はできません。 perl -e 'print "a" eq "\x61" ? "OK\n" : "NG\n"' ・・のように記述してみては。

arcsin
質問者

お礼

ありがとうございます~。 無事解決いたしました~

  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.1

無限ループの件はちょっと判りませんが、セグメントのスキップを正しく行わないと、思った通りのデータが拾えない場合があります。 スキップを正しく行わない場合、例えば、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のセグメント解析は「先頭から順サーチ」では出来ないので、もう少し工夫が必要です。

arcsin
質問者

お礼

すいません。回答の補足に関する訂正です。 >1:…2byteだけスキップ ではなくて、「その次のバイトにスキップ」です。

arcsin
質問者

補足

さっそくのご回答ありがとうございます。 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の発見 こんな感じになるのでしょうか?また、セグメントの長さとは最初の方で書いた、....の長さということでしょうか?

関連するQ&A

  • Jpegデータに関して

    同一の画格、同一のJpegヘッダ情報を持つ、二つのJepgファイルを下記方法で 1つのファイルにしようとするとViwerでの表示に乱れが生じます。 何故乱れが生じるのかご教授お願いします。。。 画像は被写体こそ違いますが、どちらもYCbCr:4:2:0で、160x160のサイズです 1:画像2のイメージパートを画像1のイメージパートの直後にコピー 2:SOF0マーカー内にあるサイズを160x160から160*320に変更 スタート/エンドマーカ等必要はマーカは全て存在しています 乱れといっても全く見れない訳ではなく二つの画像の境界付近からした半分が 白黒のようのボヤけて表示されてしまいます 各々のファイルで圧縮かけたものなので無理なのかもしれませんが 乱れをなくしたいです。 操作後のファイルを添付しています

  • Image::Magickを利用して、任意の縦横各サイズを指定したフレ

    Image::Magickを利用して、任意の縦横各サイズを指定したフレーム内に、 縦横比の違う複数の画像ファイルをHTNL側で指定して呼び出すPerlCGIを 作りたいのですが、今のところ下記のようなimg1.cgiとimg2.cgiが分かっています。 img1.cgiは、複数画像の入っているフォルダを指定してHTML側で呼び出せるのですが、 現状サイズ指定はできません。img2.cgiは、Image::Magickを利用してサイズ調整は できるのですが、HTMLからのファイル指定とができません。 指定したフォルダから任意のファイル名をHTMLから呼び出し、元画像の縦横比を 変えることなく、スクリプト内で指定した縦横サイズ内に最大の画像を表示させるには どの様にしたらよろしいでしょうか。ご教授頂ければ幸いです。 宜しく、お願いします。 【img1.cgi】 ===CGI=== #!/usr/bin/perl use strict; my $fileName = $ENV{'PATH_INFO'}; my $view = './gazou'.$fileName; my $extention; if( $fileName =~/.+\.(\w+)/){$extention = $1;} print "Content-type: image/$extention\n\n"; open IMG,"$view"; binmode IMG; binmode STDOUT; while(<IMG>){ print; } close IMG; ===HTML=== <IMG src="img1.cgi/ファイル名.JPG" border="0"> 【img2.cgi】 ===CGI=== #!/usr/bin/perl use Image::Magick; $newwidth = 100; $newheight = 100; $i = Image::Magick->new; $i->Read('./gazou/3.JPG'); $i->Scale(geometry=>geometry, width=>$newwidth, height=>$newheight); print "Content-type: image/gif\n\n"; binmode(STDOUT); $i->Write("jpeg:-"); exit; ===HTML=== <IMG src="img2.cgi" border="0">

    • ベストアンサー
    • CGI
  • c言語 ファイルの読み込み位置

    ファイルのアクセス位置を最後から7行目に移動させるプログラムを作っています。 \nを数えることで行数を数えているのですが、以下の処理、間違えていますか? コンパイルしてもできていないので間違えていることは明白なのですが、どこが違うかわかりません。 誰か、力になってください! fseek(fp, -1, SEEK_END);/*読込位置最後にする */ while(!fseek(fp, -2, SEEK_CUR))/*逆順読込ループ*/ {   if(getc(fp)=='\n')  {cnt++;}  if(cnt == 7)  {break;} }

  • 困ってます(泣)『イメージファイルが小さすぎます。縦横それぞれ32ピクセル 以上でなくてはいけません』

    困っています。オークションで画像をアップロードしようとしているのですが、元の画像が小さく、ペイントなどで画像を大きくしても『イメージファイルが小さすぎます。縦横それぞれ32ピクセル 以上でなくてはいけません』と表示されてしまいアップロードできません。元は、プロパティで「ビットマップイメージ・サイズ240KB・ディスク上のサイズ244KB」を、「JPEGイメージ・346KB・ディスク上のサイズ348KB」に苦難して変更したのですが、同じ様に『イメージファイルが小さすぎます。縦横それぞれ32ピクセル 以上でなくてはいけません』と、なってしまいます。元が小さいので、ペイントで変更してもダメなのでしょうか?こういった、小さい画像を処理をする無料のソフトなどあるのでしょうか?パソコン初心者です。専門用語はわかりません。助けてください!!

  • Perlで画像のサイズ取得する方法

    URL指定で画像サイズの取得が出来ません。 何方かご教授お願いします。 悲しいことにレンタルサーバーにはimage::magickがインストールされていないので使えません。 ----perl---- #!/usr/bin/perl $FileName = "http://i.yimg.jp/images/main11.gif"; ( $format, $width, $height ) = &GetImageSize( $FileName ); print "Content-type: text/html\n\n"; print <<"HTML"; <META http-equiv="Content-Type" content="text/html; charset=Shift_JIS"> <BR> $width x $height <br> <IMG src="$FileName" border="0"> HTML sub GetImageSize{ my ( $IMG, $in ) = @_; my ( %SHT, %LNG ); my ( $buf, $mark, $type, $f_size, $width, $height ); my ( $TAG, $TYPE, $COUNT, $V_OFFSET, $PK, $ENTRY, $Exif_IFD ); my ( $endian, $dummy1, $dummy2, $dummy, $EOI, $APP1, $length, $exif ); my ( $format, $offset, $line, $CODE, $jfif ); my @TGA; my $ntag; # 定数 $mark = pack("C", 0xff); %SHT = ( 'II' => 'v', 'MM' => 'n' ); %LNG = ( 'II' => 'V', 'MM' => 'N' ); # 初期値 $endian = ''; $width = -1; $height = -1; $format = ''; $Exif_IFD = -1; if( $in eq '' ){ $in = 'IMG'; } open( $in, $IMG ) || return( '', -1, -1 ); binmode($in); seek( $in, 0, 0 ); read( $in, $buf, 6 ); # GIF 形式 if($buf =~ /^GIF/i){ $format = 'GIF'; read( $in, $buf, 2 ); $width = unpack("v*", $buf); read( $in, $buf, 2); $height = unpack("v*", $buf); } close( $in ); return( $format, $width, $height ); } exit;

    • ベストアンサー
    • Perl
  • PHPでjpg画像を位置を指定して拡縮させる方法

    お世話になります。 PHPで、どうしてもわからないところで躓いております。 GDはonの状態でPHP5をXAMPPにて扱っております。 やりたいことは至って簡単で、 座標上で、例えば(10,10)の位置に画像を指定した縦横サイズ(30,30)に縮小して、 貼り付けたいのですが、 色々と関数を試しても、なぜか画像が表示されず、困っております。 貼り付ける画像の拡張子はJPEGです。 お忙しいところ恐れ入りますが、 宜しくお願い致します。

    • ベストアンサー
    • PHP
  • エクセルのシートに貼りつけたbmpをjpegに

    手持ちの本(4冊)やインターネットで探せなかったので、教えてください。 エクセルのシートに15枚の画像(bitmap)が貼られており このままではファイルが重いので、同サイズのjpegに変換したいのですが・・・ 手でやると 画像選択→切り取り→貼り付けセルを選択→型式を選択して貼り付け→図(jpeg) 以下マクロの記録 ActiveSheet.Shapes.Range(Array("図 11")).Select Selection.Cut Range("H60").Select ActiveSheet.PasteSpecial Format:="図 (JPEG)", Link:=False, DisplayAsIcon:= _ False End Sub となります。 これをVBAで数10ファイル連続で実行したいのですが、1つ問題があります。 画像はカウント後に配列で取り込み順次処理していきますが、 同じ場所に同じ大きさで貼りたいのですが、元画像を貼り付けているセルの番地の 取得をどうしたらよいか悩んでいます  コレ → Range("H60").Select 画像が張り付いているセルは複数で左上のセルを選択して貼り付けしたいのですが・・・ 貼り付けた画像(bitmap)は名前が自動的に振られているのでセルを指定して貼り付けると 元の位置に貼られない可能性があるので・・・ 貼り間違いなどで、同じ位置でも図の名前(図11等)が違ってしまっている場合 説明が下手で申し訳ありませんが、ご存知の方よろしくお願いいたします。

  • 【Vb.net】プリンタジョブの取得

    http://jehupc.exblog.jp/8603528/ 上記のページを参考にさせて頂きvb.netにて、印刷処理を実行し、印刷ジョブを監視するプログラムを作成しました。 印刷処理を実行した時、印刷は実行されるのですが、どうも印刷の処理自体が早く、プリンタジョブを取得する前にジョブが終了してしまっているようです。 ジョブを監視しようにも、ジョブが既に消えてしまっているので、監視しているループから抜けだせません。 (ジョブが溜まっているときは上手くジョブを取得出来るのでプログラムの処理自体は問題ないと思います。) どうにか、消えてしまう前にジョブを取得できないでしょうか? 下記が該当のプログラムです。 処理自体はバックグラウンド処理でファイルの個数分ループしています。 -------------------------------------------------------------------------------------- '印刷処理 ShellExecute(IntPtr.Zero, "print", 【ファイルパス】, "", "", 0) 'プリントサーバの情報取得 Dim prtSv As New LocalPrintServer() '印刷キュー取得 Dim que As PrintQueue = prtSv.DefaultPrintQueue '処理フラグ T:正常 F:異常 Dim blnRtn As Boolean = True 'ジョブ番号 Dim intJobNum As Integer 'ループ内での時間カウント Dim intCnt As Integer = 0 '下記のループで待つ時間をミリ秒単位で指定 Dim intWatiMiliTime As Integer = 10 '印刷がキューに入るまで待つ。 While True '指定ミリ秒待つ Threading.Thread.Sleep(intWatiMiliTime) intCnt += intWatiMiliTime '1分以上たっていたら、印刷に問題があったことにして処理異常フラグを立てる If intCnt > 60000 Then blnRtn = False Exit While End If 'キューが1つ以上 If que.NumberOfJobs > 0 Then Dim jobList As New List(Of PrintSystemJobInfo)() '印刷ジョブコレクション取得 For Each ps As PrintSystemJobInfo In que.GetPrintJobInfoCollection jobList.Add(ps) Next '最新ジョブ名に印刷ファイル名が含まれるとき、このプログラムから印刷キューに入れたと判断する。 If jobList(jobList.Count - 1).Name.EndsWith(【ファイルパス】, True, Nothing) Then intJobNum = jobList(jobList.Count - 1).JobIdentifier Exit While End If End If End While intCnt = 0 '指定されたジョブが印刷完了するまで待つ While blnRtn '指定ミリ秒待つ Threading.Thread.Sleep(intWatiMiliTime) intCnt += intWatiMiliTime Dim jobNow As PrintSystemJobInfo Try jobNow = que.GetJob(intJobNum) Catch ex As Exception '(すでに印刷が完了してジョブが破棄されたとき対策) '異常フラグ立てループ終了 blnRtn = False End Try If jobNow.JobStatus = PrintJobStatus.Completed _ OrElse jobNow.JobStatus = PrintJobStatus.Deleted _ OrElse jobNow.JobStatus = PrintJobStatus.Deleting _ OrElse jobNow.JobStatus = PrintJobStatus.Printed _ OrElse jobNow.JobStatus = PrintJobStatus.Printing _ OrElse jobNow.JobStatus = PrintJobStatus.Retained Then 'ループ終了 Exit While End If 'ジョブがなんらかのエラか、タイムアウト(1分)したなら処理異常終了 If jobNow.JobStatus = PrintJobStatus.Error _ OrElse jobNow.JobStatus = PrintJobStatus.Offline _ OrElse jobNow.JobStatus = PrintJobStatus.PaperOut _ OrElse jobNow.JobStatus = PrintJobStatus.UserIntervention _ OrElse intCnt > 60000 Then '異常フラグ立てループ終了 blnRtn = False End If End While

  • Google Map Api 複数のマーカーをおくと、一部が表示されない

    お疲れ様です。 お世話になっております。 Google Map Apiで複数のマーカーを設置するスクリプトを組みました。 10件程度は問題なく表示されるのですが、10件を境に、表示されたり、されなかったりします。 F5で表示されるもの、されないものとまばらになるので、なんとなく原因は、処理よりも表示のほうが速いからではないか?ということなんですが、JSの処理の流れがイマイチわかっていないので、結論は出せません。 実際20件登録したところ、10件~17件の間で出たり出なかったりします。1~10件までは必ず表示され、その後ろのIDを持つものがランダムになります。 これを確実に全部表示されるようにしたいのですが、表示の前にsleepなどかけるのがよいのか、ajaxにしてみるのがよいのかなど、検討がつきません。 下記が、書いたスクリプトです。 もしよければ、アドバイスお願いします。 var markers = new Object(); var marker = new Object(); marker["name"] = "xxx"; marker["icon"] = "ylw-pushpin"; marker["address"] = "座標変換用の住所"; marker["text"] = "噴出しの中身"; marker["center"] = "中心にするかしないか"; markers[0] = marker; 20回ループ markers[20] = marker; googlemap(markers) -----------googlemap(markers) function googlemap(markers) { if (GBrowserIsCompatible()) { geocoder = new GClientGeocoder(); map = new GMap2(document.getElementById("map")); map.addControl(new GSmallZoomControl()); map.addControl(new GScaleControl()); for(var i in markers){ showAddress(markers[i]); //ここは20回ちゃんとまわってるようです } } } ------------------showAddress() function showAddress(amarker) { if (geocoder) { geocoder.getLatLng( amarker['address'], function(point) { if(amarker['center'] == 1){ map.setCenter(point, 12); } //アイコンが指定されてたらアイコンを設定 if(amarker['icon']){ var marker = new GMarker(point,micon); //アラートしてみると、ここが10回~17回ぐらいしか回ってない }else{ var marker = new GMarker(point); } map.addOverlay(marker); GEvent.addListener(marker, "click", function() { marker.openInfoWindowHtml(ふきだしのなかみ) }); } ); } }

  • メモリ不足になった後の処理

    PHPで処理中にメモリ不足になった場合、下記のようなエラーが起こるかと思います。 「Fatal error: Allowed memory size of xxxxx bytes exhausted (tried to allocate 16 bytes) in …」 ここで質問させて頂きたいのですが、 予めメモリ不足が起きる可能性がある処理を、tryなどで囲んでおき、実際にメモリ不足が起きた際は、その処理を飛ばし、それ以降の処理を実行させるといったことは可能でしょうか。 それとも、やはりメモリ不足でエラーが起きているので、その後の処理を実行させるといったことは出来ないのでしょうか。 もし何か方法などございましたら、ご教授頂けると助かります。 また、質問に不備な点などありましたら、ご指摘お願いします。 よろしくお願いします。

    • ベストアンサー
    • PHP

専門家に質問してみよう