// 以下、ビットマップファイル作成まわりの関数 static WORD _DibNumColors(LPVOID pv) { // With the BITMAPINFO format headers, the size of the palette is in biClrUsed, whereas in the BITMAPCORE - style headers, // it is dependent on the bits per pixel ( = 2 raised to the power of bits/pixel). LPBITMAPINFOHEADER lpbi = ((LPBITMAPINFOHEADER)pv); LPBITMAPCOREHEADER lpbc = ((LPBITMAPCOREHEADER)pv); int bits = 0; if (lpbi->biSize != sizeof(BITMAPCOREHEADER)) { if (lpbi->biClrUsed != 0) { if (0.0 <= lpbi->biClrUsed && lpbi->biClrUsed <= 65535.0) return (WORD)lpbi->biClrUsed; else return(256); } bits = lpbi->biBitCount; } else bits = lpbc->bcBitCount; switch (bits) { case 1: return 2; case 4: return 16; case 8: return 256; default: return 0; // A 24 bitcount DIB has no color table } } static BOOL _CreateDIBPalette(BYTE* lpDibBmp, CPalette& pal) { // BITMAPINFOへのポインタ取得 LPBITMAPINFO lpbmi = NULL; if (!(lpbmi = (LPBITMAPINFO)lpDibBmp)) return FALSE; // BITMAPCOREINFOへのポインタ取得 LPBITMAPCOREINFO lpbmc = (LPBITMAPCOREINFO)lpDibBmp; // DIB 内の色数を取得 BOOL bResult = FALSE; WORD wNumColors = _DibNumColors(lpbmi); if (wNumColors == 0) return bResult; // バージョンおよびパレットのエントリ数を設定 LPLOGPALETTE lpPal = (LPLOGPALETTE)new char[sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * wNumColors]; lpPal->palVersion = 0x300; lpPal->palNumEntries = (WORD)wNumColors; bool blWinStyleDIB = (*(LPDWORD)(lpDibBmp)) == sizeof(BITMAPINFOHEADER) ? true : false; for (int i = 0; i < (int)wNumColors; i++) { if (blWinStyleDIB) { lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed; lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen; lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue; lpPal->palPalEntry[i].peFlags = 0; } else { lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed; lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen; lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue; lpPal->palPalEntry[i].peFlags = 0; } } // パレットを作成してハンドル取得 bResult = pal.CreatePalette(lpPal); delete[] lpPal; return bResult; } static WORD _PaletteSize(LPBITMAPINFOHEADER lpbi) { WORD NumColors; NumColors = _DibNumColors(lpbi); if (lpbi->biSize == sizeof(BITMAPCOREHEADER)) return NumColors * sizeof(RGBTRIPLE); else return NumColors * sizeof(RGBQUAD); } static void _SaveImageFile(HBITMAP hBmp, LPCTSTR filename) { // BITMAP情報を取得する BITMAP bmp = { 0 }; GetObject(hBmp, sizeof(bmp), &bmp); HDC hdc = GetDC(0); HDC hdc_mem = CreateCompatibleDC(hdc); ReleaseDC(0, hdc); HBITMAP hBmpOld = (HBITMAP)SelectObject(hdc_mem, hBmp); // ファイルサイズ計算 LONG imageSize = bmp.bmWidthBytes * bmp.bmHeight + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); LONG bpp; // 画素数 switch (bmp.bmBitsPixel) { case 2: bpp = 2; break; case 4: bpp = 16; break; case 8: bpp = 256; break; default: bpp = 0; } imageSize += (sizeof(RGBQUAD) * bpp); // BITMAPFILEHEADERヘッダー出力 BITMAPFILEHEADER fh; ZeroMemory(&fh, sizeof(fh)); memcpy(&fh.bfType, "BM", 2); fh.bfSize = imageSize; fh.bfReserved1 = 0; fh.bfReserved2 = 0; fh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * bpp; // BITMAPINFOHEADERヘッダー出力 BITMAPINFO* pbi = new BITMAPINFO[sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * bpp]; ZeroMemory(pbi, sizeof(BITMAPINFOHEADER)); pbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbi->bmiHeader.biWidth = bmp.bmWidth; pbi->bmiHeader.biHeight = bmp.bmHeight; pbi->bmiHeader.biPlanes = 1; pbi->bmiHeader.biBitCount = bmp.bmBitsPixel; pbi->bmiHeader.biCompression = BI_RGB; if (bpp != 0) GetDIBColorTable(hdc_mem, 0, bpp, pbi->bmiColors); // 画像データを得る LPBYTE bits = new BYTE[bmp.bmWidthBytes * bmp.bmHeight]; GetDIBits(hdc_mem, hBmp, 0, bmp.bmHeight, bits, pbi, DIB_RGB_COLORS); // ファイルに書き込む HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); DWORD writeSize; // 書き込んだサイズ WriteFile(hFile, &fh, sizeof(fh), &writeSize, NULL); WriteFile(hFile, pbi, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * bpp, &writeSize, NULL); WriteFile(hFile, bits, bmp.bmWidthBytes * bmp.bmHeight, &writeSize, NULL); CloseHandle(hFile); // 開放 delete[] pbi; delete[] bits; SelectObject(hdc_mem, hBmpOld); DeleteDC(hdc_mem); } static bool _WriteBitmap(CDC* pDC, BYTE* lpDibBmp, LPCTSTR pFile) { LPBITMAPINFOHEADER lpbi = NULL; if (!(lpbi = (LPBITMAPINFOHEADER)lpDibBmp)) return false; // パレットがある場合は、パレットを選択する CPalette pal; CPalette* pOldPal = NULL; if (_CreateDIBPalette(lpDibBmp, pal)) { pOldPal = pDC->SelectPalette(&pal, FALSE); pDC->RealizePalette(); } // DDB ビットマップのクリエイト HBITMAP hbm = CreateDIBitmap(pDC->m_hDC, (LPBITMAPINFOHEADER)lpbi, (LONG)CBM_INIT, (LPBYTE)lpbi + lpbi->biSize + _PaletteSize(lpbi), (LPBITMAPINFO)lpbi, DIB_RGB_COLORS); // パレットを元に戻す if (pOldPal) pDC->SelectPalette(pOldPal, FALSE); _SaveImageFile(hbm, pFile); ::DeleteObject(hbm); return true; }