• ベストアンサー

BMP 仕様

言語:C++ 標準ライブラリのみ OS:Windows 以上の条件でビットマップを表示したいと考えています。 ただし、今後JPEGなど別フォーマットでも対応できるようにするためLoadImage関数などは使用しないものとします。 //ファイル読み込み ifstream in( fileName.c_str(), ifstream::binary); ~ //char* _data in.read( _data, _size ); //データ取得 unsigned long getUnLng( int Index ) const { //unsigned char* _unChar = _data; //データ単位がnバイトごとの場合は別に考慮する unsigned long unLng = _unChar[Index]; return unLng; } 上記で画像データは取得できるのですが、どこに何が入っているのかがわかりません。 Index = 0 の場合 B Index = 1 の場合 M などが取得できるのですが、これが何を意味しているのかを知りたいのです。 幅や高さ、色の情報がどこに存在するかの詳細は分かりませんでしょうか。 ----例 幅  :Index 10 ~ 13 高さ :Index 14 ~ 17 ・幅×高さが 2×3 の場合 色情報:Index 18 ~ 23 ---- 説明が下手で申し訳ありません。 ご指摘いただければ情報の補足はさせていただきますのでよろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

No.1です。 >てっきりBITMAPFILEHEADER等は単なるWindowsAPIの構造体かと。 「共通規格」として規定されたデータ構造を、利用しやすいように同じ名称で構造体定義しているものは他にもたくさんありますよ。 >データ構造に関しては以上の認識で宜しいでしょうか。 どちらかというと、「nバイト」の部分は「BITMAPFILEHEADERのオフセットバイト」と覚えていた方がいいです。 こういったデータのデータ構造可変の為、「ヘッダのサイズ」や「次のデータのオフセット位置」等で表す場合が多いですから。 >ご紹介いただいたデータ構造というのはビットマップ専用のものではないのでしょうか 基本、ビットマップ専用です。 これは他のデータのファイルを「バイナリエディタ」で除いた方がはっきりとわかりますよ。 >(jpeg、png等もこれと同じデータ構造で出来ている?) おそらく、「圧縮形式」のところが引っかかっているのでしょう。 あまり使いませんが、ヘッダだけbitmap形式で内部の画像データはJPEGということもできます。 ここでは説明は省きますが、興味があったら「RIFF」や「TIFF」のデータフォーマットも調べてみてください。

ShimantoGa
質問者

お礼

ありがとうございます。 >こういったデータのデータ構造可変の為、「ヘッダのサイズ」や「次のデータのオフセット位置」等で表す場合が多いですから。 例えばファイルサイズが欲しいときは「先頭から6バイト目を参照する」ということになりますよね。 const int FILE_SIZE = 6; このように定数定義しようと考えていたのですが、それでは問題ありますでしょうか。 次のデータのオフセット位置、であれば const int FILE_TYPE = 2; const int FILE_SIZE = 4; //ファイルサイズの位置 Index = FILE_TYPE + FILE_SIZE; となりますがこれでは全データ分を定数定義しなければならないので。 >これは他のデータのファイルを「バイナリエディタ」で除いた方がはっきりとわかりますよ。 jpegは先頭から .リ....JFIF~ といった感じでまったくの別物でした、確かに何の関連性もないようですね。 >おそらく、「圧縮形式」のところが引っかかっているのでしょう。 その通りです。 jpeg等は別個に形式を持っているにも拘らずbitmap形式にjpegの圧縮形式情報を持たせる意義がわからず?となっておりました。 BITMAPV5HEADER等の圧縮形式に関してわからなければまた別個に質問させていただきます。

その他の回答 (5)

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.6

>ただ2000以前の環境にアプリを導入した際、DLLの導入を要求してしまっては.NET等を使用しない理由が薄れてしまいます。 でしたら、OleLoadPictureはどうでしょうか。 Windows95から使えるようですし、いくつかサンプルもあるようです。

ShimantoGa
質問者

お礼

>でしたら、OleLoadPictureはどうでしょうか。 おお、これは使えそうですね。 若干参考サイトが少ないですが、利用してみたいと思います。 ありがとうございました。

  • titokani
  • ベストアンサー率19% (341/1726)
回答No.5

>言語:C++ 標準ライブラリのみ >定義に関して曖昧な部分が多いことは否定できません。 標準ライブラリは規格で決まっていますし、Win32APIは含みません。 >ただし、今後JPEGなど別フォーマットでも対応できるようにするためLoadImage関数などは使用しないものとします。 むしろ逆だと思います。JPEGを自前で読み込むのはえらい面倒です。 対応するライブラリを使うのが楽ですよ。 GDI+とかはどうでしょうか。

ShimantoGa
質問者

お礼

ありがとうございます。 >標準ライブラリは規格で決まっています 失礼しました。 曖昧というのは私がC++標準ライブラリの内容を正しく認識できていないという意味です。 >Win32APIは含みません。 初めに書いておくべきでした、重ねて申し訳ありません。 >GDI+とかはどうでしょうか。 このようなライブラリもあるんですね、勉強になります。 ただ2000以前の環境にアプリを導入した際、DLLの導入を要求してしまっては.NET等を使用しない理由が薄れてしまいます。 どこまで許容するかの問題なんですが、手間がかかるようであればGDI+の使用を考えてみようと思います。

回答No.4

No.1です No.2 >このように定数定義しようと考えていたのですが、それでは問題ありますでしょうか。 使用方法さえきっちりと理解できていれば問題はないと思います。 但し、この定数を利用できるのは「それぞれのブロック(ヘッダ)」内だけです。 一番の理由は「データが必ずしも連独している必要がない」というところからです。 例えば1つ目のヘッダが「10byte」あるからと言って、次のヘッダが「11Byte目」からという保証はありません。 「オフセットの項目」が存在している場合、オフセットの値が「20」であれば「2ヌByte目(今のヘッダデータの次からnByteなら31Byte目)」となります。 この間にある「10Byte(もしくは20Byte)」はゴミデータとして処理する必要があります。 従って、「そのヘッダ内でのオフセット位置を表す」程度にとどめたほうがいいです。 WinAPIの構造体をそのまま利用できないのであれば、「同等の構造体」を定義するのも一つの手です。

ShimantoGa
質問者

お礼

ありがとうございます。 オフセットの意味を勘違いしておりました。 てっきり各項目からの相対位置的な意味合いかと。 >例えば1つ目のヘッダが「10byte」あるからと言って、次のヘッダが「11Byte目」からという保証はありません。 つまりファイルヘッダが14byteだからといって、情報ヘッダの開始地点が14byte目から、とは限らないということでしょうか。 ファイルヘッダのオフセット項目が20であれば 14 + 20 = 34 情報ヘッダの開始地点は34byte目からになる、という認識でよろしいでしょうか。 そうなりますとおっしゃる通りファイルヘッダのオフセット位置までしか定数化できませんね。 あとはコード上でオフセットの値分位置をずらす、と。 >WinAPIの構造体をそのまま利用できないのであれば、「同等の構造体」を定義するのも一つの手です。 画像形式のヘッダごとに構造体を作成するということですよね。 ただそこまで知識を身に付けることが出来ていればbmpに関してはWinAPIの構造体を利用し、jpegなどは自作した構造体という形になると思います。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

「フォーマットがど~の」とかいう前に, 「C++ 標準ライブラリのみ」で画像を表示することは不可能だと思う. 「標準ライブラリ」がどういう意味であるかにもよるけど....

ShimantoGa
質問者

お礼

ありがとうございます。 >「標準ライブラリ」がどういう意味であるかにもよるけど.... 私の認識ではMFCやCLIを使用しないもの、としております。 定義に関して曖昧な部分が多いことは否定できません。 http://docs.sun.com/app/docs/doc/820-1213/6nctanure?l=ja&a=view あと補足になるかもしれませんが「OS:Windows」としている以上WindowsのAPIは使用します。

回答No.1

>どこに何が入っているのかがわかりません。 ビットマップのデータ構造は理解できていますか? Microsoft Windows Bitmap Image http://ja.wikipedia.org/wiki/Windows_bitmap

ShimantoGa
質問者

お礼

回答ありがとうございます。 >ビットマップのデータ構造 サイトを参照したところ、理解できておりませんでした。 てっきりBITMAPFILEHEADER等は単なるWindowsAPIの構造体かと。 0バイト目から BITMAPFILEHEADER構造体 14バイト目から BITMAPV5HEADER構造体:98以降の場合 nバイト目から RGBQUAD構造体 n + 4 バイト目から ボトムダウン形式の画像データ データ構造に関しては以上の認識で宜しいでしょうか。 また、圧縮形式という項目が存在します。 ご紹介いただいたデータ構造というのはビットマップ専用のものではないのでしょうか?(jpeg、png等もこれと同じデータ構造で出来ている?)

関連するQ&A

  • char** buffer (このような2重の**の意味について)

    私は現在C++のプログラミングを学習しています。 C++の教本(SoftbankCreative 高橋麻奈著 やさしいC++) 自体は読み終え、今現在別のプログラムの本を読んでいるのですが、 わからない表記があり、 またネットでどのように(何という名前で)検索していいかわからないのでこちらで質問させて頂きます。 (char* buffer などであれば「ポインタ」とかで検索すれば出るのですが…、char**のように2重になってるのは引っ掛かりませんでした。) たとえば、 void readFile( char** buffer, int* size, const char* filename ); このような場合、 char** buffer はどういう事なのでしょうか? この書き方の名前等はありますか?(char* buffer だと ポインタ のように) あるいは、基本的なC++の本に載っている知識の組み合わせで理解できるものなのでしょうか? ネットのC++勉強サイトや、ヒントでいいので教えて頂きたいです。 必要ないかもしれませんが、私がつまった所に関連するコードを載せておきます。 void readFile( char** buffer, int* size, const char* filename );  ~~~ (mainLoop()という関数内) const char* filename = "stageData.txt"; char* stageData; int fileSize; readFile( &stageData, &fileSize, filename );  ~~~ void readFile( char** buffer, int* size, const char* filename ){ ifstream in( filename, ifstream::binary ); if ( !in ){ *buffer = 0; *size = 0; }else{ in.seekg( 0, ifstream::end ); *size = static_cast< int >( in.tellg() ); in.seekg( 0, ifstream::beg ); *buffer = new char[ *size ]; in.read( *buffer, *size ); } } 途中で、 char* stageData; とし、 readFile( &stageData, のように放り込んでいるので、 ポインタのその更にポインタ、みたいな感じでしょうか? であればあえて2重にする意味がよくわからないです。 よろしくお願い致します。

  • BMPファイルへの書き込みができない

    このプログラムは、左半分を黒、右半分を白の画像をBMPファイルに出力しようとしています。(出来ていません) プログラムの下に質問書いてます!お願いします! #include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct{ char *filename; int x; int y; int width; int height; unsigned char data[80][100]; } BMP_DATA; static void WriteBmp(char *filename, BMP_DATA Image) { unsigned long Bmp_size;/*BMPファイルのサイズ*/ unsigned int Bmp_info_header_size;/*情報ヘッダのサイズ*/ unsigned int Bmp_header_size;/*ヘッダのサイズ*/ long Bmp_width;/*幅*/ long Bmp_height;/*高さ*/ unsigned short Bmp_planes;/*プレーン数*/ unsigned short Bmp_color;/*色 = 1[bit] (黒か白かだけ)*/ long Bmp_image_size;/*画像部分のサイズ*/ long Bmp_xppm;/*水平解像度*/ long Bmp_yppm;/*垂直解像度*/ int i,j; unsigned char Bmp_headbuf[54]; /*ヘッダ*/ unsigned char Bmp_Data[13]; FILE *Out = fopen(filename, "wb"); if(Out==NULL){ fclose(Out); exit(1); } /* ヘッダ情報の準備 */ Bmp_info_header_size = 40; Bmp_header_size = 54; Bmp_planes = 1; Bmp_color = 1; Bmp_image_size = Image.height * Image.width; Bmp_xppm = 0; Bmp_yppm = 0; Bmp_size = Bmp_image_size + Bmp_header_size; Bmp_headbuf[0] = 'B'; Bmp_headbuf[1] = 'M'; memcpy(Bmp_headbuf+2, &Bmp_size, sizeof(Bmp_size)); Bmp_headbuf[6] = 0; Bmp_headbuf[7] = 0; Bmp_headbuf[8] = 0; Bmp_headbuf[9] = 0; memcpy(Bmp_headbuf+10, &Bmp_header_size, sizeof(Bmp_header_size)); Bmp_headbuf[11] = 0; Bmp_headbuf[12] = 0; Bmp_headbuf[13] = 0; memcpy(Bmp_headbuf+14, &Bmp_info_header_size, sizeof(Bmp_info_header_size)); Bmp_headbuf[15] = 0; Bmp_headbuf[16] = 0; Bmp_headbuf[17] = 0; memcpy(Bmp_headbuf+18, &Image.width, sizeof(Bmp_width)); memcpy(Bmp_headbuf+22, &Image.height, sizeof(Bmp_height)); memcpy(Bmp_headbuf+26, &Bmp_planes, sizeof(Bmp_planes)); memcpy(Bmp_headbuf+28, &Bmp_color, sizeof(Bmp_color)); memcpy(Bmp_headbuf+34, &Bmp_image_size, sizeof(Bmp_image_size)); memcpy(Bmp_headbuf+38, &Bmp_xppm, sizeof(Bmp_xppm)); memcpy(Bmp_headbuf+42, &Bmp_yppm, sizeof(Bmp_yppm)); Bmp_headbuf[46] = 0; Bmp_headbuf[47] = 0; Bmp_headbuf[48] = 0; Bmp_headbuf[49] = 0; Bmp_headbuf[50] = 0; Bmp_headbuf[51] = 0; Bmp_headbuf[52] = 0; Bmp_headbuf[53] = 0; /* ヘッダ情報書き出し */ fwrite(Bmp_headbuf, sizeof(unsigned char), Bmp_header_size, Out); /* 画像データ書き出し */ for(i=0;i<13;i++) Bmp_Data[i] = 0; for(i=0; i<Image.height; i++){ for(j=0; j<Image.width; j++){ int index = j/8; if(j%8 == 0){ Bmp_Data[index] = Image.data[i][j ] * 128 + Image.data[i][j+1] * 64 + Image.data[i][j+2] * 32 + Image.data[i][j+3] * 16 + Image.data[i][j+4] * 8 + Image.data[i][j+5] * 4 + Image.data[i][j+6] * 2 + Image.data[i][j+7]; } } Bmp_Data[12] = (Bmp_Data[12] & 0xf0); fwrite(Bmp_Data, sizeof(unsigned char), 20, Out); /* ○ */ } fclose(Out); } int main() { BMP_DATA Image; int line = 0; int i,j; Image.x = 0; Image.y = 0; Image.width = 100; Image.height = 80; if(line == 0){ for(i=0; i<Image.height; i++){ for(j=0; j<Image.width; j++){ Image.data[i][j] = 1; } } } while(1){ /* BMPファイルデータを編集 */ for(j=0; j<Image.width; j++){ if(j < 50){ Image.data[line][j] = 0;//black }else{ Image.data[line][j] = 1;//white } } /* すべての列を編集したら、再描画する */ if(line == 63){ /* BMPファイルに書込む */ WriteBmp("display.bmp", Image); break; } line++; } return 0; } 以下の条件で、BMPファイルへ書き込もうとしています ・色の深さ1(黒か白) ・画像のピクセルサイズ(横100×縦80) fwrite関数で1列ずつ書き込もうとしているのですが、 この関数は1バイトずつしか書き込めないみたいで、100ビット書き込もうと思うと、 最低でも104ビット書き込まなくてはならない状況になります。 まず、この4ビットはどう処理すればいいのでしょうか?? あと、display.bmpのファイルがある状態で、プログラムを実行するとちゃんと動くのですが、 プログラム中の○のところのfwrite関数の第三引数を13にすると、BMPファイルが壊れて閲覧できなくなります。(ある程度大きい数字だと、BMPファイルは壊れないのですが、ぐちゃぐちゃの絵になります) その理由もわかりません。 汚い文章&プログラムですが よろしくお願いします><

  • ポインタのキャスト

    配列の先頭アドレスをunsigned long型で取得するにはどうしたら良いでしょうか? 下記だとダメですよね? char a{4} = [0, 1, 2, 3]; unsigned long adr; adr = (usigned long)&a[0]; よろしくお願いします。

  • R8Cマイコンの乗算

    R8C34Mを使っています。 例えば下記のコードを実行したら  unsigned long kai;  unsigned int xx;  unsigned int yy; xx = 0x07d0;  //10進で2000 yy = 0x0064;  //10進で100 kai = xx * yy; kaiは 0x30d40 となるはずが、0x0d40 でした。 kai = (unsigned long)xx * yy; と書き直したら、うまくいきました。 答えが2バイトを超えるのが分かっていたのでkaiはlong長にしました。 どうして右辺もキャストでlong長にしないといけないのでしょうか? また、下記のようにkaiをint長、xx,yyをchar長にした場合は、 kaiは意図する値の0x4e20 になりました。  unsigned int kai;  unsigned char xx;  unsigned char yy; xx = 0x00c8;  //10進で200 yy = 0x0064;  //10進で100 kai = xx * yy; どうして後者の場合はうまくできて、前者の場合はキャストしないといけないのでしょうか? この辺ご存知の方ご教授願います。

  • H8S/2552Fにおけるプログラミング

    現在イエローソフト社のH8S/2552F USB-IF CPUボードを用いて,I/Oポートから32bitトルグスイッチの状態を出力しようとしています。それらのデータをシフトしつつ外部SRAMに送り、さらに32bitのデータとしてPCに取り込みたいと考えているのですが、その方法がわかりません。 以下に現状のプログラムを載せさせて頂きました。(間違いがあるのは十分承知です…) どなたか教えて下さい。よろしくお願い致します。 #define PORT4 (*((volatile unsigned char *)0xFFFFB3)) #define PORT9 (*((volatile unsigned char *)0xFFFFB8)) #define PORTH (*((volatile unsigned char *)0xFFFA14)) #define PORTJ (*((volatile unsigned char *)0xFFFA15)) unsigned long in_switch(void) {     return (PORTJ <<24);     return (PORTH <<16);     return (PORT9 <<8 );     return (PORTJ | PORTH | PORT9 | PORT4) ; } void main() {    puts("トグルスイッチテストプログラム");    while (1) {          unsigned long data;          printf("リターンキーで現在のスイッチ状態を表示します。");          fgetc(stdin); //リターンキー入力待ち          data = in_switch();//スイッチの状態を入力          printf("現在のスイッチ状態=%d(H'%02X)\n", data, data); //スイッチ状態表示 } }

  • C言語でのコンパイルエラー

    初心者です。 非常に基本的な質問かもしれませんが、 ご回答いただけたらうれしいです。 void test1(unsigned char* data) { } void test2(unsigned char** data) { } int main(void) { unsigned char data1[6]; unsigned char data2[6][6]; test1(data1); test2(data2); } としてtest1はうまくいくのに、 test2はコンパイルエラーになります。 どっちもポインタになると思うのですが…。 また、unsigned char data2[6][6]を 他の関数の引数とする場合は どうすればよろしいのでしょうか? 宜しくお願いいたします。

  • VC++6.0でC言語の基本データ型のビット長と範囲をしりたいです

    VC++6.0を使用しています。コマンドラインを使い勉強しているのですが、基本データ型のビット長と使える数の範囲を知りたいです。 たとえば、int型だと32ビットで-32767から32767の範囲の数を扱えるとかを知りたいです。コマンドライン上から調べることはできないのでしょうか? ネットでも書いてあるところがあるならいいのですが、できれば自分の手で調べる方法を見つけたいのです。 ちなみに char, unsigned char, int, unsigned int, short int, unsigned short int, long int unsigned long int, float, double, long doubleなどが知りたいです。 方法を知っている方教えてください。よろしくお願いします。

  • C++でBMP解析

    タイトルの通り、 C++でBMPのデータを取得したいと思いますがやり方がわかりません。 たとえば座標(3,6)にはFF0000の色が使われているなどです。 windowsの場合です。

  • templateの使い方を教えて下さい。

    質問タイトルの通りです。 今、 unsigned char* AllocByteArray1d(unsigned long int n){ unsigned char *box; box = (uchar *)calloc(n, sizeof(uchar)); if(box == NULL){ puts("can't allocate memory..."); exit(1); } return box; } という関数があって、これはunsigned charの配列をとってくれる関数になってます。これをtemplateを使って、intの配列もとれるようにしたいんです。 恥ずかしながら試しに、 template <typename T> T* AllocByteArray1d(unsigned long int n){ T *box; box = (T *)calloc(n, sizeof(T)); if(box == NULL){ puts("can't allocate memory..."); exit(1); } return box; } とやってみましたがダメでした。事前にTのデータ型がわからないからだろうか、と思って template unsigned char* AllocByteArray1d(unsigned long int); を入れて実体化させてみましたが、これでもダメでした。 どこを修正すれば使えるようになるのか、C++に詳しい方に教えて頂けると幸いです。

  • 固定幅フィールドのテキストデータをifstreamを使って読み込む方法

    固定幅フィールドのテキストデータをifstreamを使って読み込む方法 について教えてください。 計算結果の出力ファイルに1行につき8カラム、20カラム、10カラムのデータがあるとします。 例えば 1.2345671.2345678912345678911.23456789 このデータ行には 1.234567(8カラム幅) 1.234567891234567891(20カラム幅) 1.23456789(10カラム幅) の3つの固定小数点の数字が書かれています。 上記例のように3つ(複数)の数字が必ずしもホワイトスペース区切りにはなっていないものとします。 これをC++標準ライブラリのifstream や stringstreamを用いて読み込む場合、どのような記述をしなければならないのでしょうか? たとえば、 int main(int argc, char** argv) { double data[3]; char buf[BUFSIZ]; ifstream ifs( argv[1] ); // argv[1] には上記データが書かれたファイル名が入っているとします。 stringstream str; while( !ifs.eof() ) { if( !ifs.getline( buf, BUFSIZ, '\n' ) ) break; str << buf; str >> setw(8) >> data[0] >> setw(20)>> data[1] >> setw(8) >> data[2]; } cout << data[0] << " " << data[1] << " " << data[2] << endl; return 0; } のような書き方だと、以下のように出力されてしまい、幅を指定しているsetw()が効いていません。 1.23457 0.234568 0.234568 恐らく、'.'がセパレータとして使われて読み込まれているものと思います。 sscanf( buf, "%8lf%20lf%10lf", &data[0], &data[1], &data[2] ); を使うしか方法が無いのでしょうか? 開発環境は ubuntu上のg++ 4.4.3 です。