G++でGDI+で描画したAVIファイルを出力するC++


Windowsの描画API GDI+でAVIファイルを出力するC++サンプルです。グラフや数値表示など簡単なグラフィックをC++で作りたい場合にお勧めです。サンプルコードとして見やすいようにファイル選択、エラー処理などは極力省いています。


ファイルはUTF8で保存して以下のコマンドでコンパイル、ビルドしてください。

g++ .\avisample002.cpp -mwindows -lvfw32 -lgdiplus -lmsimg32 -municode -static -o avisample002


  1. #define _UNICODE    //ワイド文字列 (Unicode) 対応
  2. #include <windows.h>
  3. #include <gdiplus.h>
  4. #include <vfw.h>
  5. #include <sstream>
  6. #include <string>
  7. /********************************************************************
  8. GDI+対応版
  9. 実行するとカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
  10. g++ .\avisample002.cpp -mwindows -lvfw32 -lgdiplus -lmsimg32 -municode -static -o avisample002
  11. *********************************************************************/
  12. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
  13. {
  14.     constexpr int width = 1280; //画面サイズフレームレートなどを設定
  15.     constexpr int height = 720;
  16.     constexpr int fps = 5; //フレームレート
  17.     constexpr int frames = 400;
  18.     constexpr int c_thic = 80; //円の厚さ
  19.     constexpr int div = 59; //円を分割する数
  20.     constexpr int size = width < height?width:height; //高さと幅の短い方を選ぶ
  21.     constexpr int marX = (width - size)/2;
  22.     constexpr int marY = (height - size)/2;
  23.     constexpr float step = (float)360 / div; //分割された度数
  24.     constexpr float seg = step / 2; //空白部と実部の割合(数字が大きいほど実部が減る)
  25.     
  26.     //GDI+用変数
  27.     const Gdiplus::GdiplusStartupInput gdiSI;
  28.     ULONG_PTR gdiToken;
  29.     
  30.     Gdiplus::GdiplusStartup(&gdiToken, &gdiSI, NULL); //GDI+を使うための宣言
  31.     const Gdiplus::Font font(L"Segoe UI", 160); //フォントの宣言
  32.     const Gdiplus::RectF RectBK(0,0,width,height); //背景の矩形領域の宣言
  33.     const Gdiplus::RectF RectCircleOut(marX,marY,size,size); //円の外側の矩形領域
  34.     const Gdiplus::RectF RectCircleInner(marX+c_thic,marY+c_thic,size-c_thic*2,size-c_thic*2); //円の内側の矩形領域
  35.     
  36.     Gdiplus::StringFormat format; //文字列のフォーマットの宣言
  37.     format.SetAlignment(Gdiplus::StringAlignmentCenter); // DT_CENTER
  38.     format.SetLineAlignment(Gdiplus::StringAlignmentCenter); // DT_VCENTER
  39.     const Gdiplus::SolidBrush brushFW(Gdiplus::Color(255, 255, 255, 255)); //表の色の宣言
  40.     const Gdiplus::SolidBrush brushBK(Gdiplus::Color(255, 0, 0, 0)); //背景色の宣言
  41.     
  42.     PAVIFILE pfile;
  43.     PAVISTREAM pavi;
  44.     AVISTREAMINFO si;
  45.     const LPAVISTREAMINFO lpsi = &si;
  46.     LPVOID lpBits;
  47.     BITMAPINFOHEADER bmiHeader;    
  48.     
  49.     AVIFileInit();
  50.     if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
  51.         MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
  52.         AVIFileExit();
  53.         return 0;}
  54.     ZeroMemory(&si, sizeof(AVISTREAMINFO));
  55.     si.fccType = streamtypeVIDEO;
  56.     si.fccHandler = comptypeDIB;
  57.     si.dwScale = 1;
  58.     si.dwRate = fps;
  59.     si.dwLength = 0;
  60.     si.dwQuality = (DWORD)-1;
  61.     SetRect(&si.rcFrame, 0, 0, width, height);
  62.     if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
  63.         MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
  64.         AVIFileRelease(pfile);
  65.         AVIFileExit();
  66.         return 0;}
  67.     ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
  68.     bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  69.     bmiHeader.biWidth = lpsi->rcFrame.right;
  70.     bmiHeader.biHeight = lpsi->rcFrame.bottom;
  71.     bmiHeader.biPlanes = 1;
  72.     bmiHeader.biBitCount = 24;
  73.     bmiHeader.biCompression = BI_RGB;
  74.     bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
  75.     AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
  76.     //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
  77.     const HDC hdc = CreateCompatibleDC(NULL);
  78.     const HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
  79.     const HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
  80.     Gdiplus::Graphics hGdip(hdc); //GDI+の宣言
  81.     hGdip.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); //図形のアンチエイリアス
  82.     hGdip.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias); // テキストのアンチエイリアス
  83.     
  84.     SetBkMode(hdc, TRANSPARENT);
  85.     
  86.     bool isTop = true; //裏表フラグ
  87.     for (int fCnt = 0; fCnt < frames; fCnt++) {
  88.         hGdip.FillRectangle(&brushBK,RectBK); //背景を塗りつぶす
  89.         std::wstringstream wss; //カウンターの数字を文字列に変換
  90.         wss << fCnt;
  91.         std::wstring buf = wss.str();
  92.         const int l_begin = isTop?0:fCnt%(div+1);
  93.         const int l_end = isTop?fCnt%(div+1):div;
  94.         for (int j = l_begin;j<l_end;j++){
  95.             
  96.             Gdiplus::GraphicsPath path; //描画パスを宣言する
  97.             
  98.          path.AddArc(RectCircleOut,step*j, seg); //外周をパスに追加する
  99.          path.AddArc(RectCircleInner, step*j+seg, -seg); //内周をパスに追加
  100.             path.CloseFigure(); //パスを閉じる
  101.          hGdip.FillPath(&brushFW, &path); //パスを塗りつぶす
  102.     
  103.         }
  104.         hGdip.DrawString(buf.c_str(), -1, &font, RectCircleOut, &format, &brushFW); //文字を表示する
  105.         
  106.         AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
  107.         
  108.         if(fCnt%(div+1) == div){
  109.             isTop = !isTop; //裏表逆転
  110.         }
  111.     }
  112.     SelectObject(hdc, hbmpMemPrev);
  113.     DeleteObject(hbmpMem);
  114.     DeleteDC(hdc);
  115.     AVIStreamRelease(pavi);
  116.     AVIFileRelease(pfile);
  117.     AVIFileExit();
  118.     Gdiplus::GdiplusShutdown(gdiToken);
  119.     MessageBox(NULL, L"Done.", L"OK", MB_OK);
  120.     return 0;
  121. }

G++でGDI+で描画したAVIファイルを出力するC++

Windowsの描画API GDI+でAVIファイルを出力するC++サンプルです。グラフや数値表示など簡単なグラフィックをC++で作りたい場合にお勧めです。サンプルコードとして見やすいようにファイル選択、エラー処理などは極力省いています。 ファイルはUTF8で保存して以下のコマン...