Skip to content

Instantly share code, notes, and snippets.

@hotwatermorning
Last active August 29, 2015 14:16
Show Gist options
  • Save hotwatermorning/fcc674dc4e56dac9b365 to your computer and use it in GitHub Desktop.
Save hotwatermorning/fcc674dc4e56dac9b365 to your computer and use it in GitHub Desktop.
Draw bitmap image to memory
// DrawBitmap.cpp
// バイト列にビットマップデータを書き込んでウィンドウに表示。
#include <cassert>
#include <cstdint>
#include <algorithm>
#include <memory>
#define WIN32_LEAN_AND_MEAN // Windows ヘッダーから使用されていない部分を除外します。
// Windows ヘッダー ファイル:
#include <windows.h>
#include <tchar.h>
// グローバル変数:
HINSTANCE hInst; // 現在のインターフェイス
TCHAR szTitle[] = L"BITMAP_TEST_WINDOW"; // タイトル バーのテキスト
TCHAR szWindowClass[] = L"BITMAP_TEST_WINDOW_CLASS"; // メイン ウィンドウ クラス名
// このコード モジュールに含まれる関数の宣言を転送します:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
MSG msg;
MyRegisterClass(hInstance);
// アプリケーションの初期化を実行します:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
// メイン メッセージ ループ:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
//
// 関数: MyRegisterClass()
//
// 目的: ウィンドウ クラスを登録します。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
return RegisterClassEx(&wcex);
}
//
// 関数: InitInstance(HINSTANCE, int)
//
// 目的: インスタンス ハンドルを保存して、メイン ウィンドウを作成します。
//
// コメント:
//
// この関数で、グローバル変数でインスタンス ハンドルを保存し、
// メイン プログラム ウィンドウを作成および表示します。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // グローバル変数にインスタンス処理を格納します。
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
int x = GetLastError();
assert(x == 0);
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
int const bitmap_height = 300;
int const bitmap_width = 400;
HWND src_window;
HDC back_dc;
HBITMAP old_bitmap;
BITMAPINFO bitmap_info;
std::unique_ptr<std::int32_t[]> bitmap_data;
void SetupBitmap(HWND hWnd, int cx, int cy);
void CleanupBitmap();
void UpdateBitmap(std::int32_t *data, int cx, int cy);
int interval_millisec = 10;
//
// 関数: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// 目的: メイン ウィンドウのメッセージを処理します。
//
// WM_COMMAND - アプリケーション メニューの処理
// WM_PAINT - メイン ウィンドウの描画
// WM_DESTROY - 中止メッセージを表示して戻る
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE: {
SetupBitmap(hWnd, bitmap_width, bitmap_height);
SetTimer(hWnd, 0, interval_millisec, NULL);
UpdateWindow(hWnd);
UpdateBitmap(bitmap_data.get(), bitmap_width, bitmap_height);
return 0;
}
case WM_TIMER: {
UpdateBitmap(bitmap_data.get(), bitmap_width, bitmap_height);
InvalidateRect(hWnd, NULL, FALSE);
break;
}
case WM_COMMAND: {
int wmId, wmEvent;
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// 選択されたメニューの解析:
switch (wmId)
{
case 0:
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd, &rc);
StretchDIBits(hdc, 0, 0, rc.right, rc.bottom, 0, 0, bitmap_width, bitmap_height, bitmap_data.get(), &bitmap_info, DIB_RGB_COLORS, SRCCOPY);
EndPaint(hWnd, &ps);
break;
}
case WM_DESTROY: {
KillTimer(hWnd, 0);
CleanupBitmap();
PostQuitMessage(0);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
//======================================================================
// Color functions
//======================================================================
struct RGBColor
{
double r_;
double g_;
double b_;
RGBColor(double r, double g, double b)
: r_(r)
, g_(g)
, b_(b)
{}
};
struct HSVColor
{
double hue_;
double saturation_;
double brightness_;
HSVColor(double hue, double saturation, double brightness)
: hue_(hue)
, saturation_(saturation)
, brightness_(brightness)
{}
};
RGBColor HSVToRGB(double hue, double saturation, double brightness)
{
assert(0 <= hue && hue <= 1.0);
assert(0 <= saturation && saturation <= 1.0);
assert(0 <= brightness && brightness <= 1.0);
double r = brightness;
double g = brightness;
double b = brightness;
if (saturation > 0.0f) {
hue *= 6.0f;
int const i = (int)hue;
double const f = hue - (float)i;
switch (i) {
default:
case 0:
g *= 1 - saturation * (1 - f);
b *= 1 - saturation;
break;
case 1:
r *= 1 - saturation * f;
b *= 1 - saturation;
break;
case 2:
r *= 1 - saturation;
b *= 1 - saturation * (1 - f);
break;
case 3:
r *= 1 - saturation;
g *= 1 - saturation * f;
break;
case 4:
r *= 1 - saturation * (1 - f);
g *= 1 - saturation;
break;
case 5:
g *= 1 - saturation;
b *= 1 - saturation * f;
break;
}
}
return RGBColor(r, g, b);
}
HSVColor RGBToHSV(double r, double g, double b)
{
assert(0 <= r && r <= 1.0);
assert(0 <= g && g <= 1.0);
assert(0 <= b && b <= 1.0);
double max = r > g ? r : g;
max = max > b ? max : b;
double min = r < g ? r : g;
min = min < b ? min : b;
double h = max - min;
if (h > 0.0f) {
if (max == r) {
h = (g - b) / h;
if (h < 0.0f) {
h += 6.0f;
}
} else if (max == g) {
h = 2.0f + (b - r) / h;
} else {
h = 4.0f + (r - g) / h;
}
}
h /= 6.0f;
double s = (max - min);
if (max != 0.0f)
s /= max;
double v = max;
return HSVColor(h, s, v);
}
RGBColor HSVToRGB(HSVColor const &c)
{
return HSVToRGB(c.hue_, c.saturation_, c.brightness_);
}
HSVColor RGBToHSV(RGBColor const &c)
{
return RGBToHSV(c.r_, c.g_, c.b_);
}
//======================================================================
// Bitmap functions
//======================================================================
void SetupBitmap(HWND hWnd, int cx, int cy)
{
src_window = hWnd;
HDC dc = GetDC(src_window);
back_dc = CreateCompatibleDC(dc);
HBITMAP back_bitmap = CreateCompatibleBitmap(dc, bitmap_width, bitmap_height);
bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmap_info.bmiHeader.biWidth = cx;
bitmap_info.bmiHeader.biHeight = cy;
bitmap_info.bmiHeader.biPlanes = 1;
bitmap_info.bmiHeader.biBitCount = 32;
bitmap_info.bmiHeader.biCompression = BI_RGB;
bitmap_data = std::make_unique<std::int32_t[]>(cx * cy);
GetDIBits(dc, back_bitmap, 0, cy, bitmap_data.get(), &bitmap_info, DIB_RGB_COLORS);
old_bitmap = (HBITMAP)SelectObject(back_dc, back_bitmap);
DeleteObject(back_bitmap);
ReleaseDC(src_window, dc);
}
void CleanupBitmap()
{
SelectObject(back_dc, old_bitmap);
ReleaseDC(src_window, back_dc);
}
void UpdateBitmap(std::int32_t *bitmap, int cx, int cy)
{
for(int y = 0; y < cy; ++y) {
for(int x = 0; x < cx; ++x) {
double hue = (x + y * cx) / (double)(cx * cy - 1);
auto rgb = HSVToRGB(hue, 1.0, 1.0);
int r = std::min<int>(static_cast<int>(rgb.r_ * 256), 255);
int g = std::min<int>(static_cast<int>(rgb.g_ * 256), 255);
int b = std::min<int>(static_cast<int>(rgb.b_ * 256), 255);
bitmap[x + y * cx] = r * (1 << 16) + g * (1 << 8) + b * (1 << 0);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment