#include"bmpio.h" // 初期化 // コンストラクタ BmpIO::BmpIO(void) { m_pErrText[0]=_T('\0'); } // コピーコンストラクタ // const BmpIO &source:代入する側のオブジェクト BmpIO::BmpIO(const BmpIO &source) { CopyObject(&source); } // 終了処理 // BMPの削除と初期化 void BmpIO::DeleteBmp(void) { if(m_hBmp) { DeleteObject(m_hBmp); Initialize(); } } // デストラクタ BmpIO::~BmpIO(void) { DeleteBmp(); } // オブジェクトの代入 // オブジェクトのコピー // const BmpIO *pSource:代入する側のオブジェクト void BmpIO::CopyObject(const BmpIO *pSource) { // 自分は代入される側 DeleteBmp(); // 自分のBMPを削除 if(pSource->m_hdc == NULL) return; // 相手はBMPを持っていない // BITMAPINFO構造体のコピー CopyMemory(&m_bmpInfo,&pSource->m_bmpInfo,sizeof(BITMAPINFO)); // DIBSection作成 m_hBmp=CreateDIBSection(NULL,&m_bmpInfo,DIB_RGB_COLORS,(void**)&m_pPixel,NULL,0); // デバイスコンテキスト作成 HDC hdc=GetDC(NULL); m_hdc=CreateCompatibleDC(hdc); SelectObject(m_hdc,m_hBmp); ReleaseDC(NULL,hdc); BYTE *pPixel=pSource->m_pPixel; m_length=pSource->m_length; DWORD height=pSource->m_bmpInfo.bmiHeader.biHeight; // 画素のコピー CopyMemory(m_pPixel,pPixel,m_length*height); lstrcpy(m_pFile,pSource->m_pFile); lstrcpy(m_pFileTitle,pSource->m_pFileTitle); lstrcpy(m_pErrText,pSource->m_pErrText); } // 代入演算子の再定義 // const BmpIO &source:代入する側のオブジェクト BmpIO& BmpIO::operator =(const BmpIO &source) { if(&source==this) return *this; // 自分自身 CopyObject(&source); return *this; } // エラー処理 // 直前の処理の結果を設定 // const TCHAR *text:エラー文字列 NULLなら成功した void BmpIO::SetLastErr(const TCHAR *text) { if(text) lstrcpy(m_pErrText,text); else m_pErrText[0]=_T('\0'); } // 直前の処理の結果を取得 // 戻り値:エラー文字列 NULLなら成功した const TCHAR* BmpIO::GetLastErr(void) { if(m_pErrText[0]==_T('\0')) return NULL; return m_pErrText; } // 画像ファイル読み込み // [ファイルを開く]ダイアログボックスを作る // 戻り値:ファイル選択をキャンセルしたか bool BmpIO::CreateOpenDialog(HWND hWnd) { OPENFILENAME ofn={0}; // 初期化必須 TCHAR file[MAX_PATH]={0}; // 初期化必須 TCHAR fileTitle[MAX_PATH]={0}; // 初期化必須 static DWORD index=1; ofn.lStructSize=sizeof(OPENFILENAME); ofn.hwndOwner=hWnd; ofn.lpstrFilter=_T("ビットマップ (*.bmp)\0*.bmp\0Truevision Targa (*.tga)\0*.tga\0\0"); ofn.nFilterIndex=index; ofn.lpstrFile=file; // フルパス ofn.nMaxFile=MAX_PATH; ofn.lpstrFileTitle=fileTitle; // タイトル ofn.nMaxFileTitle=MAX_PATH; ofn.Flags=OFN_FILEMUSTEXIST; // 存在するファイルだけ if(GetOpenFileName(&ofn)==FALSE) return false; // キャンセルした index=ofn.nFilterIndex; // 選択されたフィルタのインデックスを保存 lstrcpy(m_pFile,ofn.lpstrFile); lstrcpy(m_pFileTitle,ofn.lpstrFileTitle); return true; } // 拡張子を取得する // TCHAR *pExt:拡張子を取得するバッファ 3文字とは限らない void BmpIO::GetFileExt(TCHAR *pExt) { TCHAR *ext=_tcsrchr(m_pFileTitle,_T('.')); lstrcpy(pExt,ext+1); } // 画像ファイルを読み込む // DIB_BIT bitCount:作成するDIBSectionのビット数 32ビット or 24ビット // const TCHAR *pFilePath:読み込むファイル名 NULLならダイアログから選択 void BmpIO::LoadImage(HWND hWnd,DIB_BIT bitCount,const TCHAR *pFilePath) { SetLastErr(NULL); // ファイル名を設定する if(pFilePath) { lstrcpy(m_pFile,pFilePath); ::GetFileTitle(pFilePath,m_pFileTitle,MAX_PATH); } else // ダイアログから選択する { if(CreateOpenDialog(hWnd)==false) return; // キャンセルした } // ファイルを開く HANDLE fh=CreateFile(m_pFile,GENERIC_READ,0,NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); if(fh==INVALID_HANDLE_VALUE) { SetLastErr(_T("ファイルを開けません")); m_pFile[0]=_T('\0'); m_pFileTitle[0]=_T('\0'); return; } // ファイルの内容すべてをメモリに読み込む DWORD fileSize=GetFileSize(fh,NULL); BYTE *pData=(BYTE*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,fileSize); DWORD readSize; ReadFile(fh,pData,fileSize,&readSize,NULL); CloseHandle(fh); TCHAR ext[8]; GetFileExt(ext); // 拡張子取得 if(lstrcmpi(ext,_T("bmp"))==0) { LoadBmp(pData,bitCount); // BMPファイル読み込み } else if(lstrcmpi(ext,_T("tga"))==0) { LoadTga(pData,bitCount); // TGAファイル読み込み } else { SetLastErr(_T("対応していないファイル形式です")); m_pFile[0]=_T('\0'); m_pFileTitle[0]=_T('\0'); } HeapFree(GetProcessHeap(),0,pData); } // BMPを読み込んでDIBSectionを作る // const BYTE *pData:BMPINFO構造体と画素の先頭アドレス // DIB_BIT bitCount:作成するDIBSectionのビット数 32ビット or 24ビット void BmpIO::LoadBmpData(const BYTE *pData,DIB_BIT bitCount) { SetLastErr(NULL); BITMAPINFO *pBmpInfo=(BITMAPINFO*)pData; BYTE bits=(BYTE)pBmpInfo->bmiHeader.biBitCount; if(bits!=32 && bits!=24 && bits!=8) { SetLastErr(_T("32/24/8 ビット以外のBMPファイルは読み込めません")); m_pFile[0]=_T('\0'); m_pFileTitle[0]=_T('\0'); return; } DeleteBmp(); // 以前のBMPを削除 DWORD colorTables=pBmpInfo->bmiHeader.biClrUsed; if(bits==8 && colorTables==0) colorTables=256; BYTE *pPixel=(BYTE*)pData + sizeof(BITMAPINFOHEADER); if(bits==8) pPixel+=colorTables*sizeof(RGBQUAD); int width=pBmpInfo->bmiHeader.biWidth; int height=pBmpInfo->bmiHeader.biHeight; BYTE bytes=bits/8; // ファイル BYTE byteCount=(BYTE)(bitCount/8); // DIBSection // 横のバイト数を4の倍数に切り上げ int lenSrc; if(width*bytes % 4) lenSrc=width*bytes+(4-(width*bytes % 4)); else lenSrc=width*bytes; int lenDst; if(width*byteCount % 4) lenDst=width*byteCount+(4-(width*byteCount % 4)); else lenDst=width*byteCount; m_length=lenDst; // メンバ変数に保存 CopyMemory(&m_bmpInfo,&pBmpInfo->bmiHeader,sizeof(BITMAPINFOHEADER)); m_bmpInfo.bmiHeader.biBitCount=(WORD)bitCount; // DIBSection作成 m_hBmp=CreateDIBSection(NULL,&m_bmpInfo,DIB_RGB_COLORS,(void**)&m_pPixel,NULL,0); // デバイスコンテキスト作成 HDC hdc=GetDC(NULL); m_hdc=CreateCompatibleDC(hdc); SelectObject(m_hdc,m_hBmp); ReleaseDC(NULL,hdc); int x,y; switch(bits) // ファイルのビット数 ボトムアップで記録されている { case 32: for(y=0;ybmiColors; for(y=0;ybfType!=('M'<<8)+'B') { SetLastErr(_T("不正なBMPファイルです")); m_pFile[0]=_T('\0'); m_pFileTitle[0]=_T('\0'); return; } LoadBmpData(pData+sizeof(BITMAPFILEHEADER),bitCount); } // TGAファイルを読み込んでDIBSectionを作る // const BYTE *pData:ファイルの内容すべてを読み込んだバッファの先頭アドレス // DIB_BIT bitCount:作成するDIBSectionのビット数 32ビット or 24ビット void BmpIO::LoadTga(const BYTE *pData,DIB_BIT bitCount) { SetLastErr(NULL); TGAFILEHEADER *pTgaFH=(TGAFILEHEADER*)pData; BYTE image_type=pTgaFH->image_type; BYTE bits=pTgaFH->pixel_size; if(image_type!=1 && image_type!=2) { SetLastErr(_T("読み込めないTGAファイルです")); m_pFile[0]=_T('\0'); m_pFileTitle[0]=_T('\0'); return; } if(bits!=32 && bits!=24 && bits!=8) { SetLastErr(_T("32/24/8 ビット以外のTGAファイルは読み込めません")); m_pFile[0]=_T('\0'); m_pFileTitle[0]=_T('\0'); return; } if((image_type==1 && bits!=8) || (image_type==2 && bits!=32 && bits!=24)) { SetLastErr(_T("読み込めないTGAファイルです")); m_pFile[0]=_T('\0'); m_pFileTitle[0]=_T('\0'); return; } DeleteBmp(); // 以前のBMPを削除 BYTE color_map_bytes=0,*pColorTable=NULL; BYTE *pPixel=NULL; if(image_type==1) // カラーマップ有り { pColorTable=(BYTE*)pData + 18 + pTgaFH->identification_len; WORD color_map_len=pTgaFH->color_map_len; if(color_map_len==0) color_map_len=256; color_map_bytes=pTgaFH->color_map_size/8; pPixel=pColorTable + color_map_len*color_map_bytes; } else if(image_type==2) // カラーマップ無し { pPixel=(BYTE*)pData + 18 + pTgaFH->identification_len; } int width=pTgaFH->width; int height=pTgaFH->height; BYTE bytes=bits/8; // ファイル BYTE byteCount=(BYTE)(bitCount/8); // DIBSection // TGAは4の倍数に切り上げない int lenSrc=width*bytes; // 横のバイト数を4の倍数に切り上げ int lenDst; if(width*byteCount % 4) lenDst=width*byteCount+(4-(width*byteCount % 4)); else lenDst=width*byteCount; m_length=lenDst; // メンバ変数に保存 m_bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); m_bmpInfo.bmiHeader.biWidth=width; m_bmpInfo.bmiHeader.biHeight=height; m_bmpInfo.bmiHeader.biPlanes=1; m_bmpInfo.bmiHeader.biBitCount=(WORD)bitCount; m_bmpInfo.bmiHeader.biCompression=BI_RGB; // DIBSection作成 m_hBmp=CreateDIBSection(NULL,&m_bmpInfo,DIB_RGB_COLORS,(void**)&m_pPixel,NULL,0); // デバイスコンテキスト作成 HDC hdc=GetDC(NULL); m_hdc=CreateCompatibleDC(hdc); SelectObject(m_hdc,m_hBmp); ReleaseDC(NULL,hdc); int x,y; if(pTgaFH->identification_len) // トップダウンで記録されている { switch(bits) // ファイルのビット数 { case 32: for(y=0;y