このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

CGIからGIFの情報の取得について

発言者:さと
( Date Saturday, September 29, 2001 13:54:11 )


CGIから、GIF画像ファイルの縦幅と横幅を取得したいのですが、
うまく出来ません。
↓のサイトの[gifdog.pl]中のコードを利用して、行おうとしましたが、
知識不足のせいか、分かりませんでした。
 http://tohoho.wakusei.ne.jp/soft/wcnt.htm#gifcat.pl 
 http://cgi-bean.virtualave.net/ 

宜しくお願いします。

→  とほほ

田中求之 さんからのコメント
( Saturday, September 29, 2001 14:44:02 )

GIF ファイルの先頭の10バイトを読み込んでください

最初の6バイトは GIF のバージョンになっています

7バイト目と8バイト目が画像の横幅の情報です。7バイト目の値に8バイト目の
値の 256 倍を加えたものが横幅です。

9バイト目と10バイト目が画像の縦幅の情報です。9バイト目の値に10バイト
目の値の 256 倍を加えたものが縦幅です。

参考にならないと思いますが、AppleScript でのスクリプトだと以下のように
なります。

set myFile to choose file of type {"GIFf"}

set myData to MT Read File myFile from 7 to 10
set x to MT ASCII Numbers myData
set myHeight to ((item 4 of x) * 256 + (item 3 of x)) as string
set myWidth to ((item 2 of x) * 256 + (item 1 of x)) as string

"WIDTH=" & myWidth & " HEIGHT=" & myHeight

さと さんからのコメント
( Saturday, September 29, 2001 17:44:14 )

ありがとうございました。

でも、ちょっと分かりません・・・(>_<)
CGIにすると、どの様な感じになるのでしょうか。

重松修 さんからのコメント
( Saturday, September 29, 2001 22:19:48 )

何がどうわからないのでしょうか?

補足するとすれば、縦・横の幅は 2 バイトでリトルエンディアンで
記録されています。リトルエンディアンの意味がわからないのか、
田中先生が示されたコードのうち OSAX を使っている部分の動作が
わからないのか、もうすこし具体的に書かないとコメントしようがないですよ。

CGI にすると、という意味もさっぱり不明なのですが、引数として
ファイル名を渡すと、縦と横のサイズを表示する CGI が作りたい、
でも、CGI の書き方がわからない (ので手取り足取り、動くコードを書いて
教えて欲しい) ということなのでしょうか?

いずれにしても、とほほさんのページと田中先生の説明でわからないなら、
プログラム言語自体をもう少し修得された方がいいと思います。

重松修 さんからのコメント
( Saturday, September 29, 2001 22:21:50 )

あと、書き忘れましたが、おそらく QuickTime 4 か
MacOS 9.2 のバグだと思いますが、gifcat.pl の出力結果を
表示できないことがあります。
私も原因は調査中ですが。
もし、AppleScript に移植中ならば、お気をつけ下さい。

さと さんからのコメント
( Sunday, September 30, 2001 00:30:47 )

重松修さん>
はい、縦と横のサイズを表示するCGIが、作りたいんです。
知識が全く、不十分のようです・・・。
こんな事をしてみましたが、無理でした。全く、違うようですね。
-----------------------
open(IN,"./testimg\.gif");
$ImgData = <IN>;
close(IN);

$test = substr($ImgData, 7, 1);
$test = ord $test;
$test2 = substr($ImgData, 8, 1);
$test2 = ord $test2;
$test2 = test2 * 256;
$test3 = test + test2;

$test = substr($ImgData, 9, 1);
$test = ord $test;
$test2 = substr($ImgData, 10, 1);
$test2 = ord $test2;
$test2 = test2 * 256;
$test = test + test2;
print <<"EOM";
横幅$test3
縦幅$test
EOM
-----------------------

仰るとおり、できれば、「動くコード」を書いて教えて頂きたいです。

宜しくお願いします。

重松修 さんからのコメント
( Sunday, September 30, 2001 14:34:14 )

言語は Perl をお使いのようですね。
そういう重要なことは、まず最初に書かないと、いけませんね。

で、結論から言えば、gifcat.pl の説明書をよく読んでください。
# あるいはコメント。

それが動くコードです。縦横の寸法はおろか、様々な情報を表示できます。

あと、PHP でも同じコードを書いてみました。(ただし、そういう画像情報
については私が必要としていないので実装していません。)


→  gifcat PHP 版

さと さんからのコメント
( Sunday, September 30, 2001 14:56:50 )

いえ、ですから、[gifdog.pl]を見ても、
分からなかったので、「動くコード」書いて教えて欲しいと言うことです。

すみません、CGIと言えば、Perlかと思っていましたが、
そういう事じゃないみたいですね?解りませんでした。

[gifcat PHP 版]ですが、全く分かりません。CGI,Perlでお願いします。

重松修 さんからのコメント
( Sunday, September 30, 2001 23:08:36 )

まず、私は動くコードを教えるつもりは一切ありません。
たとえば、1+1 の答えがわからない人に 2 だ答えだけ教えて、
その人が、それ以外の数の計算ができるようになるとは思いませんから。

とりあえず、提示されたコードの問題点を。

* #!/usr/bin/perl から始まる必要があるのではないか?
* OS が書かれていないため問題が生じるかどうかわからないが、
  ファイルがバイナリモードとして開かれてない。
* substr() の使い方が違う。文字のオフセットは 0 から数える。
* 適切な HTTP ヘッダを出力していないのではないか。

といった具合ですね。私は Perl は使ったことがないので、
これ以外にもうまくいかない理由があるかも知れません。

今回の必要な知識は、
* GIF という画像形式に対する知識
* Perl という言語に対する知識
* CGI というアプリケーションに関する知識
です。

どれも、よくわからない、でかたづけてしまっているようですが、
本屋に行けば山と Perl/CGI の入門書がありますし、
一度読破してみてはいかがでしょうか。

それ以外にも、実行環境、Perl のバージョン、等々、
環境を全く書かなかったりと、ご自身の置かれている立場・問題点を
見ず知らずの第三者に伝えるのがさとさんはどうも苦手のようですね。
よい回答を得るためには、良い質問をしなければなりません。
もう一度、質問の仕方を見直してみてはいかがでしょうか。

あと、私は、gifdog ではなくて、そのオリジナルの gifcat のほうが
単純でわかりやすいので、そちらを見てはどうかと提案したんですが?

さと さんからのコメント
( Monday, October 01, 2001 00:06:51 )

当然、[/use/bin/perl]などの処理は、行っています。
コード上の一部を抜粋してるつもりですが。
CGI,Perlを全て、掲示板上に表記してしまうのは、問題かと思いまして。

CGI上で使用する上での環境ですので、通常のプロバイダの環境。
つまり、一般的なものですが。

いちいち、随分と皮肉な言い方をしますね。
私が、分かりもしない、PHP版などを書いてて、
「動くコードを教えるつもりは一切ありません。」と言ってることと矛盾してますね。
これは、私が、「PHPを知らないから」わざと、「PHP版」を書いてるんじゃありませんか?
だいたい、PHP版のコードを見て、どうしろと言うんですか?
貴方が、CGI,Perlを知らないから、そして、皮肉なんじゃありませんか?

>たとえば、1+1 の答えがわからない人に 2 だ答えだけ教えて
ですから、私自身で、書いた、抜粋したコードの問題点を指摘して
頂いてくれても、結構でしたが。
1+1の解き方が分からない人に、解き方を教えてあげればいいんじゃないですかね?
そんな事をしていたら、1+1の解き方が分からない人は、いつまで経っても、分からないままですけど。

>私は、gifdog ではなくて、そのオリジナルの gifcat のほうが
始めに書き込みしたとおり、分からないから、聞いたのですが。両方のことを推測できませんかね。

これ以上(既に)のことを続けると、この掲示板の本来をずれるので、止めておきます。

しあわせのツボ さんからのコメント
( Monday, October 01, 2001 00:41:33 )

ヒントでなく回答を要求しておいて、
ヒントしか与えられないと今度は逆ギレですか。

他言語の記述でもある程度ロジックを読むことはできますし、
人のスキルを確認せず「Perlを知らないから」などと
言うべきではありません。
少なくとも「動くコード」を書ける時点で、あなたよりは
Perlを知っている方だと思いますが、違いますか?

解き方は既に十分提供されています。
あなたに「教わる態度」がないから理解できないとしか
見えないのですが。

> これ以上(既に)のことを続けると、この掲示板の本来をずれるので、止めておきます。
それがお互いのためでしょうね。
Perlの質問をできる掲示板はたくさんありますから、
ここの風土になじまないなら、そちらを利用して下さい。
その態度のままでは、どこに行っても同じでしょうけど。


//
という切り捨て方は、田中先生の望むところでは
ないだろうなぁ…とは思いつつ。

今井真人 さんからのコメント
( Monday, October 01, 2001 09:34:10 )

ネット上で問い合わせる際のマナー
http://www.ed.kagawa-u.ac.jp/~akiyama/mac/News/tf/tf-manner.html

というページがあります。参考にしてみてください。

→  ネット上で問い合わせる際のマナー



重松修 さんからのコメント
( Monday, October 01, 2001 10:30:34 )

さとさん。

まず、GIF のサイズを表示する程度の CGI は、Perl で書けますよ。(w
私が Perl を使わないのは、それを CGI として使うのが「美しくない」
と思う美的感覚の問題です。
私は、自分自身では、あなたが思うほど素人ではないと思いますが。
# 自意識過剰でしょうか。:-P

また、この会議室は、「自分でサーバを運営する人のための場」なので、
暗黙のうちに「環境は自分で好きに変更できる」と判断します。
ですので、プロバイダに間借りしているというような特殊な例の場合、
あらかじめ、そういうことは明示しないとわかりませんよね?
というか、今まで何度もいっているのに、最低限の常識である、
環境を明示するということすらで行っていないので、
場所を変え、相手を変えても、スムーズに問題は解決しないでしょう。
今回の問題だとほとんど環境に依存するような案件はないですが、
それでも、依存した問題でないとは言い切れませんから。
まあ、何事も修行ですし、経験を積めばなぜ教えてもらえなかったのか、
わかる日も来るでしょう。

しあわせのつぼさん
とりあえず、来るもの拒まず去る者追わず、ではなかったでしょうか。>風土
いずれにせよ、もう少しで解決できるところまで来ているので、
後少しがんばって、解決の報告が聞きたいという気持ちはありますが。
2ch とかなら晒し age ものかな。このスレッド。

今井真人さん
有益なページのリンクをありがとうございます。
いつもは、http://www.geocities.co.jp/SiliconValley/5656/ あたりを
紹介しているんですが、ここは、文章が毒々しいので、もっと
真面目な表現のものがあればいいなと思っていました。
早速ブックマークしておきます。

重松修 さんからのコメント
( Monday, October 01, 2001 10:54:45 )

ちなみに、動くコードが書けない、と思われているようなので、
あまりにしゃくなので Perl で CGI として書きました。
# アホらしいけど、apache の設定変えました。;-)
# くどいけど、美的に許容できないから、普通は CGI としては動作させません。

動くコードそのものはこう。

#!/usr/bin/perl
open(IN,"1.gif");
binmode(IN);
$buf = <IN>;
close(IN);

$wl = ord(substr($buf,6,1));
$wh = ord(substr($buf,7,1));

print "content-type: text/html\r\n\r\n";
print $wh * 256 + $wl;

ファイルは固定で、幅だけですけど、高さの計算の仕方がわからない
からコードに書いてない、などと思わないでください。(w

実際に動かしてみないと、信用しませんか?

http://www.ravi.ne.jp/%7eshige/gifcat/test.cgi

でどうぞ。Perl はしりませんけど、この程度のことは出来ます。

http://www.ravi.ne.jp/%7eshige/gifcat/index.php

で使っている連結元の 1.gif のサイズを表示します。
gif 画像そのものは、

http://www.ravi.ne.jp/%7eshige/gifcat/1.gif

で取得できます。

> 1+1の解き方が分からない人に、解き方を教えてあげればいいんじゃないですかね?

ということで、コードをそのものを提示する行為は 2 を教える行為、
コードや理解が足りない部分から次にするべき行動を示す行為が、
解き方を教える、と私は思いますから、というわけで、
書けないわけではなくて、「あたなのためにならないので」
今まで書かなかっただけだというのはおわかりになれたかと思います。

うーん、でも、結果答えを書いたから、何とも不毛な。。。

重松修 さんからのコメント
( Monday, October 01, 2001 11:17:58 )

あと、gifcat について。
コメント読めば、すぐにわかることですけど、使い方として、
説明がそのままのってます。

#!/usr/bin/perl
require('gifcat.pl');
print "content-type: text/plain\r\n\r\n";
&gifcat'gifprint("1.gif");

とすればいいだけ。

コメント読んでますか? 日本語で書いてありますよ。

;# 基本的な使い方
;#    require "gifcat.pl";
;#    open(OUT, "> out.gif");
;#    binmode(OUT);    # MS-DOS や Windows の場合に必要です。
;#    print OUT &gifcat'gifcat("xx.gif", "yy.gif", "zz.gif");
;#    close(OUT);
;#
;# デバッグ用(GIFの解析出力)
;#    require "gifcat.pl";
;#    &gifcat'gifprint("xx.gif", "yy.gif", "zz.gif");

これも動くものは、

http://www.ravi.ne.jp/~shige/gifcat/test2.cgi

でどうぞ。

前薗 健一 さんからのコメント
( Monday, October 01, 2001 11:21:07 )

田中さんと重松さんの情報だけから
C だと、細かいことは抜きにして

typedef struct {
  char dummy[ 6 ];
  short w;
  short h;
} GIFHeader;

GIFHeader hdr;
// open file
hdr = ... // ファイルからヘッダ部分だけ読む
// close file
short w = ntoh( hdr.w );
short h = ntoh( hdr.h );

こんだけ。 :-)

前薗 健一 さんからのコメント
( Monday, October 01, 2001 11:26:42 )

little endian to big endian は hton() でしたっけ?
最近使っていない (^^;

今泉克美 さんからのコメント
( Monday, October 01, 2001 12:14:12 )

こういう質問があると
常に思うのですが、
なにかの機能要求があったときに
「それって何に使うの?」
と自問自答しちゃうクセがあります。

疑問なのですが、perlによるCGIで
gif画像のサイズを取得するメリットは
何でしょう?

webサイトで公開して使うというのはチョット変な
気がします。(後述)

windowsマシンならば、ローカルで
gif画像の大きさを取得するプログラムがありまして
HTML文書を作成するときに利用しています。
(画像のプロパティー見るだけでもわかるといえば
わかりますが、、、)

「HTML文書のレンダリング速度の最適化をはかりたいので」
という目的があるのなら「CGIがどうしても使いたい」
ことは抜きにして、ダイレクトな別解があるような
気がします。

(後述)の続き
最近はやりの?
画像アップローダ関連で作りたいのなら
この程度でつまずいていたら無謀だとも
思いますし。

まぁ独り言ですが、
質問者は、目的も明言したのうが
いいと思っています。


重松修 さんからのコメント
( Monday, October 01, 2001 12:46:01 )

前薗さん
エンディアンの変換関数なんてあるんですか? はじめて知りました。:-)
UN*X などの場合、

const static short foo = 0x1234;
if(0x12 = *(char*)foo){
  /* big endian */
}else{
  /* little endian */
}

のように動作を分けたり、そもそも影響を受けないように、

wl = fgetc(fp);
wh = fgetc(fp);
w = (wh << 8) | wl;

というやり方の方が一般的だと思います。

後、厳密にやるとすれば、EOF の検出のコードも必要ですね。

前薗 健一 さんからのコメント
( Monday, October 01, 2001 13:46:01 )

to 重松さん
Network と plat home の互換性を持たせるためにあります。

ntoh() > Network to Host
hton() > Host to Network

plat home を UNIX, DOS, OS/2, Windows, Mac, etc と考えてもいいし、
Intel 系 x86 ( little endian ), Motorola 系 68K ( big endian ) 。

それぞれ 2 bytes, 4 bytes 用があります。だったはず。忘れています。(^^;
詳細は御自分でお調べ下さい。

私も昔この関数があるのを知らなかった時、自分で実装しました。
重松さんとは違うやり方ですが。:-)