スポンサーリンク

SkiaのSkBitmap::setPixelsで自分で管理しているメモリをSkBitmapに設定して描画

SkBitmapは、SetPixels関数を使うと書き込む先のメモリを自分で管理している者に設定することができる。

以下はWin32APIのDIBSectionを指定してSkia経由で描画した例。

// Skiaがminmaxを使用するので、Windowsと一緒に使う場合はNOMINMAXを定義
#define NOMINMAX

#include <Windows.h>
#include <tchar.h>

// skia
#include "include/core/SkCanvas.h"
#include "include/core/SkBitmap.h"

// DIB Sectionに設定するピクセルの構造体
struct rgbu_t {
  unsigned char b;
  unsigned char g;
  unsigned char r;
  unsigned char u;// unused
  rgbu_t(unsigned char R, unsigned char G, unsigned char B) :b(B), g(G), r(R) {}
  static const rgbu_t White;
  static const rgbu_t Black;
};

// DIBSectionを作成する関数
void createDIBsection32(
  HBITMAP* hBitmap,
  HDC* hMemDC,
  BITMAPINFO* bmpInfo,
  rgbu_t** m_lpPixel,
  LONG width,
  LONG height)
{
  //DIBの情報を設定する
  bmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  bmpInfo->bmiHeader.biWidth = width;
  bmpInfo->bmiHeader.biHeight = -height; //-を指定しないと上下逆になる
  bmpInfo->bmiHeader.biPlanes = 1;
  bmpInfo->bmiHeader.biBitCount = 32;
  bmpInfo->bmiHeader.biCompression = BI_RGB;

  HDC hdc = CreateDC(_T("DISPLAY"), 0, 0, 0);

  *hBitmap = CreateDIBSection(hdc, bmpInfo, DIB_RGB_COLORS, (void**)m_lpPixel, NULL, 0);
  *hMemDC = CreateCompatibleDC(hdc);

  DeleteDC(hdc);

  SelectObject(*hMemDC, *hBitmap);

}

// DIBSectionを削除する関数
void deleteDIBsection32(HDC hMemDC, HBITMAP hBitmap) {
  DeleteDC(hMemDC);
  DeleteObject(hBitmap);
}

// DIBSectionの情報
HBITMAP dib_hBitmap;
HDC dib_hMemDC;
BITMAPINFO dib_bmpInfo;
rgbu_t* dib_lpPixel;

LRESULT
CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; RECT rect; static int width; static int height; static SkBitmap skbitmap; switch (msg) { case WM_CREATE: GetClientRect(hwnd, &rect); //DIB Sectionを作成(32Bit) createDIBsection32( &dib_hBitmap, &dib_hMemDC, &dib_bmpInfo, &dib_lpPixel, rect.right, rect.bottom ); width = rect.right; height = rect.bottom; // dib_lpPixel 経由でDIBSectionを赤で塗りつぶす for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { dib_lpPixel[y * width + x] = rgbu_t(0, 0, 255); } }
 
    {
      skbitmap.setInfo(SkImageInfo::MakeN32Premul(width, height));
      // SkiaのBitmapにDIBSectionの情報を設定
      skbitmap.setPixels(dib_lpPixel);
      SkCanvas canvas(skbitmap);

      // 図形の描画
      SkPaint paint;
      paint.setStyle(SkPaint::kStroke_Style);
      paint.setStrokeWidth(5);
      paint.setColor(SK_ColorRED);
      canvas.drawCircle(200, 200, 100, paint);
    }
    break;
  case WM_PAINT:
  {

    // 画像を表示
    PAINTSTRUCT ps;
    HDC hDC = BeginPaint(hwnd, &ps);

    BitBlt(hDC, 0, 0, width, height, dib_hMemDC, 0, 0, SRCCOPY);


    EndPaint(hwnd, &ps);

    break;
  }
  case WM_DESTROY:
    deleteDIBsection32(dib_hMemDC, dib_hBitmap);
    PostQuitMessage(0);
    return 0;
  case WM_LBUTTONDOWN:
    hdc = GetDC(hwnd);
    ReleaseDC(hwnd, hdc);
    return 0;
  }
  return DefWindowProc(hwnd, msg, wp, lp);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  PSTR lpCmdLine, int nCmdShow) {
  HWND hwnd;
  WNDCLASS winc;
  MSG msg;

  winc.style = CS_HREDRAW | CS_VREDRAW;
  winc.lpfnWndProc = WndProc;
  winc.cbClsExtra = winc.cbWndExtra = 0;
  winc.hInstance = hInstance;
  winc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  winc.hCursor = LoadCursor(NULL, IDC_ARROW);
  winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  winc.lpszMenuName = NULL;
  winc.lpszClassName = TEXT("SZL_WINDOW");

  if (!RegisterClass(&winc)) return 0;

  hwnd = CreateWindow(
    TEXT("SZL_WINDOW"), TEXT("szl window"),
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    CW_USEDEFAULT, CW_USEDEFAULT,
    600, 400,
    NULL, NULL,
    hInstance, NULL
  );

  if (hwnd == NULL) return 0;

  while (GetMessage(&msg, NULL, 0, 0)) DispatchMessage(&msg);
  return msg.wParam;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: