🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

3回答

3641閲覧

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

suikoku

総合スコア5

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/10/03 19:24

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

該当のソースコード

C

1#include<stdio.h> 2#include<stdlib.h> 3#define NAME 20 //ファイル名の長さ 4 5int main() { 6 char infile[NAME], outfile[NAME]; 7 FILE *infp, *outfp; 8 unsigned char header[54]; 9 unsigned char **data; 10 int width, height; 11 int pixWidth; 12 int i; 13 14 //BMPファイル読み込み 15 printf("input file name:"); 16 scanf("%s", infile); 17 18 infp = fopen(infile, "rb"); 19 if (infp == NULL) { 20 printf("ファイルの読み込みに失敗しました\n"); 21 return -1; 22 } 23 24 //ヘッダ読み込み 25 fread(header, sizeof(unsigned char), 54, infp); 26 27 width = header[18] + header[19] * 256 + header[20] * 256 * 256 + header[21] * 256 * 256 * 256; 28 height = header[22] + header[23] * 256 + header[24] * 256 * 256 + header[25] * 256 * 256 * 256; 29 //1行は1pixelにつき3byteかつ4byteの倍数 30 pixWidth = width * 3 + width % 4; 31 32 //画素データ読み込み 33 data = (unsigned char**)malloc(sizeof(unsigned char*) * height); 34 for (i = 0; i < height; i++) { 35 data[i] = (unsigned char*)malloc(sizeof(unsigned char) * pixWidth); 36 } 37 38 for (i = 0; i < height; i++) { 39 fread(data[i], sizeof(unsigned char), pixWidth, infp); 40 } 41 42 fclose(infp); 43 44 //BMPファイル書き出し 45 printf("output file name:"); 46 scanf("%s", outfile); 47 48 outfp = fopen(outfile, "wb"); 49 if (outfp == NULL) { 50 printf("ファイルの読み込みに失敗しました\n"); 51 return -1; 52 } 53 54 //ヘッダ書き出し 55 fwrite(header, sizeof(unsigned char), 54, outfp); 56 57 //画素データ書き出し 58 for (i = 0; i < height; i++) { 59 if (fwrite(data[i], sizeof(unsigned char), pixWidth, outfp) < pixWidth) { 60 fputs("書き出しに失敗しました\n", stderr); 61 } 62 63 } 64 65 fclose(outfp); 66 67 for (i = 0; i < height; i++) { 68 free(data[i]); 69 } 70 free(data); 71 return 0; 72}

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikadzuchi

2019/10/04 00:24

ヘッダから読んだり計算した値を出力して想定とあっていますか?
mituha

2019/10/04 03:59

念の為確認ですが、ファイルのリネーム方法を知りたいではなく、後々独自処理(フォーマットも自前)もしたい想定の質問でしょうか?
suikoku

2019/10/04 06:17

情報ヘッダからヘッダのサイズを確認したところ108byteとなっており,入力ファイルはヘッダを108(ファイルヘッダも含めて122)byteとすると計算が合うのですが,出力ファイルはヘッダが54byteとなっており、ここが計算が合っていない箇所ではないかと考えています.ただバイナリエディタ上ではヘッダの情報には過不足は見られないように思えます.ヘッダのサイズは54byteで固定なのだと考えていましたがそうならない場合があるのでしょうか. このプログラムには後々独自処理を追加する予定でいます. とりあえず入出力から作ろうとしているところです.
suikoku

2019/10/04 06:38

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

2019/10/04 06:58

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

回答3

0

ベストアンサー

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

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

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

投稿2019/10/04 00:04

dodox86

総合スコア9254

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

suikoku

2019/10/04 06:11

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

2019/10/04 06:23 編集

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

2019/10/04 06:37

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

2019/10/04 06:39

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

0

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

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

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

投稿2019/10/03 22:05

編集2019/10/03 22:06
y_waiwai

総合スコア88038

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuma-s

2019/10/04 02: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)
y_waiwai

2019/10/04 02:45

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

2019/10/04 06:19

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

2019/10/04 06:22

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

0

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

投稿2019/10/03 20:30

kazuma-s

総合スコア8224

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

suikoku

2019/10/04 06:04

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問