HTML ファイルで画像を扱う時には、その画像の大きさを width="xxx" height="xxx" といったふうに指定しておくと、ブラウザでの表示が早くなります。しかし、画像の大きさをチェックするのに、いちいちその画像を画像処理プログラムで開いてみるのも面倒です。一番簡単な方法は、ImageMagic のコマンドを使うことです。ImageMagic はコマンドラインから利用できる画像処理プログラムで、たいていのディストリビューションに入っているそうです。Vine Linux にも入っていました。
identify [filename]とすると、画像の大きさや、形式などの情報を示してくれます。
私は、いままでこのコマンドの存在を知らなかったので、画像の大きさを指定しないで HTML を書いていました。後からひとつひとつのファイルを編集しなおすのも面倒なので、HTML に画像の定義 (<img src="xxxx") があれば、identify コマンドを呼出し、そこに画像サイズを書き込むプログラムを書きました。「必要は発明の母」とは言いますが、私の場合は「ものぐさはプログラミングの友」です。面倒なことをやりたくないのでプログラムを書くのです。もっともプログラムを書くというのは、ひょっとしたらもっと面倒なのですが、それが楽しみになるのです。ちょうど、買物に行くときにはできるだけ店に近いところに車をとめて、あまり歩かなくてよいようにしているくせに、ウォーキングとなると一所懸命遠くまで歩くのとあまりかわりませんね。
それはともかく、ImageMagic の機能は perl から利用できるそうですから、perl と c を組み合わせればいいのですが、私は perl の勉強を始めたばかりで、そうした高等なことができませんので、最初は、identify imagefile > temp.txt というコマンドをシステムに渡し、あらためて temp.txt を読み込んでいました。下の get_size() がそうです。
get_size(char *img) { FILE *fp; char buf[180], command[160], width[8], height[8]; int i, j; sprintf(command, "identify %s > temp.txt", img); system(command); if((fp=fopen("temp.txt", "r"))==NULL){ printf("Can't open <temp.txt>\n"); exit(0); } if(fgets(buf, 180, fp)!=NULL){ for(i=0; ; i++){ if(buf[i]==' ') break; } for(i=i+1, j=0; buf[i]!='x'; i++, j++) width[j]=buf[i]; width[j]='\0'; for(i=i+1, j=0; ; i++, j++){ if(buf[i]==' ' || buf[i]=='+') break; height[j]=buf[i]; } height[j]='\0'; sprintf(replace, "%s\" width=\"%s\" height=\"%s\"", img, width, height); fclose(fp); return YES; } else{ fclose(fp); return NO; } }
けれどもたった一行だけのインフォメーションを得るのにわざわざ temp.txt を作るのは大げさですので、後で、popen() を使う方法に書き換えました。popen は、あるコマンドから次のコマンドにパイプを通してデータが渡される時、そのパイプを通して渡されるデータを開いてみるもので、私は、Linux のプログラミングではじめてこれを知り、今回使ってみました。以下が改良した部分です。
get_size(char *img) { FILE *fp; char buf[180], command[160], width[8], hight[8]; int i, j, chars_read; sprintf(command, "identify %s", img); //identify の引数に画像ファイル名を渡す read_fp = popen(command, "r"); //pipe を「読み込み」で開く if(read_fp == NULL){ //開けなかった時の処理 pclose(read_fp); return NO; } else{ //pipe からバッファに読み込む chars_read = fread(buf, sizeof(char), 180, fp); if (chars_read == 0){ //読み込んだ文字が 0 の場合の処理 pclose(read_fp); return NO; } for(i=0; ; i++){ //以下は以前と同様 if(buf[i]==' ') break; } for(i=i+1, j=0; buf[i]!='x'; i++, j++) width[j]=buf[i]; width[j]='\0'; for(i=i+1, j=0; ; i++, j++){ if(buf[i]==' ' || buf[i]=='+') break; hight[j]=buf[i]; } hight[j]='\0'; sprintf(replace, "%s\" width=\"%s\" hight=\"%s\"", img, width, hight); pclose(read_fp); //pipe を閉じて終了 return YES; } }
できあがってから、何度か試して見ましたが、すでに画像の大きさを指定してある場合は画像の大きさを入れるのをスキップしなければと、気づいて、search() を二回かけるようにしました。search() も無茶苦茶いい加減なプログラムですが、私はこれを私のいろんな自作プログラムで使っていますが、小さなファイルを調べるだけですので、これで実用上問題はでていません。ただ、同じ行に img src="xxxx" が二個以上出てきた場合はそれを調べませんし、たとえば、<img align="top" src="xxxx" などと <img src="xxxx" 以外の書き方をしている時や、ファイル名を引用符号 (") でくくっていないときは使い物になりませんので、それぞれ、ご自分の HTML の書き方のくせに合わせて改造してみてください。
/* imgsize.c */ #include <stdio.h> #define YES 1 #define NO 0 char data[2000], replace[200]; main(int argc, char *argv[]) { FILE *inp, *out; char imgfile[80], inpname[80], outname[80], command[160]; int i, j, start, end; if(argc<2){ printf("Input HTML file."); exit(0); } else strcpy(inpname, argv[1]); strcpy(outname, inpname); sprintf(inpname, "%s.bak", outname); sprintf(command, "mv %s %s", outname, inpname); system(command); if((inp=fopen(inpname, "r"))==NULL){ printf("Can't open <%s>\n", inpname); exit(0); } if((out=fopen(outname, "w"))==NULL){ printf("Can't creat <%s>\n", outname); exit(0); } while(fgets(data,2000,inp)!=NULL){ if((start=search("img src=\""))>=0 && search("width=")<0){ start=start+strlen("img src=\""); for(i=start, j=0; data[i]!='"'; i++, j++) imgfile[j]=data[i]; imgfile[j]='\0'; end=i+1; if(get_size(imgfile)==YES){ for(i=0; i<start; i++) putc(data[i], out); fputs(replace, out); for(i=end; data[i]!='\0'; i++) putc(data[i], out); } else fputs(data, out); } else fputs(data, out); } } search(char *keyword) { int i, j, key; char buf[40]; for(i=0; data[i]!='\n'; i++){ key=YES; for(j=0; keyword[j]!='\0'; j++){ if(toupper(keyword[j])!=toupper(data[i+j])){ key=NO; break; } } if(key==YES) return i; } return -1; } get_size(char *img) { FILE *fp; char buf[180], command[160], width[8], hight[8]; int i, j, chars_read; sprintf(command, "identify %s", img); read_fp = popen(command, "r"); if(read_fp == NULL){ pclose(read_fp); return NO; } else{ chars_read = fread(buf, sizeof(char), 180, fp); if(char_read == 0){ pclose(read_fp); return NO; } for(i=0; ; i++){ if(buf[i]==' ') break; } for(i=i+1, j=0; buf[i]!='x'; i++, j++) width[j]=buf[i]; width[j]='\0'; for(i=i+1, j=0; ; i++, j++){ if(buf[i]==' ' || buf[i]=='+') break; hight[j]=buf[i]; } hight[j]='\0'; sprintf(replace, "%s\" width=\"%s\" hight=\"%s\"", img, width, hight); pclose(read_fp); return YES; } }