このページの説明には一部誤りが有ることが分かっています。
PNM(PPM/PGM/PBM)形式について、改めて書き直しています。以下を参照ください。
画像ファイルの扱い方 (3) -PPM/PGM/PBM形式 (2)
PPM/PGM/PBM形式入力関数
とりあえず作ってみました。動的メモリ確保なんてやるとメモリリークが怖いけど、メモリリーク起こってないよね?
なにかミスor変なところに気が付かれたかたはご連絡お願いします。
まあ、コードの中で無駄なこととか一杯してます。
fread() つかえよ、とか、ポインタの使い方おかしいぞ、とか、
これじゃ効率悪いだろ、とか、いろいろ言ってきてください。
本来、こういうところで示すソースコードってエラー対策とかは極力控えて、
どう読み込むかだけを示すようにしなくちゃいけないような・・・
(ソースの処理からファイルフォーマットを理解してもらうのが目的だからな~~)
注意:この関数では Picture 構造体及び内部のrgbについてそれぞれ動的メモリ確保をしています。
そのため、使用後には必ず free() もしくは、この中にある deletePicture でメモリを解放してください。
※ Rayさんからご指摘がいくつかありました。(毎度ありがとうございます)
一つは、ヘッダ読み込みバッファは char [256] つまり255文字分用意してありますが、
もしコメントが255文字以上あった場合うまく動かないというものです。
まあ一般に一行255文字以上も使ったりしないでしょうが、可能性としてはあります。
この対策としては、 gets() を使わず、読み飛ばし用に関数を自作するのも手です。
まあどこまでエラー対策をするか、という問題ですのでそこは皆様の判断にお任せします。
(別にめんどくさくなったわけではない(笑))
もう一つはこいつは内部で動的にメモリを確保しているので、
プログラムの終了までにr,g,bそして場合によっては
Picuture 構造体を free() で解放しないといけないという注意書きを書くのを忘れていました。
※2 2002/7/16 ソースコードを変更しました。 メモリリークなどの心配は少なくなったと思います。
#include <stdio.h>
/* 構造体メモリ確保&初期化関数 */
Picture* newPicture(){
Picture *pPic;
pPic = (Picture*)malloc(sizeof(Picture));
if(pPic == NULL){
return NULL; /* メモリ確保できない */
}
pPic->x = 0;
pPic->y = 0;
pPic->r = NULL;
pPic->g = NULL;
pPic->b = NULL;
pPic->a = NULL;
return pPic;
}
/* 構造体メモリ解放関数 */
void deletePicture(Picture *pPic){
free(pPic->r);
free(pPic->g);
free(pPic->b);
free(pPic->a);
free(pPic);
pPic = NULL;
}
/* ppmファイル取得関数(α値には手を加えない) */
/* ファイルポインタを引数に与えて読み出す。 */
/* 画像データ構造体は内部でメモリを確保し、 */
/* 戻り値としてそのポインタを返す。 */
/* 読み込みに失敗したらNULLを返す。 */
Picture* getPpm(FILE* fp)
{
int i,j,k; /* ループ用変数 */
char ss[256]; /* ヘッダ読み込み時のバッファ */
int type; /* ファイル形式 */
int max; /* 最大輝度 */
int x,y; /* x,yのサイズ */
int tmp; /* 作業用変数 */
double ratio; /* 最大輝度の255に対する比 */
unsigned char *r,*g,*b; /* 読み込み時作業用ポインタ */
Picture *pPic; /* 戻り値用ポインタ */
if(fp ==NULL) /* 読み込み失敗 */
return NULL;
/* -------------------- ヘッダ取得 ここから -------------------- */
fgets(ss,255,fp);
if(ss[0]!='P')
return NULL; /* ファイル形式が違う */
sscanf(ss,"P%d",&type);
if(type < 1 || type > 6)
return NULL; /* ファイル形式が違う */
do fgets(ss,255,fp); while(ss[0]=='#'); /* コメント読み飛ばし */
sscanf(ss,"%d%d",&x,&y);
if(x < 1 || y < 1)
return NULL; /* サイズが異常 */
if(type == 2 || type == 3 || type == 5 || type == 6){
do fgets(ss,255,fp); while(ss[0]=='#'); /* コメント読み飛ばし */
sscanf(ss,"%d",&max);
if(max < 1 || max > 255)
return NULL; /* 最大輝度が範囲外 */
ratio = 255 / (float)max;
}
/* -------------------- ヘッダ取得 ここまで -------------------- */
/* 構造体メモリ確保 */
pPic = newPicture();
if(pPic == NULL){
return NULL; /* メモリ確保できない */
}
pPic->x = x;
pPic->y = y;
/* 画像データ読み込みのためのメモリ確保 */
pPic->r = r = (unsigned char*)malloc(sizeof(unsigned char) * x * y);
pPic->g = g = (unsigned char*)malloc(sizeof(unsigned char) * x * y);
pPic->b = b = (unsigned char*)malloc(sizeof(unsigned char) * x * y);
if(r == NULL || b == NULL || g == NULL){
deletePicture(pPic);
return NULL; /* メモリ確保できない */
}
/* -------------------- 画像データ取得 -------------------- */
switch(type){
case 1: /* 2値ascii形式 */
for(i=0 ; i<y ; i++){
for(j=0 ; j<x ; j++){
if(fscanf(fp,"%d",&tmp) != 1){
deletePicture(pPic);
return NULL;
}
*(r++) = *(g++) = *(b++) = (unsigned char)((1-tmp) * 255);
}
}
break;
case 2: /* グレースケールascii形式 */
for(i=0 ; i<y ; i++){
for(j=0 ; j<x ; j++){
if(fscanf(fp,"%d",&tmp) != 1){
deletePicture(pPic);
return NULL;
}
*(r++) = *(g++) = *(b++) = (unsigned char)(tmp * ratio);
}
}
break;
case 3: /* フルカラーascii形式 */
for(i=0 ; i<y ; i++){
for(j=0 ; j<x ; j++){
if(fscanf(fp,"%d",&tmp) != 1){
deletePicture(pPic);
return NULL;
}
*(r++) = (unsigned char)(tmp * ratio);
if(fscanf(fp,"%d",&tmp) != 1){
deletePicture(pPic);
return NULL;
}
*(g++) = (unsigned char)(tmp * ratio);
if(fscanf(fp,"%d",&tmp) != 1){
deletePicture(pPic);
return NULL;
}
*(b++) = (unsigned char)(tmp * ratio);
}
}
break;
case 4: /* 2値raw形式 */
for(i=0 ; i<y ; i++){
for(j=0 ; j<(x-1)/8 ; j++){
if((tmp = getc(fp)) == EOF){
deletePicture(pPic);
return NULL;
}
for(k = 7;k >= 0;k--){
*(r++) = *(g++) = *(b++) = (unsigned char)((1-((tmp>>k)%2))*255);
}
}
if((tmp = getc(fp)) == EOF){
deletePicture(pPic);
return NULL;
}
for(k=7 ; k>=7-(x-1)%8 ; k--){
*(r++) = *(g++) = *(b++) = (unsigned char)((1-((tmp>>k)%2))*255);
}
}
break;
case 5: /* グレースケールraw形式 */
for(i=0 ; i<y ; i++){
for(j=0 ; j<x ; j++){
if((tmp = getc(fp)) == EOF){
deletePicture(pPic);
return NULL;
}
*(r++) = *(g++) = *(b++) = (unsigned char)(tmp * ratio);
}
}
break;
case 6: /* フルカラーraw形式 */
for(i=0 ; i<y ; i++){
for(j=0 ; j<x ; j++){
if((tmp = getc(fp)) == EOF){
deletePicture(pPic);
return NULL;
}
*(r++) = (unsigned char)(tmp * ratio);
if((tmp = getc(fp)) == EOF){
deletePicture(pPic);
return NULL;
}
*(g++) = (unsigned char)(tmp * ratio);
if((tmp = getc(fp)) == EOF){
deletePicture(pPic);
return NULL;
}
*(b++) = (unsigned char)(tmp * ratio);
}
}
break;
}
return pPic; /* 読み込み作業完了! */
}