このプログラムについて – 固定ページ 2 – プログラミング – Home

このプログラムについて
 
通知
すべてクリア

[解決済] このプログラムについて

固定ページ 2 / 2

toru
 toru
(@toru)
ゲスト
結合: 24年前
投稿: 48
 

WIDTHが480で24BITの場合は↓こんな感じ。

unsigned char image[Y_SIZE][X_SIZE * 3];


返信引用
ん
 ん
(@ん)
ゲスト
結合: 24年前
投稿: 106
 

> 自分がなにせ初心者なもので、
> 皆さんの意見がときどき理解できていません。

わからないなら、質問しましょう。
「初心者」を言い訳材料にしても意味ないです。


返信引用
美紀
 美紀
(@美紀)
ゲスト
結合: 24年前
投稿: 11
Topic starter  

そうですね。んさんの言う通りですね。
BITMAPFILEHEADERとBITMAPINFOHEADER
ってなんですか?BMPフォーマット関係のこと
というのはわかるのですが、深いところはわかりません。


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 24年前
投稿: 117
 

ネット上のBITMAPについて
長いですが呼んでみてください。

ビットマップファイルについて
Windowsでは,3.0のころから,ビットマップという画像形式が標準で使用されています.Windowsに付属のペイントブラシなどで作成でき,現在ほとんどのグラフィックソフトが出力することができます.
このビットマップファイルは,2色,4色,16色,256色,フルカラーのデータを扱うことができ,圧縮がされていないため,サイズは大きいが,比較的簡単に扱うことのできるファイル形式です.(注:256色には,RLE形式という圧縮形式もあります.)
ここでは,ゲームなどに使用するのに便利な,256色のカラーテーブル付きのビットマップについて説明していきます.このカラーテーブル付きのビットマップのことを,DIB(Device Independent Bitmap:デバイス独立ビットマップ)と呼びます.つまり,カラーテーブルを持っているので,どんなデバイスにも出力できる形式です. (デバイス依存ビットマップは,システムカラーを使ったりするので,デバイスによってパレット値が変わってしまいます.)
さらに,DIBには,bottom-upDIBと,top-downDIBの二種類があります.通常,ファイルに保存されているビットマップは,bottom-upDIBです.これは,実際のイメージが,上下逆さまに格納されている形式です.最近は,あまり使われていませんが,WinGなどで転送速度の最適化をする場合には,top-downDIBというのを使用します.これは,イメージの上下の向きがそのままで格納されている形式です.

DIBの構造
ここからは,bottom-upDIBについて説明していきます.(基本的には,top-downDIBも同じ構造で,高さがマイナスになっています.)表1にDIBの構造を示します.
ヘッダ部
カラーテーブル
ビットデータ
表1.DIBの構造

さらに,ヘッダ部は,次の2つのヘッダに別れています.(表2)

ファイル情報 BITMAPFILEHEADER構造体
DIBのヘッダ BITMAPINFOHEADER構造体
表2.ヘッダ

これらの構造体を以下に示します.

typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;

bfType ビットマップファイルの印「BM」を格納します.
bfSize ファイルのサイズを指定します.
bfReserved1,bfReserved2 予約されています.0が入ります.
bfOffbits ビットデータの先頭までのオフセットです.
表3.BITMAPFILEHEADER構造体

typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;

biSize sizeof(BITMAPINFOHEADER)
biWidth ビットマップの幅です.
biHeight ビットマップの高さです.
biPlanes プレーン数です.通常1です.
biBitCount 1ピクセルあたりのビット数です.256色の場合8です.
biCompression DIBでは,非圧縮なので0です.
biSizeImage イメージのサイズです.DIBでは,0を指定します.
biXPelsPerMeter,biYPelsPerMeter DIBでは,0を指定します.
biClrUsed カラーテーブルを持っている場合,0またはそのサイズを示します.
biClrImportant 重要なカラーインデックス値を示します.通常0(全ての色)です.
表4.BITMAPINFOHEADER構造体

実際にファイルから読み込んで,メモリに保存する場合は,BITMAPINFOHEADER構造体以下を保存し,BITMAPINFOHEADER構造体へのポインタを保持するようにします.

次に,カラーテーブルです.

カラーテーブルは,RGBQUAD構造体の配列になっています.256色のビットマップの場合には,256色分のRGBQUAD構造体があります.次にRGBQUAD構造体を示します.

typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;

ここには,それぞれの色のRGB値を指定します.必ず,256色分のデータが連続して格納される必要があります.

これに続いて,実際のビットデータが格納されています.256色DIBでは,1ピクセルあたり,8ビットすなわち,1ピクセルあたり1バイトのデータとして格納されています.このビットデータの値は,カラーテーブルで示されるパレット番号になります.実際の色を知る場合には,カラーテーブルを参照します.

ビットデータは,bottom-upDIBの場合,一番下の水平走査線の左から順に格納されています.上下が逆に格納されており,下のラインから,上のラインへという順になります.

ここで注意するべきは,水平走査線のサイズは,必ず,32ビット境界にそろえる必要があるということです.つまり,256色の場合,幅が4の倍数ではないときには,4の倍数になるように足りない分のビットを追加する必要があります.この追加されたデータは,0にする必要があり,この部分は表示してはいけません.

ビットマップの読み込み
DIBをファイルからメモリ上に読み込む方法について説明します.基本的には,ファイルのヘッダを読み込んで,それに基づいてヘッダ部と,カラーテーブル,ビットデータを読み込んで,メモリに格納します.
それでは,順に説明していきます.
まず,ファイルを開いて,ファイルのハンドルを取得します.

HANDLE hFile;
hFile = CreateFile(szBitmapFile,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,NULL);

szBitmapFileには,ファイル名が入っています.ファイルが見付からない場合にはオープンしないので,hFileの値をチェックする必要があります.

次に,オープンできたら,ファイルヘッダを読み込みます.

BITMAPFILEHEADER bmHead;
DWORD d;

SetFilePointer(hFile,0,NULL,FILE_BEGIN);

/*ヘッダ部読み込み*/
ReadFile(hFile,&bmHead,sizeof(BITMAPFILEHEADER),&d,NULL);

ここで,ビットマップファイルであることを,bfTypeメンバから確認します.ビットマップであれば,ヘッダ部以降を読み込みます.ここで読み込む前にDIBの大きさや,色数などを知りたい場合は,ヘッダ部を仮に読み込んでおくと良いでしょう.ここでは,どんな場合でも読み込んでしまう方法(色数が何色でも読み込める方法)で説明します.次のように残りのデータを読み込みます.

LPBITMAPINFOHEADER pDib;

pDib = (LPBITMAPINFOHEADER)GlobalAlloc(GPTR,(bmHead.bfSize - sizeof(BITMAPFILEHEADER)) );
ReadFile(hFile,pDib,(bmHead.bfSize - sizeof(BITMAPFILEHEADER)),&d,NULL);

ここでは,ファイルヘッダのbfSizeメンバからファイルヘッダのサイズを引いたサイズの領域をメモリ上に確保し,その領域に,現在のファイルポインタの位置から,そのサイズだけデータを読み込んでいます.
以上で,DIBをメモリ上にロードできました.もちろん,

CloseHandle(hFile);

をお忘れなく.

以降は,ここで確保したメモリ領域のポインタ,pDibの値を使用してビットマップを表示したり,内容を編集したりします.

ビットマップを表示する
読み込みが完了したら,せっかくなので表示してみましょう.
DIBを表示するには,StretchDIBits関数を使用します. hWndで示されるウィンドウにDIBを表示するには,次のようにします.

HDC hdc;
BYTE *pBits;

pBits = (BYTE *)((RGBQUAD *)(pDib + 1) + 256);
hdc = GetDC(hWnd);
StretchDIBits(hdc,0,0,pDib->biWidth,pDib->biHeight,
0,0,pDib->biWidth,pDib->biHeight,
pBits,(BITMAPINFO *)pDib,DIB_RGB_COLORS,SRCCOPY);
ReleaseDC(hWnd,hdc);

pBitsは,DIBのビットデータの先頭へのポインタです.これを求めるのには,マクロを作っておくと便利でしょう.StretchDIBits関数は,パレットを最適化して表示してくれるので,ディスプレーの色数よりも大きな色数の絵を表示しようとしても,自動的にディザをかけてくれるので,表示ができます.しかし,その反面,256色のDIBの場合でも,最適なパレットを探すという処理をウィンドウズが行ってしまうためあまり高速な処理には適しません.また,256色環境で256色のDIBを表示する場合にも,ディザがかかってしまい,意図する絵ではなくなってしまいます.この場合は,パレットを設定してデバイスコンテクストに選択する必要があります.パレットについては他の章で詳しく説明します.

また,DIBを高速に表示したい場合は,CreateDIBSectionを使うとある程度高速になります.CreateDIBSectionは,Windows3.1で,WinGと呼ばれていたものと,ほぼ同じもので,ビットマップへのメモリDCを提供するものです.CreateDIBSectionについては,別ページで詳しく説明します.


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 24年前
投稿: 117
 

上記に基づいて簡単なグレーのスケールのファイル作成ロジックです。
まあ、参考程度に見てください。
簡単につくったんで雑で申し訳ないです。

char *wk;
long len, len1, len2, len3, len4;
FILE *fp;

BITMAPFILEHEADER b_map_h;
BITMAPINFOHEADER b_map_i;
RGBQUAD rgb[256];
char ptn[256][256];

len1 = sizeof(b_map_h); // BITMAPFILEHEADERサイズ
len2 = sizeof(b_map_i); // BITMAPINFOHEADERサイズ
len3 = sizeof(rgb); // カラー情報今回256
len4 = sizeof(ptn); // データサイズ今回256*256

len = len1 + len2 + len3 + len4; // ファイルサイズ

wk = (char *)&b_map_h; // ヘッダ作成部
memset(wk,0x00,len1);

wk[0] = 'B'; // 固定
wk[1] = 'M'; // 固定
b_map_h.bfSize = len; // ファイルサイズ
b_map_h.bfOffBits = len1 + len2 + len3; //データまでのオフセットセット

wk = (char *)&b_map_i; // 情報作成部
memset(wk,0x00,len2);

b_map_i.biSize = len2;
b_map_i.biWidth = 256;
b_map_i.biHeight = 256;
b_map_i.biPlanes = 1;
b_map_i.biBitCount = 8;
b_map_i.biCompression = 0;
b_map_i.biSizeImage = 0;
b_map_i.biXPelsPerMeter = 0;
b_map_i.biYPelsPerMeter = 0;
b_map_i.biClrUsed = 0;
b_map_i.biClrImportant = 0;

wk = (char *)&rgb[0];
memset(wk,0x00,len3);

// 今回はグレーのグラデーションでつくるカラーをセット
int i,j,k;
for (i = 0; i < 256; i++) {
j = i / 8;
j *= 8;
rgb[i].rgbBlue = j;
rgb[i].rgbGreen = j;
rgb[i].rgbRed = j;
}

// データをカラーパレットに沿ってセット
wk = (char *)&ptn[0][0];
memset(wk,0x00,len4);
for (i = 0; i < 256; i++) {
k = i / 2;
k = k * 2;
for (j = 0; j < 256; j++) {
ptn[j][i] = k;
}
}

// ファイル用データエリア確保
wk = new char[len];

memcpy(&wk[0],(void *)&b_map_h,len1); // ヘッダセット
memcpy(&wk[len1],(void *)&b_map_i,len2); // 情報セット
memcpy(&wk[len1 + len2],(void *)&rgb[0],len3); // パレットセット
memcpy(&wk[len1 + len2 + len3],(void *)&ptn[0][0],len4); // データセット

fp = fopen( test2.bmp, wb+ );
fwrite(wk,1,len,fp);
fclose(fp);

if (wk != NULL) {
delete [] wk;
}


返信引用
EIJI
 EIJI
(@EIJI)
ゲスト
結合: 25年前
投稿: 76
 

>TAKAさん
ページまるごとコピペじゃなくてURLを示したほうが良いのでは?
そのほうが読みやすいし。
もしまったくの他人のページだと問題になりかねないし。


返信引用
TAKA
 TAKA
(@TAKA)
ゲスト
結合: 24年前
投稿: 117
 

EIJIさんへ
すみませんそのとおりですね。
今後、気をつけます。


返信引用
美紀
 美紀
(@美紀)
ゲスト
結合: 24年前
投稿: 11
Topic starter  

TAKAさんありがとうございます。
おかげで自分の作りたかった物が出来ました。
しばらくインターネットをしてなかったので、
返事が遅れてすいませんでした。
TAKAさん以外の人たちも、
本当にありがとうございました。
また困ったときはよろしくお願いします。


返信引用
固定ページ 2 / 2

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました