【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))

            {

                // TODO: 必要に応じてエラー コードを変更してください。

                wprintf(L"致命的なエラー: MFC の初期化ができませんでした。¥n");

                nRetCode = 1;

            }

            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

        {

            // TODO: 必要に応じてエラー コードを変更してください。

            wprintf(L"致命的なエラー: GetModuleHandle が失敗しました¥n");

            nRetCode = 1;

        }

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

    }

     

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

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



    calendar

    S M T W T F S
    1234567
    891011121314
    15161718192021
    22232425262728
    293031    
    << October 2017 >>

    profile

    others

    mobile

    qrcode