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

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

ただいまの
回答率

89.69%

C言語でのBMP出力時にデータ末尾が欠損してしまう

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 348

suikoku

score 1

C言語でBMPファイルの入力・出力を行うプログラムを作成しています.
具体的には入力されたBMPファイルをそのまま別名のBMPファイルとして出力するプログラムを作成しているのですが,
ファイルの一部分が欠損して出力されてしまいます.(なので,ペイント等を使用して出力されたファイルを開くことができません.) 
バイナリエディタを使用して入出力ファイルを比較したところ,どうやら画素データの末尾から数十バイトが出力されていないようでした.
ヘッダや欠損した末尾以外の部分はきちんと出力されていました.
データが最後までfwrite()で出力できていないのではと思いfputs()によりエラーを出力するようにしましたが,エラー出力もされません.
ソースコードを記載しますので,ご意見を頂ければと思います.

該当のソースコード

#include<stdio.h>
#include<stdlib.h>
#define NAME 20    //ファイル名の長さ

int main() {
    char infile[NAME], outfile[NAME];
    FILE *infp, *outfp;
    unsigned char header[54];
    unsigned char **data;
    int width, height;
    int pixWidth;
    int i;

    //BMPファイル読み込み
    printf("input file name:");
    scanf("%s", infile);

    infp = fopen(infile, "rb");
    if (infp == NULL) {
        printf("ファイルの読み込みに失敗しました\n");
        return -1;
    }

    //ヘッダ読み込み
    fread(header, sizeof(unsigned char), 54, infp);

    width = header[18] + header[19] * 256 + header[20] * 256 * 256 + header[21] * 256 * 256 * 256;
    height = header[22] + header[23] * 256 + header[24] * 256 * 256 + header[25] * 256 * 256 * 256;
    //1行は1pixelにつき3byteかつ4byteの倍数
    pixWidth = width * 3 + width % 4;

    //画素データ読み込み
    data = (unsigned char**)malloc(sizeof(unsigned char*) * height);
    for (i = 0; i < height; i++) {
        data[i] = (unsigned char*)malloc(sizeof(unsigned char) * pixWidth);
    }

    for (i = 0; i < height; i++) {
        fread(data[i], sizeof(unsigned char), pixWidth, infp);
    }

    fclose(infp);

    //BMPファイル書き出し
    printf("output file name:");
    scanf("%s", outfile);

    outfp = fopen(outfile, "wb");
    if (outfp == NULL) {
        printf("ファイルの読み込みに失敗しました\n");
        return -1;
    }

    //ヘッダ書き出し
    fwrite(header, sizeof(unsigned char), 54, outfp);

    //画素データ書き出し
    for (i = 0; i < height; i++) {
        if (fwrite(data[i], sizeof(unsigned char), pixWidth, outfp) < pixWidth) {
            fputs("書き出しに失敗しました\n", stderr);
        }

    }

    fclose(outfp);

    for (i = 0; i < height; i++) {
        free(data[i]);
    }
    free(data);
    return 0;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • suikoku

    2019/10/04 15:38

    どうやらGimpでの入力ファイル作成時にパレット情報が書き込まれていたようです.
    改めてパレット情報を出力しないように設定したところ無事入出力を行うことができました.
    ベストアンサーはこれに気づくきっかけとなったdodox86様の回答とさせていただきます.
    皆さまご助力いただきありがとうございました.

    キャンセル

  • Bull

    2019/10/04 15:52

    ヘッダのサイズが 108byte なら PBITMAPV4HEADER ですね。
    https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapv4header

    キャンセル

  • Bull

    2019/10/04 15:58

    ファイルヘッダーに bfOffBits(ファイル先頭から画像データまでのオフセット)と言う項目があります。
    これが事実上(ファイルヘッダー・情報ヘッダー・パレットデータを合わせた)ヘッダーサイズになります。

    キャンセル

回答 3

checkベストアンサー

0

ビットマップファイルは色数やパレット、圧縮の有無でフォーマットが変わるので、ヘッダーの情報を確認しましょう。ビットマップファイルのヘッダーは何段か連なっていて各種のサイズのデータも含まれます。
ヘッダー、画像データ、ファイルの各部分のサイズの認識が正しいか確認しましょう。読むべきデータをスキップしてしたりしているかもしれません。

BITMAPFILEHEADER ファイルのヘッダー
BITMAPINFOHEADER  情報ヘッダー
RGBQUAD パレットデータ - 最近ではまず見ない、存在しない。

詳細は「Bitmapファイル フォーマット」などで検索してみてください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/04 15:11

    入力ファイルの情報ヘッダのサイズを確認したところ108byteとなっていました.
    情報ヘッダのサイズは40byteで固定だと考えていたのですが,40byteにならない場合があるのでしょうか?
    またこのような場合,何のデータが抜けていると考えられるのでしょうか.
    バイナリエディタ上ではヘッダは過不足なく入力できているように見えるのですが….
    ちなみに入力ファイルはGimpを使って適当に作成したものを使用しています.

    キャンセル

  • 2019/10/04 15:23 編集

    Gimpですか。Bitmapファイルの仕様として、ヘッダーのサイズは固定と言うことは無いです。多くの場合でそうというだけで。Bitmapファイル自体歴史があるのと、gimpのソフト自体が色々できるのが相まって、gimpでの保存時にBitmapファイルのフォーマットを駆使して複雑なことをやってくれちゃうことがあります。パレット情報、RGQUADが連なっているかもしれません。例えば、以下のサイトなど、読み易くて参考になるかと思います。(なんと2002年の記事です) 感謝しつつ、ご案内します。
    http://www.umekkii.jp/data/computer/file_format/bitmap.cgi

    キャンセル

  • 2019/10/04 15:37

    また、例えば最初の14バイトのBITMAPFILEHEADERですが、最後のメンバー「bfOffBits」の意味は「ファイル先頭から画像データまでのオフセット」なので、解釈としては極端な話、ファイル先頭から実際の画像データ先頭まで何バイトもダミーデータが入っていても、不正とは言えないかもしれません。
    https://msdn.microsoft.com/ja-jp/windows/dd183374(v=vs.80)

    キャンセル

  • 2019/10/04 15:39

    どうやらGimpでの入力ファイル作成時にパレット情報が書き込まれていたようです.
    改めてパレット情報を出力しないように設定したところ無事入出力を行うことができました.
    ご助力いただきありがとうございました.

    キャンセル

0

header[28] の値は 24(0x18) ですか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/04 15:04

    はい,24になっていました.
    入力したファイルのビットの深さも24bitで一致していました.

    キャンセル

-2

ツッコミどころはいろいろありますが、気のついたところを

      data[i] = (unsigned char*)malloc(sizeof(unsigned char) * pixWidth);

1ラインは4の倍数の必要があります

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/10/04 11:35

    pixWidth = width * 3 + width % 4 だから pixWidth は 4の倍数です。
    width = 4k のとき pixWidth = 3(4k) = 4(3k)
    width = 4k+1 のとき pixWidth = 3(4k) + 3 + 1 = 4(3k+1)
    width = 4k+2 のとき pixWidth = 3(4k) + 6 + 2 = 4(3k+2)
    width = 4k+3 のとき pixWidth = 3(4k) + 9 + 3 = 4(3k+3)

    キャンセル

  • 2019/10/04 11:45

    んじゃその次はそうやって計算して出たファイルサイズが、保存したファイルサイズと合ってるのかどうかですねー

    キャンセル

  • 2019/10/04 15:19

    画像データ部は入力ファイル・出力ファイル共に計算が合いましたが,入力ファイルだとヘッダが122(情報ヘッダが108)byteとなっており,ここが計算が合っていないようです.ヘッダは54byteで固定だと考えていましたが,54byteにならない場合があるのでしょうか.

    キャンセル

  • 2019/10/04 15:22

    「BMP ファイルフォーマット」でぐぐったら説明出てくるのでよく読みましょう
    ヘッダは固定じゃないですし、画像データの格納形式も一種類だけじゃないです

    キャンセル

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

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

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