【VC++】メモリDCに文字と図形を出力してビットマップファイルとして保存する

0

    <機能>

    (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

    VC,VC++,メモリデバイスコンテキスト,ビットマップ,CreateCompatibleDC,CreateCompatibleBitmap,GetDIBits,GetTextExtentPoint32W

     

    <使い方>

    (1)Win32コンソールアプリケーションでプロジェクトを作成

    VC,VC++,メモリデバイスコンテキスト,ビットマップ,CreateCompatibleDC,CreateCompatibleBitmap,GetDIBits,GetTextExtentPoint32W

    (2)アプリケーション設定で「MFC」にチェック

    VC,VC++,メモリデバイスコンテキスト,ビットマップ,CreateCompatibleDC,CreateCompatibleBitmap,GetDIBits,GetTextExtentPoint32W

    (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);
    }


    よろしければポチッと押してください

    プログラマー ブログランキングへ



    selected entries

    categories

    calendar

    S M T W T F S
        123
    45678910
    11121314151617
    18192021222324
    252627282930 
    << November 2018 >>

    profile

    others

    archives