Windowsの描画API GDI+でAVIファイルを出力するC++サンプルです。グラフや数値表示など簡単なグラフィックをC++で作りたい場合にお勧めです。サンプルコードとして見やすいようにファイル選択、エラー処理などは極力省いています。
ファイルはUTF8で保存して以下のコマンドでコンパイル、ビルドしてください。
g++ .\avisample002.cpp -mwindows -lvfw32 -lgdiplus -lmsimg32 -municode -static -o avisample002
- #define _UNICODE //ワイド文字列 (Unicode) 対応
- #include <windows.h>
- #include <gdiplus.h>
- #include <vfw.h>
- #include <sstream>
- #include <string>
- /********************************************************************
- GDI+対応版
- 実行するとカウントアップするAVI動画を作成します。以下のコマンドラインでビルドしてください。
- g++ .\avisample002.cpp -mwindows -lvfw32 -lgdiplus -lmsimg32 -municode -static -o avisample002
- *********************************************************************/
- int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hinstPrev, LPWSTR lpszCmdLine, int nCmdShow)
- {
- constexpr int width = 1280; //画面サイズフレームレートなどを設定
- constexpr int height = 720;
- constexpr int fps = 5; //フレームレート
- constexpr int frames = 400;
- constexpr int c_thic = 80; //円の厚さ
- constexpr int div = 59; //円を分割する数
- constexpr int size = width < height?width:height; //高さと幅の短い方を選ぶ
- constexpr int marX = (width - size)/2;
- constexpr int marY = (height - size)/2;
- constexpr float step = (float)360 / div; //分割された度数
- constexpr float seg = step / 2; //空白部と実部の割合(数字が大きいほど実部が減る)
- //GDI+用変数
- const Gdiplus::GdiplusStartupInput gdiSI;
- ULONG_PTR gdiToken;
- Gdiplus::GdiplusStartup(&gdiToken, &gdiSI, NULL); //GDI+を使うための宣言
- const Gdiplus::Font font(L"Segoe UI", 160); //フォントの宣言
- const Gdiplus::RectF RectBK(0,0,width,height); //背景の矩形領域の宣言
- const Gdiplus::RectF RectCircleOut(marX,marY,size,size); //円の外側の矩形領域
- const Gdiplus::RectF RectCircleInner(marX+c_thic,marY+c_thic,size-c_thic*2,size-c_thic*2); //円の内側の矩形領域
- Gdiplus::StringFormat format; //文字列のフォーマットの宣言
- format.SetAlignment(Gdiplus::StringAlignmentCenter); // DT_CENTER
- format.SetLineAlignment(Gdiplus::StringAlignmentCenter); // DT_VCENTER
- const Gdiplus::SolidBrush brushFW(Gdiplus::Color(255, 255, 255, 255)); //表の色の宣言
- const Gdiplus::SolidBrush brushBK(Gdiplus::Color(255, 0, 0, 0)); //背景色の宣言
- PAVIFILE pfile;
- PAVISTREAM pavi;
- AVISTREAMINFO si;
- const LPAVISTREAMINFO lpsi = &si;
- LPVOID lpBits;
- BITMAPINFOHEADER bmiHeader;
- AVIFileInit();
- if (AVIFileOpen(&pfile, L"video.avi", OF_CREATE | OF_WRITE, NULL) != 0) {
- MessageBox(NULL, L"Fail file open.", L"OK", MB_OK);
- AVIFileExit();
- return 0;}
- ZeroMemory(&si, sizeof(AVISTREAMINFO));
- si.fccType = streamtypeVIDEO;
- si.fccHandler = comptypeDIB;
- si.dwScale = 1;
- si.dwRate = fps;
- si.dwLength = 0;
- si.dwQuality = (DWORD)-1;
- SetRect(&si.rcFrame, 0, 0, width, height);
- if (AVIFileCreateStream(pfile, &pavi, &si) != 0) {
- MessageBox(NULL, TEXT("Fail open stream."), TEXT("OK"), MB_OK);
- AVIFileRelease(pfile);
- AVIFileExit();
- return 0;}
- ZeroMemory(&bmiHeader, sizeof(BITMAPINFOHEADER));
- bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bmiHeader.biWidth = lpsi->rcFrame.right;
- bmiHeader.biHeight = lpsi->rcFrame.bottom;
- bmiHeader.biPlanes = 1;
- bmiHeader.biBitCount = 24;
- bmiHeader.biCompression = BI_RGB;
- bmiHeader.biSizeImage = bmiHeader.biHeight * ((3 * bmiHeader.biWidth + 3) / 4) * 4;
- AVIStreamSetFormat(pavi, 0, &bmiHeader, sizeof(BITMAPINFOHEADER));
- //ここにHDCへ描画し、AVIStreamWriteを呼び出し一コマ書き出す。これを繰り返す。
- const HDC hdc = CreateCompatibleDC(NULL);
- const HBITMAP hbmpMem = CreateDIBSection(NULL, (LPBITMAPINFO)&bmiHeader, DIB_RGB_COLORS, &lpBits, NULL, 0);
- const HBITMAP hbmpMemPrev = (HBITMAP)SelectObject(hdc, hbmpMem);
- Gdiplus::Graphics hGdip(hdc); //GDI+の宣言
- hGdip.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); //図形のアンチエイリアス
- hGdip.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAlias); // テキストのアンチエイリアス
- SetBkMode(hdc, TRANSPARENT);
- bool isTop = true; //裏表フラグ
- for (int fCnt = 0; fCnt < frames; fCnt++) {
- hGdip.FillRectangle(&brushBK,RectBK); //背景を塗りつぶす
- std::wstringstream wss; //カウンターの数字を文字列に変換
- wss << fCnt;
- std::wstring buf = wss.str();
- const int l_begin = isTop?0:fCnt%(div+1);
- const int l_end = isTop?fCnt%(div+1):div;
- for (int j = l_begin;j<l_end;j++){
- Gdiplus::GraphicsPath path; //描画パスを宣言する
- path.AddArc(RectCircleOut,step*j, seg); //外周をパスに追加する
- path.AddArc(RectCircleInner, step*j+seg, -seg); //内周をパスに追加
- path.CloseFigure(); //パスを閉じる
- hGdip.FillPath(&brushFW, &path); //パスを塗りつぶす
- }
- hGdip.DrawString(buf.c_str(), -1, &font, RectCircleOut, &format, &brushFW); //文字を表示する
- AVIStreamWrite(pavi, fCnt, 1, lpBits, bmiHeader.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); //一コマ書き出し
- if(fCnt%(div+1) == div){
- isTop = !isTop; //裏表逆転
- }
- }
- SelectObject(hdc, hbmpMemPrev);
- DeleteObject(hbmpMem);
- DeleteDC(hdc);
- AVIStreamRelease(pavi);
- AVIFileRelease(pfile);
- AVIFileExit();
- Gdiplus::GdiplusShutdown(gdiToken);
- MessageBox(NULL, L"Done.", L"OK", MB_OK);
- return 0;
- }