#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: 作成