質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.19%

BMPファイルを書き込む際にデータが欠損してしまう

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,041

Takayou

score 15

c言語でBMP画像の入出力を実装したいのですがうまくいきません。

具体的には、読み込んだBMPファイルをそのまま出力しようとしたところ、出力したファイルを開くと
「このファイルはサポートしていない形式のようです」
となり、画像が表示されません。

また、入力ファイルのサイズにくらべて出力ファイルのサイズが小さくなってしまっています。
(入力ファイル4144kBに対して、出力ファイル4142KB)

以下にプログラムを示します。
どなたか教えてください!

追記
visual studio2019で動かしています。
また、画像は以下のリンクのものをしようしています。
https://www.google.com/url?sa=i&source=images&cd=&ved=2ahUKEwjG5LHctfLkAhXC62EKHWyLBJ0QjRx6BAgBEAQ&url=http%3A%2F%2Fimagingsolution.blog.fc2.com%2Fblog-entry-180.html&psig=AOvVaw0T4Qw7OXJeYByGbmMmddTJ&ust=1569722386315809

/*
BMPファイルに対して, 以下の処理を行う
・グレースケール変換
・エッジ検出(Prewittオペレータ, Sobelオペレータ)
・拡大,縮小,回転, 移動(線形補間法)
*/


#include<stdio.h>
#include<stdlib.h>

#define IMG_MAX_SIZE 512

typedef struct {
    unsigned char *red;
    unsigned char *blue;
    unsigned char *green;
}ImageData;

typedef struct {
    unsigned char    FileHeader[14];
    unsigned int    Size;
    int                Width, Height;
    unsigned char    InfoHeader[28];
    ImageData img;
}BMP;

//BMPファイル読み込み
void ReadBmp(char FileName[], BMP* bmp);
//画像を書き込む
void WriteBmp(char FileName[], BMP* bmp);

int main() {
    BMP bmp;

    char input_file[] = "lena.bmp";
    char output_file[] = "lenaout.bmp";
    ReadBmp(input_file, &bmp);
    WriteBmp(output_file, &bmp);

    return 0;

    free(bmp.img.red);
    free(bmp.img.green);
    free(bmp.img.blue);
}


//BMPファイル読み込み
void ReadBmp(char FileName[], BMP* bmp)
{
    FILE* fp;

    fopen_s(&fp, FileName, "rb");
    if (fp == NULL) {
        printf("Not Found : %s", FileName);
        exit(1);
    }

    //ヘッダー情報を読み込み
    fread(bmp->FileHeader, sizeof(unsigned char), 14, fp);
    fread(&bmp->Size,       sizeof(int),   1, fp);
    fread(&bmp->Width,     sizeof(int),   1, fp);
    fread(&bmp->Height,    sizeof(int),   1, fp);
    fread(bmp->InfoHeader, sizeof(unsigned char), 28, fp);

    //画像本体の読み込み
    bmp->img.red   = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char));
    bmp->img.blue  = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char));
    bmp->img.green = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char));
    if (bmp->img.red == NULL) {
        printf("メモリ確保に失敗\n");
        exit(1);
    }
    if (bmp->img.green == NULL) {
        printf("メモリ確保に失敗\n");
        exit(1);
    }
    if (bmp->img.blue == NULL) {
        printf("メモリ確保に失敗\n");
        exit(1);
    }

    for (int h = 0; h < bmp->Height; h++) {
        for (int w = 0; w < bmp->Width; w++) {
            fread(&bmp->img.red   [w + h * bmp->Width], sizeof(unsigned char), 1, fp);
            fread(&bmp->img.green [w + h * bmp->Width], sizeof(unsigned char), 1, fp);
            fread(&bmp->img.blue  [w + h * bmp->Width], sizeof(unsigned char), 1, fp);
        }
    }

    //読みこんだファイルを閉じる
    fclose(fp);
}

//画像を書き込む
void WriteBmp(char FileName[], BMP* bmp)
{
    FILE* fp;
    fopen_s(&fp, FileName, "wb");
    if (fp == NULL) {
        printf("Not Found : %s\n", FileName);
        exit(1);
    }

    fwrite(bmp->FileHeader,  sizeof(unsigned char), 14, fp);
    fwrite(&bmp->Size,       sizeof(int),   1, fp);
    fwrite(&bmp->Width,         sizeof(int),   1, fp);
    fwrite(&bmp->Height,     sizeof(int),   1, fp);
    fwrite(bmp->InfoHeader,  sizeof(unsigned char), 28, fp);


    printf("%s\n", bmp->FileHeader);
    printf("%d %d %d\n", bmp->Size, bmp->Width, bmp->Height);
    printf("%s\n", bmp->InfoHeader);


    //画像本体の読み込み
    for (int h = 0; h < bmp->Height; h++) {
        for (int w = 0; w < bmp->Width; w++) {
            fwrite(&bmp->img.red  [w + h * bmp->Width], sizeof(unsigned char), 1, fp);
            fwrite(&bmp->img.green[w + h * bmp->Width], sizeof(unsigned char), 1, fp);
            fwrite(&bmp->img.blue [w + h * bmp->Width], sizeof(unsigned char), 1, fp);
        }
    }

    fclose(fp);
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Zuishin

    2019/09/28 11:09

    BMP ではないようですが。

    キャンセル

  • dodox86

    2019/09/28 11:21

    >Zuishinさん
    本当だ、PNGファイルですね。

    >Takayouさん
    画像の見た目のお話ではありません。もし本当にここからレナさん画像PNGファイルをダウンロードしたのであれば、ファイルのフォーマットが違うので、絶対に扱えません。それとも、これからBMPファイルに手動で変換したのでしょうか。

    キャンセル

  • Takayou

    2019/09/28 12:35

    ここから手動でBMPファイルに変換してしまいました。

    キャンセル

回答 2

checkベストアンサー

+1

入力ファイルのサイズにくらべて出力ファイルのサイズが小さくなってしまっています。

1ラインごとに4の倍数バイトになるよう、末尾に0パディングする必要があります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/09/28 12:39

    上手くいきました!ありがとうございます!

    読み出し側でも0埋めをして読むとのはなぜなのでしょうか?

    キャンセル

  • 2019/09/28 12:45

    画像幅が4の倍数ドットでない場合、1ラインごとに4の倍数バイトになるよう0パディングされているので、
    1ライン読むごとにその末尾の0を読み飛ばしてやらないと、次のラインの先頭画素として0が読まれてしまいます。

    キャンセル

  • 2019/09/28 12:53

    なるほど、わかりました。
    丁寧に教えてくださりありがとうございます。

    キャンセル

0

とりあえず、バイナリエディタなどを使って、書き出したファイルのヘッダ情報だけでも同一になっているかを確認してみたらどうでしょうか。

「BMP ファイルフォーマット」でぐぐればBMPの詳細が出てきますが、これは読んでますか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.19%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る