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

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

詳細はこちら
C

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

Q&A

解決済

2回答

3088閲覧

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

Takayou

総合スコア15

C

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

0グッド

0クリップ

投稿2019/09/28 01:15

編集2019/09/28 02:06

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

C

1/* 2BMPファイルに対して, 以下の処理を行う 3・グレースケール変換 4・エッジ検出(Prewittオペレータ, Sobelオペレータ) 5・拡大,縮小,回転, 移動(線形補間法) 6*/ 7 8 9#include<stdio.h> 10#include<stdlib.h> 11 12#define IMG_MAX_SIZE 512 13 14typedef struct { 15 unsigned char *red; 16 unsigned char *blue; 17 unsigned char *green; 18}ImageData; 19 20typedef struct { 21 unsigned char FileHeader[14]; 22 unsigned int Size; 23 int Width, Height; 24 unsigned char InfoHeader[28]; 25 ImageData img; 26}BMP; 27 28//BMPファイル読み込み 29void ReadBmp(char FileName[], BMP* bmp); 30//画像を書き込む 31void WriteBmp(char FileName[], BMP* bmp); 32 33int main() { 34 BMP bmp; 35 36 char input_file[] = "lena.bmp"; 37 char output_file[] = "lenaout.bmp"; 38 ReadBmp(input_file, &bmp); 39 WriteBmp(output_file, &bmp); 40 41 return 0; 42 43 free(bmp.img.red); 44 free(bmp.img.green); 45 free(bmp.img.blue); 46} 47 48 49//BMPファイル読み込み 50void ReadBmp(char FileName[], BMP* bmp) 51{ 52 FILE* fp; 53 54 fopen_s(&fp, FileName, "rb"); 55 if (fp == NULL) { 56 printf("Not Found : %s", FileName); 57 exit(1); 58 } 59 60 //ヘッダー情報を読み込み 61 fread(bmp->FileHeader, sizeof(unsigned char), 14, fp); 62 fread(&bmp->Size, sizeof(int), 1, fp); 63 fread(&bmp->Width, sizeof(int), 1, fp); 64 fread(&bmp->Height, sizeof(int), 1, fp); 65 fread(bmp->InfoHeader, sizeof(unsigned char), 28, fp); 66 67 //画像本体の読み込み 68 bmp->img.red = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char)); 69 bmp->img.blue = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char)); 70 bmp->img.green = (unsigned char*)malloc( (bmp->Width) * (bmp->Height) * sizeof(unsigned char)); 71 if (bmp->img.red == NULL) { 72 printf("メモリ確保に失敗\n"); 73 exit(1); 74 } 75 if (bmp->img.green == NULL) { 76 printf("メモリ確保に失敗\n"); 77 exit(1); 78 } 79 if (bmp->img.blue == NULL) { 80 printf("メモリ確保に失敗\n"); 81 exit(1); 82 } 83 84 for (int h = 0; h < bmp->Height; h++) { 85 for (int w = 0; w < bmp->Width; w++) { 86 fread(&bmp->img.red [w + h * bmp->Width], sizeof(unsigned char), 1, fp); 87 fread(&bmp->img.green [w + h * bmp->Width], sizeof(unsigned char), 1, fp); 88 fread(&bmp->img.blue [w + h * bmp->Width], sizeof(unsigned char), 1, fp); 89 } 90 } 91 92 //読みこんだファイルを閉じる 93 fclose(fp); 94} 95 96//画像を書き込む 97void WriteBmp(char FileName[], BMP* bmp) 98{ 99 FILE* fp; 100 fopen_s(&fp, FileName, "wb"); 101 if (fp == NULL) { 102 printf("Not Found : %s\n", FileName); 103 exit(1); 104 } 105 106 fwrite(bmp->FileHeader, sizeof(unsigned char), 14, fp); 107 fwrite(&bmp->Size, sizeof(int), 1, fp); 108 fwrite(&bmp->Width, sizeof(int), 1, fp); 109 fwrite(&bmp->Height, sizeof(int), 1, fp); 110 fwrite(bmp->InfoHeader, sizeof(unsigned char), 28, fp); 111 112 113 printf("%s\n", bmp->FileHeader); 114 printf("%d %d %d\n", bmp->Size, bmp->Width, bmp->Height); 115 printf("%s\n", bmp->InfoHeader); 116 117 118 //画像本体の読み込み 119 for (int h = 0; h < bmp->Height; h++) { 120 for (int w = 0; w < bmp->Width; w++) { 121 fwrite(&bmp->img.red [w + h * bmp->Width], sizeof(unsigned char), 1, fp); 122 fwrite(&bmp->img.green[w + h * bmp->Width], sizeof(unsigned char), 1, fp); 123 fwrite(&bmp->img.blue [w + h * bmp->Width], sizeof(unsigned char), 1, fp); 124 } 125 } 126 127 fclose(fp); 128}

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

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

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

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

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

dodox86

2019/09/28 01:40

回答未満なのでこちらにコメントさせてもらいますが、何か色々と問題がありそうな気がします。Windowsのビットマップファイルって、単純なフォーマットではないです。また、構造体メンバーのパディングの問題で、正しくメンバーが読めていない気もします。ファイルのヘッダーは確かに14バイト(sizeof(BITMAPFILEHEADER))ですが、32ビット境界ではないのでコンパイル結果によっては以降にズレが生じます。そんなこんなで、ファイルの読み取り時点でおかしくなっているのでは。有名なレナさん画像"lena.bmp"をお使いでしょうから、ファイルの在処(ダウンロード元?)やコンパイルオプションを示せば、有効な回答を得られるかもしれません。
Takayou

2019/09/28 01:52

ありがとうございます、修正させていただきます。
Zuishin

2019/09/28 02:09

BMP ではないようですが。
dodox86

2019/09/28 02:21

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

2019/09/28 03:35

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

回答2

0

ベストアンサー

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

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

投稿2019/09/28 02:49

編集2019/09/28 02:50
SHOMI

総合スコア4079

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

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

Takayou

2019/09/28 02:55

回答ありがとうございます。 書き出すときに0を追加すればよいのでしょうか? BMPを書き込む関数の一部を以下のように書き換えたら、画像は表示されたのですが、ゆがんだ形になってしまいました。 ```C //一列4byte単位でなければならないので、padding処理を行う int stride = (bmp->Width + 3) / 4 * 4; unsigned char padding = '00'; //画像本体の書き込み 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); } for (int i = 0; i < stride - bmp->Width; i++) { fwrite(&padding, sizeof(unsigned char), 1, fp); fwrite(&padding, sizeof(unsigned char), 1, fp); fwrite(&padding, sizeof(unsigned char), 1, fp); } } ```
SHOMI

2019/09/28 03:13 編集

0埋めを3バイトごとと決め打ちではずれます。 例:幅2ドットの場合、0埋めは2バイト。 int stride = (bmp->Width*3 + 3) / 4 * 4; unsigned char padding = 0; for (int i = 0; i < stride - bmp->Width*3; i++) { fwrite(&padding, sizeof(unsigned char), 1, fp); } 読み出し側も0埋めを考慮して読んでいませんね。
Takayou

2019/09/28 03:39

上手くいきました!ありがとうございます! 読み出し側でも0埋めをして読むとのはなぜなのでしょうか?
SHOMI

2019/09/28 03:45

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

2019/09/28 03:53

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

0

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

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

投稿2019/09/28 01:48

y_waiwai

総合スコア88038

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問