【VC++】メモリDCに文字と図形を出力してビットマップファイルとして保存する
<機能>
(1)下記手順にてメモリデバイスコンテキストにビットマップを割付
・GetDC
・CreateCompatibleDC
・CreateCompatibleBitmap
・SelectObject
(2)メモリデバイスコンテキスト(DC)に文字を出力します
・メイリオのサイズ26でフォントオブジェクトを生成
・文字列をTextOutWにてDCに出力
・横方向中央揃えで出力(GetTextExtentPoint32W)
(3)メモリデバイスコンテキスト(DC)に図形を出力します
・ペンオブジェクトを生成(CreatePen)
・Ellipseで楕円を出力
・Polygonで三角形を出力
(4)下記手順にて2色ビットマップファイルを出力
・イメージデータサイズを取得(幅を4バイト揃え)
・BITMAPFILEHEADERをセット
・BITMAPINFOHEADERをセット
・GetDIBitsにてイメージデータ部をセット
<動作検証&開発環境>
Visual Studio Community 2015
<イメージ>
白:RGB(0xFF,0xFF,0xFF)とピンク:RGB(0xCC,0x00,0x99)の2色ビットマップを作成
サイズは400×300
<使い方>
(1)Win32コンソールアプリケーションでプロジェクトを作成
(2)アプリケーション設定で「MFC」にチェック
(3)プロトタイプ宣言(1~5行)
(4)構造体定義(7~18行)
(5)main()以下を修正&追加
//プロトタイプ宣言
void DrawStringToHDC(HDC hdc, CStringW csw, int iXsize, int iYpos);
HFONT SetFontStyle(const CStringW cfname, int ifsize);
void SetBmpFileHeader(BITMAPFILEHEADER *bmFileh, int imgSize);
void SetBmpInfoHeader(BITMAPINFOHEADER *bmInfoh, int imgSize, int iXsize, int iYsize);
//RGBQUAD構造体配列(本サンプルでは色ビット数=1で作成のため2色)
int Palette[2] = {
0x00CC0099, //本サンプルではRGB(CC,00,99)を指定
0x00FFFFFF,
};
//ビットマップ情報構造体とカラーパレット
//GetDIBitsで使用するBITMAPINFO構造体
struct SCT_BMPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiPalette[2];
};
// 唯一のアプリケーション オブジェクトです。
CWinApp theApp;
using namespace std;
int main()
{
int nRetCode = 0;
HMODULE hModule = ::GetModuleHandle(nullptr);
if (hModule != nullptr)
{
// MFC を初期化して、エラーの場合は結果を印刷します。
if (!AfxWinInit(hModule, nullptr, ::GetCommandLine(), 0))
{
//〜〜省略〜〜
}
else
{
BITMAPFILEHEADER bmFileh;
BITMAPINFOHEADER bmInfoh;
SCT_BMPINFO bmInfo;
FILE *fp;
int iXsize = 400; //画像の幅(Width)
int iYsize = 300; //画像の高さ(Height)
/* 描画対象のデバイスコンテキストを用意 */
//スクリーンのデバイスコンテキストを用意
HDC hdcScreen = GetDC(0);
HDC hdc = CreateCompatibleDC(hdcScreen);
//スクリーンのビットマップを用意(400×300ピクセル)
HBITMAP hBmp = CreateCompatibleBitmap(hdcScreen, iXsize, iYsize);
//スクリーンのデバイスコンテキストにビットマップを割付
HBITMAP hBmpOld = (HBITMAP)SelectObject(hdc, hBmp);
/* デバイスコンテキストに描画を行う */
//フォントオブジェクトを生成
HFONT hFont,hFontOld;
int iFsize = 26;
hFont = SetFontStyle(L"メイリオ", iFsize);
hFontOld = (HFONT)SelectObject(hdc, hFont);
//背景を白で塗りつぶし
RECT rect;
SetRect(&rect, 0, 0, iXsize, iYsize);
FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
//文字を出力する
DrawStringToHDC(hdc, L"メモリデバイスコンテキストに文字を出力します", iXsize,40);
DrawStringToHDC(hdc, L"全角:あいうえお 半角:12345ABCDEカキクケコ", iXsize, 70);
DrawStringToHDC(hdc, L"袋熊(コアラ)海豹(アザラシ)珊瑚(サンゴ)", iXsize, 100);
//図形を出力する
POINT pt[3];
HPEN hPen, hPenOld;
hPen = CreatePen(PS_SOLID, 8, RGB(0xCC, 0, 0x99));
hPenOld = (HPEN)SelectObject(hdc, hPen);
Ellipse(hdc, 50, 150, 180, 270);
pt[0].x = 285;
pt[0].y = 150;
pt[1].x = 220;
pt[1].y = 270;
pt[2].x = 350;
pt[2].y = 270;
Polygon(hdc,pt, 3);
/* ビットマップファイル(色ビット数=1bit)に保存 */
//イメージデータ部のサイズを取得(1画素あたり1bit)
//行単位で4バイト(32ビット)単位に揃えなければならない
int imgSize;
if ((iXsize % 32) == 0) {
//画像の幅が4バイト単位になっているとき
imgSize = iXsize * iYsize;
}
else {
//画像の幅を4バイト単位に揃える
imgSize = ((32 / 8) * ((int)(iXsize / 32) + 1)) * iYsize;
}
//イメージデータ部の格納バッファ
void *lpImgbuf;
lpImgbuf = (void *)malloc(imgSize);
//ビットマップファイルヘッダ(14バイト)に値をセット
SetBmpFileHeader(&bmFileh, imgSize);
//ビットマップ情報ヘッダ(40バイト)に値をセット
SetBmpInfoHeader(&bmInfoh, imgSize, iXsize, iYsize);
//GetDIBitsにてイメージデータを生成
//DIBの原点はビットマップの左下隅
//データはリトルエンディアンにて記録される
bmInfo.bmiHeader = bmInfoh;
memcpy(bmInfo.bmiPalette, Palette, sizeof(Palette));
GetDIBits(hdc, hBmp, 0, iYsize,lpImgbuf, (LPBITMAPINFO)&bmInfo, DIB_RGB_COLORS);
//出力ファイル名の生成(result+年月日時分秒)
CTime ct = CTime::GetCurrentTime();
char cFile[2048];
ZeroMemory(&cFile, sizeof(cFile));
sprintf_s(cFile,".¥¥result_%04d%02d%02d%02d%02d%02d.bmp", ct.GetYear(), ct.GetMonth(), ct.GetDay(), ct.GetHour(), ct.GetMinute(), ct.GetSecond());
//ファイルへ出力
int ierr = fopen_s(&fp, (char*)cFile, "wb");
fwrite(&bmFileh, sizeof(BITMAPFILEHEADER), 1, fp);
fwrite(&bmInfoh, sizeof(BITMAPINFOHEADER), 1, fp);
fwrite(Palette, sizeof(Palette), 1, fp);
fwrite(lpImgbuf, imgSize, 1, fp);
fclose(fp);
//終了処理
DeleteObject(hBmp);
DeleteObject(hFont);
DeleteObject(hPen);
DeleteDC(hdc);
ReleaseDC(0, hdcScreen);
//バッファを解放
free(lpImgbuf);
//終了メッセージ
MessageBox(NULL, L"ビットマップの出力処理が終了しました", L"処理終了", MB_ICONINFORMATION);
}
}
else
{
//〜〜省略〜〜
}
return nRetCode;
}
/*************************************************
関数名 DrawStringToHDC
機能 メモリデバイスコンテキストに文字列を出力
iXsize : 出力画像の幅(Width)
iYpos : 縦方向の出力位置
*************************************************/
void DrawStringToHDC(HDC hdc, CStringW csw, int iXsize,int iYpos)
{
wchar_t wct[512];
SIZE sz;
ZeroMemory(&wct, 512);
wcscpy_s(wct, csw);
//中央に描画する
GetTextExtentPoint32W(hdc, wct, lstrlenW(wct), &sz);
TextOutW(hdc, (iXsize - sz.cx) / 2, iYpos, wct, lstrlenW(wct));
}
/*************************************************
関数名 SetBmpFileHeader
機能 BITMAPFILEHEADER構造体をセット
bmFileh : BITMAPFILEHEADER構造体
imgSize : データ部のサイズ
*************************************************/
void SetBmpFileHeader(BITMAPFILEHEADER *bmFileh, int imgSize)
{
int ofs;
//イメージデータまでのサイズ
//本サンプルでは2色ビットマップ(色ビット数=1)のためカラーパレットは2個
//(参考)色ビット数=4(1画素あたり4ビット)のときパレットは16個
//(参考)色ビット数=8(1画像あたり8ビット)のときパレットは256個
//(参考)色ビット数=24(1画素あたり3バイト)のときパレットなし
//(参考)色ビット数=32(1画素あたり4バイト)のときパレットなし
ofs = sizeof(BITMAPFILEHEADER)
+ sizeof(BITMAPINFOHEADER)
+ sizeof(Palette);
ZeroMemory(bmFileh, sizeof(BITMAPFILEHEADER));
bmFileh->bfType = 0x4D42; //BM
bmFileh->bfSize = ofs + imgSize;
bmFileh->bfOffBits = ofs;
return;
}
/*************************************************
関数名 SetBmpInfoHeader
機能 BITMAPINFOHEADER構造体をセット
bmFileh : BITMAPINFOHEADER構造体
imgSize : データ部のサイズ
iXsize : ビットマップの幅(Width)
iYsize : ビットマップの高さ(Height)
*************************************************/
void SetBmpInfoHeader(BITMAPINFOHEADER *bmInfoh, int imgSize,int iXsize,int iYsize)
{
ZeroMemory(bmInfoh, sizeof(BITMAPINFOHEADER));
bmInfoh->biSize = 40;
bmInfoh->biWidth = iXsize;
bmInfoh->biHeight = iYsize;
bmInfoh->biPlanes = 1;
//色ビット数(biBitCount)について
//1 : 本サンプルでは2色ビットマップのため1をセット
//(参考)4 : 色ビット数=4(1画素あたり4ビット)のとき16色
//(参考)8 : 色ビット数=8(1画像あたり8ビット)のとき256色
//(参考)24: 色ビット数=24(1画素あたり3バイト)のとき1677万色
//(参考)32: 色ビット数=32(1画素あたり4バイト)のとき1677万色
bmInfoh->biBitCount = 1;
bmInfoh->biSizeImage = imgSize;
return;
}
/*************************************************
関数名 SetFontStyle
機能 フォントオブジェクトを生成
https://msdn.microsoft.com/ja-jp/library/2ek64h34.aspx
*************************************************/
HFONT SetFontStyle(const CStringW cfname, int ifsize)
{
LOGFONT lf;
memset(&lf, 0x0, sizeof(LOGFONT));
//フォントの高さを指定
lf.lfHeight = ifsize;
//フォントの文字セット
lf.lfCharSet = DEFAULT_CHARSET;
//希望する出力精度を指定
lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
//希望するクリッピング精度を指定
lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
//フォントの出力品質を指定
lf.lfQuality = DEFAULT_QUALITY;
//フォントのピッチとファミリを指定
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
//フォントのタイプフェイス名を指定
lstrcpy(lf.lfFaceName, (LPCWSTR)cfname);
//LOGFONT 構造体で指定された特性でCFontオブジェクトを初期化する
return CreateFontIndirect(&lf);
}
よろしければポチッと押してください