downsize.c

Image Magic の convert -geometry コマンドを使うと、さまざまなフォーマットの画像を好きな大きさに、しかも綺麗に変えることができます。ただし、画像の大きさは自分で指定しなければなりません。いちいち、identify プログラムで元の画像の大きさを読み取り、計算するのは面倒なので、私は、それをパーセンテージを入れることによって、縦横の比率を保ちながら縮小するプログラムをつくりました。小さな画像を大きくすると、綺麗ではないので、拡大機能は滅多に使いませんので、縮小専用のプログラムを作りました。

パーセンテージを入れるプログラムを作ってから、縦のピクセルを指定してそれに合わせて横のピクセルを合わせたり、横のピクセルを指定して縦のピクセルを指定するのも便利なので、横のピクセルを指定する場合は w200、縦のピクセルを指定する場合は h60 などと、パーセンテージの指定のかわりにピクセルでの指定も出来るように改造しました。

まずは、出力ファイルですが、これは、次のように、元のファイル名に _s を付け加えるようにしました。

get_outname(char *filename)
{
int i, j;

for(i=0, j=0; filename[i]!='.'; i++, j++)
    outname[j]=filename[i];
outname[j++]='_';
outname[j++]='s';
for(; filename[i]!='\0'; i++, j++)
    outname[j]=filename[i];
outname[j]='\0';
printf("<%s>\n", outname);
exit(0);
}

もともとの画像ファイルの大きさを読むには次のファンクションを使いました。identify の出力を popen と fread を使って読みとり、バッファを解析して、org_width と org_height を得ています。

get_size(char *imgfile)
{
FILE *read_fp;
char buf[180], command[160], width[8], height[8];
int i, j, chars_read;

sprintf(command, "identify %s", imgfile);
read_fp = popen(command, "r");
if(read_fp == NULL){
    pclose(read_fp);
    return NO;
    }
else{
    chars_read = fread(buf, sizeof(char), 180, read_fp);
    if (chars_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';
    org_width=atoi(width);
    for(i=i+1, j=0; ; i++, j++){
        if(buf[i]==' ' || buf[i]=='+')
            break;
        height[j]=buf[i];
        }
    height[j]='\0';
    org_height=atoi(height);
    pclose(read_fp);
    return YES;
    }
}

新しい横のピクセル、縦のピクセルは次の式で得ることができます。

new_width=((org_width /10) * ratio) / 10;
new_height=((org_height / 10) * ratio) / 10;
元の画像を新しい縦横比に縮小するには次のコマンドでできますので、

convert -geometry (new_width)x(new_height), inpname, outname
次のようにコマンドをシステムに渡し、実行させます。
sprintf(command, "convert -geometry %dx%d %s %s", new_width, new_height, inpname, outname);
system(command);

縦横のどちらかをピクセルで指定した場合のために、次の部分を書きました。

if(key=='w'){
    new_width=inp_width;
    ratio=(inp_width * 100) / org_width;
    }
if(key!='h')
    new_height=((org_height / 10) * ratio) / 10;
if(key=='h'){
    new_height=inp_height;
    ratio=(inp_height * 100) / org_height;
    }
if(key!='w')
    new_width=((org_width /10) * ratio) / 10;
以下は、上記を組み合わせた downsize.c の全体です。エラーの時の処理が甘いと思いますが、自分で使う分にはこの程度でいいかなと、手を抜いています。エラーが出るたびに書き直していけばいいと、暢気にかまえています。

/*

downsize.c

*/

#include <stdio.h>

#define YES 1
#define NO  0

char outname[80];
int org_width, org_height;

main(int argc, char *argv[])
{
FILE *inp, *out;
char buf[8], imgfile[80], inpname[80], command[160];
int i, j, key, start, end, ratio, inp_width, inp_height, new_width, new_height;

if(argc<3){
    printf("Input [w/h][ratio] [image file]\n");
    exit(0);
    }
key=argv[1][0];
if(key>='0' && key<='9')
    ratio=atoi(argv[1]);
else if(key=='w' || key=='h'){
    for(i=1, j=0; argv[1][i]!='\0'; i++, j++)
        buf[j]=argv[1][i];
    buf[j]='\0';
    inp_width=atoi(buf);
    inp_height=atoi(buf);
    }
else{
    printf("Wrong ratio.\n");
    exit(0);
    }
strcpy(inpname, argv[2]);
get_outname(inpname);

if(get_size(inpname)==YES){
    if(key=='w'){
        new_width=inp_width;
        ratio=(inp_width * 100) / org_width;
        }
    if(key!='h')
        new_height=((org_height / 10) * ratio) / 10;
    if(key=='h'){
        new_height=inp_height;
        ratio=(inp_height * 100) / org_height;
        }
    if(key!='w')
        new_width=((org_width /10) * ratio) / 10;
    sprintf(command, "convert -geometry %dx%d %s %s", new_width, new_height, inpname, outname);
    system(command);
    printf("%s %dx%d --> %dx%d %s\n", inpname, org_width, org_height, new_width, new_height, outname);
    }
else
    printf("Cannot identify image size of %s\n", inpname);
}

get_size(char *imgfile)
{
FILE *read_fp;
char buf[180], command[160], width[8], height[8];
int i, j, chars_read;

sprintf(command, "identify %s", imgfile);
read_fp = popen(command, "r");
if(read_fp == NULL){
    pclose(read_fp);
    return NO;
    }
else{
    chars_read = fread(buf, sizeof(char), 180, read_fp);
    if (chars_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';
    org_width=atoi(width);
    for(i=i+1, j=0; ; i++, j++){
        if(buf[i]==' ' || buf[i]=='+')
            break;
        height[j]=buf[i];
        }
    height[j]='\0';
    org_height=atoi(height);
    pclose(read_fp);
    return YES;
    }
}

get_outname(char *filename)
{
int i, j;

for(i=0, j=0; filename[i]!='.'; i++, j++)
    outname[j]=filename[i];
outname[j++]='_';
outname[j++]='s';
for(; filename[i]!='\0'; i++, j++)
    outname[j]=filename[i];
outname[j]='\0';
}

[目次にもどる]