FC2ブログ

ホーム > DIBファイルフォーマット > DIBファイルの書き込み

DIBファイルの書き込み



DIBデバイス独立ビットマップ)をファイルに書き込む場合は、以下のような流れになります。

  1. DIBハンドルからDIBSECTION構造体を取得し、必要な各値を算出する。
  2. BITMAPINFO構造体のサイズを算出する。
  3. BITMAPFILEHEADER構造体をファイルに書き込む。
  4. BITMAPINFOHEADER構造体をファイルに書き込む。
  5. カラーテーブルがあればファイルに書き込む。
  6. マスクビットフィールドがあればファイルに書き込む。
  7. 圧縮形式に従ってピクセルビットをファイルに書き込む。




DIBのカラーテーブルを取得する関数です。

//DIBのカラーテーブルからRGB(赤、緑、青)カラーの値を取得
UINT __stdcall _GetDIBColorTable(HBITMAP hBitmap,UINT iStart,UINT cEntries,RGBQUAD *prgbq)
{
HDC hMemDC=::CreateCompatibleDC(0);
HGDIOBJ hOldObj=::SelectObject(hMemDC,hBitmap);
UINT uResult=::GetDIBColorTable(hMemDC,iStart,cEntries,prgbq);
::SelectObject(hMemDC,hOldObj);
::DeleteDC(hMemDC);
return uResult;
}


新規にファイルを作成して、_DIBStreamOut関数を呼び出します。

//DIBをファイルに書き出します。
BOOL __stdcall _SaveDIB(LPCTSTR lpszFileName,HBITMAP hbmDIB,DWORD dwCompression)
{
CFile outfile;
if (!outfile.Open(lpszFileName,CFile::modeCreate|CFile::modeWrite)) return FALSE;
BOOL bResult=_DIBStreamOut(&outfile,hbmDIB,dwCompression);
outfile.Close();
return bResult;
}


DIBをファイルに書き出します。

//DIBファイルストリームの書き込み
BOOL __stdcall _DIBStreamOut(CFile* outfile,HBITMAP hbmDIB,DWORD dwCompression)
{
ASSERT(AfxIsValidAddress(outfile,sizeof(CFile),0));

//現在のファイル位置を取得しておきます。
ULONGLONG posStart=outfile->GetPosition();

//DIBSECTION構造体の取得
DIBSECTION ds={0};
//入力されたDIBが正しくないか、DIBではない場合、
//FALSEを返して終了します。

if ((!::GetObject(hbmDIB,sizeof(DIBSECTION),&ds))||
(ds.dsBmih.biSize!=sizeof(BITMAPINFOHEADER))) return FALSE;

//各値の取得------------------------------------------------------------
UINT width =ds.dsBmih.biWidth; //DIBの幅
UINT height=abs(ds.dsBmih.biHeight); //DIBの高さ(絶対値)
UINT nBpp=ds.dsBmih.biBitCount; //DIBのビット深度

DWORD widthBytes=WIDTHBYTES(nBpp*width); //ビットマップバイト幅の算出
DWORD dwSizeImage=widthBytes*height; //ピクセルデータのバイト数

//カラーテーブルのサイズを算出します。----------------------------------
DWORD dwClrUsed=ds.dsBmih.biClrUsed; //使用色数
UINT nColors=0; //カラーテーブルのエントリー数を0にします。
if (nBpp<=8) { //カラーテーブルがある時
//使用色数が0でないなら、エントリー数には使用色数を、
//それ以外は2のnBpp乗を代入する

nColors=(dwClrUsed)? dwClrUsed:1<<nBpp;
}
DWORD dwSizeOfColorTable=sizeof(RGBQUAD)*nColors;

//マスクビットフィールドがあればそのサイズを算出します。----------------
//ビットカウントが16/32ビットで、圧縮方法がBI_BITFIELDSの場合、
//マスクビットフィールドのサイズを12byte、それ以外は0byteにします。

DWORDdwSizeOfMaskBit=(((nBpp==16)||(nBpp==32))&&
(ds.dsBmih.biCompression==BI_BITFIELDS))?sizeof(DWORD)*3:0;

//BITMAPINFO構造体のサイズを算出します。--------------------------------
DWORD dwSizeOfBitmapInfo=((nBpp=32)&&(dwCompression==BI_BITFIELDS))?
sizeof(BITMAPV5HEADER):
sizeof(BITMAPINFOHEADER)+dwSizeOfColorTable+dwSizeOfMaskBit;

//BITMAPFILEHEADERを書き込みます。--------------------------------------
BITMAPFILEHEADER fh;
fh.bfType=0x4D42; //DIBファイルの形式'BM'
fh.bfOffBits=sizeof(BITMAPFILEHEADER)+dwSizeOfBitmapInfo;
fh.bfSize=fh.bfOffBits+dwSizeImage;
fh.bfReserved1=fh.bfReserved2=0;
outfile->Write(&fh,sizeof(BITMAPFILEHEADER));

//BITMAPINFOHEADERを書き込みます。--------------------------------------
//ランレングス圧縮の場合はイメージサイズを0にします。

if ((dwCompression==BI_RLE4)&&(ds.dsBmih.biBitCount==4)){
ds.dsBmih.biSizeImage=0;
ds.dsBmih.biCompression=BI_RLE4;
}
else if ((dwCompression==BI_RLE8)&&(ds.dsBmih.biBitCount==8)){
ds.dsBmih.biSizeImage=0;
ds.dsBmih.biCompression=BI_RLE8;
}
else
ds.dsBmih.biSizeImage=dwSizeImage;

//32ビットアルファDIBの場合
if ((ds.dsBmih.biBitCount==32)&&(dwCompression=BI_BITFIELDS))
ds.dsBmih.biSize=sizeof(BITMAPV5HEADER);

outfile->Write(&ds.dsBmih,sizeof(BITMAPINFOHEADER));

//カラーテーブルがあれば、書き込みます。--------------------------------
if (dwSizeOfColorTable){
RGBQUAD* pColorTable=new RGBQUAD[nColors];
//確保した領域にDIBのカラーテーブルを読み出します。
_GetDIBColorTable(hbmDIB,0,nColors,pColorTable);
outfile->Write(pColorTable,dwSizeOfColorTable);
delete[]pColorTable;//確保した領域の開放
}
//マスクビットフィールドがあれば、書き込みます。------------------------
else if (dwSizeOfMaskBit){
outfile->Write(&ds.dsBitfields,dwSizeOfMaskBit);
//32ビットアルファDIBの場合、
if ((nBpp==32)&&(ds.dsBmih.biCompression==BI_BITFIELDS)){
DWORD bV5AlphaMask=0xFF000000;
outfile->Write(&bV5AlphaMask,sizeof(DWORD));
int nRemain=sizeof(BITMAPV5HEADER)-sizeof(BITMAPINFOHEADER)-sizeof(DWORD)*4;
BYTE b=0;
for(int i=0;i<nRemain;i++)
outfile->Write(&b,1);
}
}
//ピクセルビットの書き込み----------------------------------------------
switch(ds.dsBmih.biCompression){
case BI_RLE4:
//4ビットランレングス圧縮の場合は、_EncodeRle4関数を呼び出して
//RLE4圧縮して書き込みます。

dwSizeImage=(DWORD)_EncodeRle4(ds.dsBm.bmBits,dwSizeImage,width,height,outfile);
break;

case BI_RLE8:
//8ビットランレングス圧縮の場合は、_EncodeRle8関数を呼び出して
//RLE8圧縮して書き込みます。

dwSizeImage=(DWORD)_EncodeRle8(ds.dsBm.bmBits,dwSizeImage,width,height,outfile);
break;

case BI_RGB:
case BI_BITFIELDS:
default:
//圧縮されていない場合は、そのまま書き込みます。
outfile->Write(ds.dsBm.bmBits,ds.dsBmih.biSizeImage);
return TRUE;
break;
}
//ランレングス圧縮の場合------------------------------------------------
//書き込みバイト数が0のときはFALSEを返して終了します。


if (!dwSizeImage) return FALSE;

//ファイルサイズを取得して、BITMAPFILEHEADER構造体のbfSizeに格納します。
fh.bfSize=(DWORD)outfile->GetLength();
//ファイル先頭に戻ってからBITMAPFILEHEADER構造体を書き直します。
outfile->Seek(posStart,CFile::begin);
outfile->Write(&fh,sizeof(BITMAPFILEHEADER));

return TRUE;
}


戻り値がTRUEなら、ファイルへの書き込みは成功です。

サンプルプログラム(VisualC++.Net 2003ソリューション)DIBFileTest04.zip

上記のzipファイルをダウンロードしてからWinRAR等で解凍し、DIBFileTest04フォルダー内にある「DIBFileTest.sln」を開きます。「F5」キーを押すと、ビルド確認のダイヤログが表示されるので「Yes」を選択してソリューションをビルドします。



ビルドが終わると直ちにプログラムが自動起動してウィンドウが表示されます。ウィンドウのメニューで「ファイル」/「開く」を選択して、「ファイルを開く」ダイヤログを表示させ、resフォルダー内の「Luchi8bit.bmp」を読み込みます。



画像が表示されたところで「ファイル」/「名前を付けて保存」で「ファイル名を付けて保存」ダイヤログを表示させ、「Luchi8bit-Copy.bmp」と名づけて「保存」ボタンを押します。



ツールバーの「新規」で画像を一旦を消しておいてから、先ほど作成した「Luchi8bit-Copy.bmp」を読み込んで、元の画像と同じ画像が表示されるか確認します。




スポンサーサイト



コメント: 0

この記事へのコメント
ブログ著者にのみ知らせます。

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/13-404a3c35
Listed below are links to weblogs that reference
DIBファイルの書き込み from マルチメディアファイルフォーマット

Home > DIBファイルフォーマット > DIBファイルの書き込み

タグクラウド
ブロとも申請フォーム

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る