PNM形式---コンピュータに画像データを読み込むためのプログラミング(C言語の関数)

概要

サンプルソース

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


Back / Studying / Top