#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*PNM画像のヘッダ*/
struct pnmheader
{
int id; /*identifier... PNM画像の先頭文字*/
int type; /*PNM画像の種別*/
char comment[256]; /*コメント*/
int col_size; /*horizontal-縦方向のサイズ*/
int row_size; /*vertical-横方向のサイズ*/
int qmax; /*量子化レベルの最大*/
};
/*外部関数の取り込み*/
extrn double round(double f, int dec); /*四捨五入(10のdec乗の位より下位を処理)...リンク先の「C言語による丸め」を参照のこと*/
/*PnM画像からヘッダ情報を取得*/
struct pnmheader getpnmheader(char* imgfile, struct pnmheader dstinfo)
{
char tmpc; /* 作業用変数 */
char tmps[256]; /* 作業用変数 */
struct pnmheader cimghead;
FILE *fdat;
cimghead = dstinfo; /*構造体情報を丸写し*/
//ファイルオープン
fdat = fopen(imgfile, "rb");
/* -------------------- ヘッダ取得 ここから -------------------- */
/*先頭文字取得*/
cimghead.id = fgetc(fdat);
if(cimghead.id != 'P') /* ファイル形式が違う */
{
fprintf(stderr, "Error: PNM画像ではありません。\n");
fclose(fdat); /*ファイルクローズ*/
cimghead.id = -1; /*返り先のエラー処理のため*/
return(cimghead);
}
/*種別*/
fgets(tmps, 2, fdat);
cimghead.type = atoi(tmps);
if(cimghead.type < 1 || cimghead.type > 6) /* ファイル形式が違う */
{
fprintf(stderr, "Error: PNM画像に該当しないタイプです。\n");
fclose(fdat); /*ファイルクローズ*/
cimghead.id = -1; /*返り先のエラー処理のため*/
return(cimghead);
}
tmpc = ' ';
/*コメント取得*/
while(tmpc != '#') tmpc = fgetc(fdat); /*コメント開始文字を無視する*/
fgets(cimghead.comment, 256, fdat); /*コメントを改行文字が現れるまで、または256文字まで取得する*/
/*画像の横縦サイズ(pixels)*/
fgets(tmps, 256, fdat);
sscanf(tmps, "%d %d", &cimghead.col_size, &cimghead.row_size);
if(cimghead.col_size < 1 || cimghead.row_size < 1) /* サイズが異常 */
{
fprintf(stderr, "Error: 横または縦のサイズが異常です。\n");
fclose(fdat); /*ファイルクローズ*/
cimghead.id = -1; /*返り先のエラー処理のため*/
return(cimghead);
}
/* 量子化レベルの最大値の取得 */
if(cimghead.type % 3 != 1) /*2値画像以外の場合*/
{
fgets(tmps, 255, fdat);
sscanf(tmps,"%d",&cimghead.qmax);
if(cimghead.qmax < 1 || cimghead.qmax > 255)
{
fprintf(stderr, "Error: 量子化レベルの最大値が異常です。");
fclose(fdat); /*ファイルクローズ*/
cimghead.id = -1; /*返り先のエラー処理のため*/
return(cimghead);
}
}
/* -------------------- ヘッダ取得 ここまで -------------------- */
fclose(fdat); /*ファイルクローズ*/
return(cimghead); /* 構造体データを返す */
}
/*******************************************/
/*指定したPNM画像の情報を取得し、 */
/*画素値情報をメモリ上に展開する */
/* */
/* ■imgfile...PnM画像ファイル名 */
/* */
/* ■color...カラー画像の場合に返値とするデータの色*/
/* 0... (予約) */
/* 1... 赤 */
/* 2... 緑 */
/* 3... 青 */
/*******************************************/
unsigned char* readpnm(char *imgfile, int color)
{
unsigned char *picdat; /*画素値の配列*/
char tmpcarr[256]; /*ヘッダを読み飛ばす時の格納用*/
int tmp; /*画素値取得作業用*/
int row, col, k; /*カウンタ…row: 横方向の座標値、 col: 縦方向の座標値、 k: 汎用カウンタ*/
int r, g, b; /*カラー画像における R,G,B の値*/
double ratio; /*ファイル上の画素値からメモリ上の画素値に変換するための係数*/
FILE *fpnm, *finfo; /*画像ファイルと、ヘッダ情報用テキストファイル*/
struct pnmheader headerinfo;
/*構造体の初期値... 関数の返り値として、構造体ポインタを受取る場合は、何か値を与えておく*/
headerinfo.id = 0;
headerinfo.type = 0;
/* headerinfo.comment; */
headerinfo.col_size = 0;
headerinfo.row_size = 0;
headerinfo.qmax = 0;
headerinfo = getpnmheader(imgfile, headerinfo); /* ヘッダ取得 */
/* 注意!… この関数↑で一度ファイルを開閉しているため、もう一度オープンしてヘッダを読み飛ばすこと。*/
if(headerinfo.id == -1) return "Error"; /*getpnmheader関数の返値から、正常なPnM画像かどうかを判断する*/
ratio = 255 / (double)headerinfo.qmax;
fpnm = fopen(imgfile, "rb"); /*ファイルオープン*/
/*ヘッダの読み飛ばし*/
fgets(tmpcarr, 256, fpnm); /*画像タイプの読み飛ばし*/
fgets(tmpcarr, 256, fpnm); /*コメントの読み飛ばし*/
fgets(tmpcarr, 256, fpnm); /*画像サイズの読み飛ばし*/
fgets(tmpcarr, 256, fpnm); /*最大輝度の読み飛ばし*/
/*ヘッダのx-y sizeから、メモリ領域の大きさを決定する*/
picdat = (unsigned char*)malloc(sizeof(unsigned char) * headerinfo.col_size * headerinfo.row_size);
if(picdat == NULL) /*メモリ確保できない場合*/
{
fprintf(stderr, "メモリ領域確保に失敗しました。\n");
free(picdat);
return "Error";
}
switch(headerinfo.type)
{
case 1: /* 2値ascii形式 */
for(row = 0 ; row < headerinfo.row_size ; row++)
{
for(col = 0 ; col < headerinfo.col_size ; col++)
{
if(fscanf(fpnm,"%d",&tmp) != 1)
{
free(picdat);
return "Error";
}
picdat[row * headerinfo.col_size + col] = (unsigned char)((1 - tmp) * 255);
}
}
break;
case 2: /* グレースケールascii形式 */
for(row = 0 ; row < headerinfo.row_size ; row++)
{
for(col = 0 ; col < headerinfo.col_size ; col++)
{
if(fscanf(fpnm,"%d",&tmp) != 1)
{
free(picdat);
return "Error";
}
picdat[row * headerinfo.col_size + col] = (unsigned char)(tmp * ratio);
}
}
break;
case 3: /* フルカラーascii形式 */
for(row = 0 ; row < headerinfo.row_size ; row++)
{
for(col = 0 ; col < headerinfo.col_size ; col++)
{
if(fscanf(fpnm,"%d",&r) != 1)
{
free(picdat);
return "Error";
}
if(fscanf(fpnm,"%d",&g) != 1)
{
free(picdat);
return "Error";
}
if(fscanf(fpnm,"%d",&b) != 1)
{
free(picdat);
return "Error";
}
if(color == 1)
picdat[row * headerinfo.col_size + col] = (unsigned char)(r * ratio); /*Rを読込む*/
if(color == 2)
picdat[row * headerinfo.col_size + col] = (unsigned char)(g * ratio); /*Gを読込む*/
if(color == 3)
picdat[row * headerinfo.col_size + col] = (unsigned char)(b * ratio); /*Bを読込む*/
}
}
break;
case 4: /* 2値raw形式 */
for(row = 0 ; row < headerinfo.row_size ; row++)
{
for(col = 0 ; col < (headerinfo.col_size - 1) / 8 ; col++)
{
if((tmp = fgetc(fpnm)) == EOF)
{
free(picdat);
return "Error";
}
for(k = 7; k >= 0; k--)
{
picdat[row * headerinfo.col_size + col] = (unsigned char)((1 - ((tmp >> k) % 2)) * 255);
}
}
}
break;
case 5: /* グレースケールraw形式 */
for(row = 0 ; row < headerinfo.row_size ; row++)
{
for(col = 0 ; col < headerinfo.col_size ; col++)
{
if((tmp = fgetc(fpnm)) == EOF)
{
free(picdat);
return "Error";
}
picdat[row * headerinfo.col_size + col] = (unsigned char)(tmp * ratio);
}
}
break;
case 6: /* フルカラーraw形式 */
for(row = 0 ; row < headerinfo.row_size ; row++)
{
for(col = 0 ; col < headerinfo.col_size ; col++)
{
if((r = fgetc(fpnm)) == EOF)
{
free(picdat);
return "Error";
}
if((g = fgetc(fpnm)) == EOF)
{
free(picdat);
return "Error";
}
if((b = fgetc(fpnm)) == EOF)
{
free(picdat);
return "Error";
}
if(color == 1)
picdat[row * headerinfo.col_size + col] = (unsigned char)(r * ratio); /*Rを読込む*/
if(color == 2)
picdat[row * headerinfo.col_size + col] = (unsigned char)(g * ratio); /*Gを読込む*/
if(color == 3)
picdat[row * headerinfo.col_size + col] = (unsigned char)(b * ratio); /*Bを読込む*/
}
}
break;
}
fclose(fpnm); /* ファイルクローズ */
return(picdat);
}
|
2008/07/19: 作成