ファイル処理(画像ファイルの編集)

(ブログ記事の一覧は「こちら」)

C言語での画像ファイルの読み込み・書き込みの処理について確認していきましょう。 (画像ファイルのような、バイトデータの集まりのファイルをバイナリファイルと呼びます)

【復習】 ファイルのオープン/クローズの定義は以下のようになります。

ファイル名(filename)で示されるファイルを、指定モード(mode)でオープン

FILE *fopen(const char *filename, const char *mode);

fopen でオープンされたファイルをクローズ

int fclose(FILE *fp);

「FILE *」は、ファイルポインタというファイルを扱うときの型であるFILE型のポインタです。

以下も復習です。

テキストファイルの読み込み

 fp = fopen("test_r.txt", "r");

テキストファイルの書き込み

 fp = fopen("test_w.txt", "w");

以下が、今回で扱う書き方になります。

バイナリ・ファイルの読み込み

 fp = fopen("input.bmp", "rb");

バイナリ・ファイルの書き込み

 fp = fopen("output.bmp", "wb");

Bitmap(ビットマップ)ファイルのフォーマット

Bitmap(ビットマップ)ファイルは、圧縮されていない画像ファイルのことです。 まず、Bitmapファイルを用意します。(「bmp sample」で検索すると見つかります。)

次に、用意したBitmapファイルのフォーマットを確認します。

バイナリファイルのデータを確認するには、「Stirling」というツールを使用すると便利です。 StirlingでBitmapファイルを開くと、16進数の値が16列ずつに並んだ表示が得られます。 バイナリファイルはそれらの値が意味を持っています。

f:id:MJeeeey:20200108020326j:plain:w512

赤い枠で囲った部分が、Bitmapファイルの画像ファイルの幅と高さになります。
(Bitmapファイルのフォーマットについては、「bmp フォーマット」などで検索すると情報が見つかります。)

読み取った順に処理すると、「00 00 01 00」となります。これは10進数で「256」です。 つまり、上の例での、画像ファイルの幅と高さは「256 * 256」です。

Bitmap(ビットマップ)ファイルの読み込みのサンプル

Bitmap(ビットマップ)ファイルのデータを読み込むサンプルです。あらかじめ、プロジェクトフォルダに「input.bmp」をコピーして、以下のプログラムを実行してください。

#include <stdio.h>

int main(void)
{
    unsigned char BitMapFileHeader[14]; // BMPのファイルヘッダー
    unsigned int biSize; // 情報ヘッダーのサイズ
    int biWidth; // BMPの幅
    int biHeight; // BMPの高さ
    unsigned char BitMapInfoHeader[28]; // 他のBMPの情報ヘッダー

    unsigned char cData[512][512][3]; //画素情報(幅、高さ、RGB)

    int i, j, k; 
    FILE *fp; 

    fp = fopen("input.bmp", "rb");

    fread(&BitMapFileHeader, sizeof(char), 14, fp); 
    fread(&biSize, sizeof(int), 1, fp);
    fread(&biWidth, sizeof(int), 1, fp);
    fread(&biHeight, sizeof(int), 1, fp); 
    fread(&BitMapInfoHeader, sizeof(char), 28, fp); 

    for (i = 0; i < biWidth; i++) {
        for (j = 0; j < biHeight; j++) {
            for (k = 0; k < 3; k++) {
                fread(&cData[i][j][k], sizeof(char), 1, fp);         }
        }
    }

    fclose(fp);

    return 0;
}

以下は、Bitmapファイル「input.bmp」を読み込み、「out.bmp」を書き出すサンプルです。

#include <stdio.h>

int main(void)
{
    unsigned char BitMapFileHeader[14]; // BMPのファイルヘッダー
    unsigned int biSize; // 情報ヘッダーのサイズ
    int biWidth; // BMPの幅
    int biHeight; // BMPの高さ
    unsigned char BitMapInfoHeader[28]; // 他のBMPの情報ヘッダー

    unsigned char cData[512][512][3]; //画素情報(幅、高さ、RGB)

    int i, j, k; 
    FILE *fp1;
    FILE *fp2;

    // BMPファイルの読み込み
    fp1 = fopen("lena_color_256.bmp", "rb");

    fread(&BitMapFileHeader, sizeof(char), 14, fp1);
    fread(&biSize, sizeof(int), 1, fp1);
    fread(&biWidth, sizeof(int), 1, fp1);
    fread(&biHeight, sizeof(int), 1, fp1);
    fread(&BitMapInfoHeader, sizeof(char), 28, fp1);

    for (i = 0; i < biWidth; i++) {
        for (j = 0; j < biHeight; j++) {
            for (k = 0; k < 3; k++) {
                fread(&cData[i][j][k], sizeof(char), 1, fp1);
            }
        }
    }

    fclose(fp1);

    // BMPファイルの書き込み
    fp2 = fopen("out.bmp", "wb");

    fwrite(&BitMapFileHeader, sizeof(char), 14, fp2);
    fwrite(&biSize, sizeof(int), 1, fp2);
    fwrite(&biWidth, sizeof(int), 1, fp2);
    fwrite(&biHeight, sizeof(int), 1, fp2);
    fwrite(&BitMapInfoHeader, sizeof(char), 28, fp2);

    for (i = 0; i < biWidth; i++) {
        for (j = 0; j < biHeight; j++) {
            for (k = 0; k < 3; k++) {
                fwrite(&cData[i][j][k], sizeof(char), 1, fp2);
            }
        }
    }

    fclose(fp2);

    return 0;
}