绘制像素buffer
#ifndef CLASS_BITMAP_H
#define CLASS_BITMAP_H
#include <stdio.h>
#include <windows.h>
class cbitmap
{
public:
cbitmap();
~cbitmap();
public:
// 创建
void create(unsigned width, unsigned height, unsigned bits_per_pixel, unsigned clear_value = 256);
// 销毁
void destroy();
HBITMAP create_dib_section(HDC h_dc, unsigned width, unsigned height, unsigned bits_per_pixel, unsigned clear_value = 256);
// 附加到一个现存的bmp
void attach_to_bmp(BITMAPINFO *bmp);
// 设置像素buf为clear_value
void clear(unsigned clear_value = 256);
// bmp信息
BITMAPINFO* bitmap_info() { return m_bmp; }
// 绘制
void draw(HDC h_dc, const RECT* device_rect = 0, const RECT* bmp_rect = 0) const;
// 绘制
void draw(HDC h_dc, int x, int y, double scale = 1.0) const;
// 像素buf指针
unsigned char* buf();
// 宽
unsigned width() const;
// 高
unsigned height() const;
// 行字节数
int stride() const;
// 像素的字节数 bits_per_pixel
unsigned bpp() const { return m_bits_per_pixel; }
// 辅助的静态函数
public:
// 计算bmp指向的整块内存大小
static unsigned calc_full_size(BITMAPINFO* bmp);
// 信息头+调色板的大小(不包括像素buf部分)
static unsigned calc_header_size(BITMAPINFO *bmp);
// 计算调色板大小
static unsigned calc_palette_size(unsigned clr_used, unsigned bits_per_pixel);
// 计算调色板大小
static unsigned calc_palette_size(BITMAPINFO *bmp);
// 获取像素buf的指针(在bitmap头+调色板之后)
static unsigned char* calc_img_ptr(BITMAPINFO *bmp);
// 创建bitmap信息(后面后面跟随调色板[8位及以下像素才需要调色板],然后跟随rgb_buffer)
static BITMAPINFO* create_bitmap_info(unsigned width, unsigned height, unsigned bits_per_pixel);
// 调色板设置为渐变灰度
static void create_gray_scale_palette(BITMAPINFO *bmp);
// 计算行长度
static unsigned calc_row_len(unsigned width, unsigned bits_per_pixel);
private:
cbitmap(const cbitmap&);
const cbitmap& operator = (const cbitmap&);
void create_from_bmp(BITMAPINFO *bmp);
private:
// 宽高等信息都记录在此结构
BITMAPINFO* m_bmp;
// 像素的buf
unsigned char* m_pixel_buf;
// 像素的位数
unsigned m_bits_per_pixel;
// 代表是否需要释放内存(如果是从外部附加进来的不需要释放)
bool m_is_internal;
// m_buf大小
unsigned m_img_size;
// m_bmp指向的整块内存大小
unsigned m_full_size;
};
#endif
#include "cbitmap.h"
// ------------------------------------------------------------------------
cbitmap::cbitmap()
: m_bmp(0)
, m_pixel_buf(0)
, m_bits_per_pixel(0)
, m_is_internal(false)
, m_img_size(0)
, m_full_size(0)
{
}
// ------------------------------------------------------------------------
cbitmap::~cbitmap()
{
destroy();
}
// 创建
// ------------------------------------------------------------------------
void cbitmap::create(unsigned width, unsigned height, unsigned bits_per_pixel, unsigned clear_value)
{
destroy();
if (width == 0)
{
width = 1;
}
if (height == 0)
{
height = 1;
}
m_bits_per_pixel = bits_per_pixel;
create_from_bmp(create_bitmap_info(width, height, m_bits_per_pixel));
create_gray_scale_palette(m_bmp);
// 代表要释放内存
m_is_internal = true;
// 默认值256代表不要清除内存
if (clear_value <= 255)
{
memset(m_pixel_buf, clear_value, m_img_size);
}
}
// 销毁
// ------------------------------------------------------------------------
void cbitmap::destroy()
{
if (m_bmp && m_is_internal)
{
delete []m_bmp;
m_bmp = 0;
m_is_internal = false;
m_pixel_buf = 0;
}
}
// 设置像素buf为clear_value
// ------------------------------------------------------------------------
void cbitmap::clear(unsigned clear_value)
{
if (m_pixel_buf)
{
memset(m_pixel_buf, clear_value, m_img_size);
}
}
// 附加到一个现存的bmp
// ------------------------------------------------------------------------
void cbitmap::attach_to_bmp(BITMAPINFO *bmp)
{
if (bmp)
{
destroy();
create_from_bmp(bmp);
// 从外部附加进来的,不需要释放内存
m_is_internal = false;
}
}
// 绘制
//------------------------------------------------------------------------
void cbitmap::draw(HDC h_dc, const RECT *device_rect, const RECT *bmp_rect) const
{
if (m_bmp == 0 || m_pixel_buf == 0)
{
return;
}
unsigned bmp_x = 0;
unsigned bmp_y = 0;
unsigned bmp_width = m_bmp->bmiHeader.biWidth;
unsigned bmp_height = m_bmp->bmiHeader.biHeight;
if(bmp_rect)
{
bmp_x = bmp_rect->left;
bmp_y = bmp_rect->top;
bmp_width = bmp_rect->right - bmp_rect->left;
bmp_height = bmp_rect->bottom - bmp_rect->top;
}
unsigned dvc_x = bmp_x;
unsigned dvc_y = bmp_y;
unsigned dvc_width = bmp_width;
unsigned dvc_height = bmp_height;
if (device_rect)
{
dvc_x = device_rect->left;
dvc_y = device_rect->top;
dvc_width = device_rect->right - device_rect->left;
dvc_height = device_rect->bottom - device_rect->top;
}
if (dvc_width != bmp_width || dvc_height != bmp_height)
{
::SetStretchBltMode(h_dc, COLORONCOLOR);
::StretchDIBits(
h_dc, // handle of device context
dvc_x, // x-coordinate of upper-left corner of source rect.
dvc_y, // y-coordinate of upper-left corner of source rect.
dvc_width, // width of source rectangle
dvc_height, // height of source rectangle
bmp_x,
bmp_y, // x, y -coordinates of upper-left corner of dest. rect.
bmp_width, // width of destination rectangle
bmp_height, // height of destination rectangle
m_pixel_buf, // address of bitmap bits
m_bmp, // address of bitmap data
DIB_RGB_COLORS, // usage
SRCCOPY // raster operation code
);
}
else
{
::SetDIBitsToDevice(
h_dc, // handle to device context
dvc_x, // x-coordinate of upper-left corner of
dvc_y, // y-coordinate of upper-left corner of
dvc_width, // source rectangle width
dvc_height, // source rectangle height
bmp_x, // x-coordinate of lower-left corner of
bmp_y, // y-coordinate of lower-left corner of
0, // first scan line in array
bmp_height, // number of scan lines
m_pixel_buf, // address of array with DIB bits
m_bmp, // address of structure with bitmap info.
DIB_RGB_COLORS // RGB or palette indexes
);
}
}
// 绘制
//------------------------------------------------------------------------
void cbitmap::draw(HDC h_dc, int x, int y, double scale) const
{
if (m_bmp == 0 || m_pixel_buf == 0)
{
return;
}
unsigned width = unsigned(m_bmp->bmiHeader.biWidth * scale);
unsigned height = unsigned(m_bmp->bmiHeader.biHeight * scale);
RECT rect;
rect.left = x;
rect.top = y;
rect.right = x + width;
rect.bottom = y + height;
draw(h_dc, &rect);
}
// 像素buf指针
// ------------------------------------------------------------------------
unsigned char* cbitmap::buf()
{
return m_pixel_buf;
}
// 宽
// ------------------------------------------------------------------------
unsigned cbitmap::width() const
{
return m_bmp->bmiHeader.biWidth;
}
// 高
// ------------------------------------------------------------------------
unsigned cbitmap::height() const
{
return m_bmp->bmiHeader.biHeight;
}
// 行字节数
// ------------------------------------------------------------------------
int cbitmap::stride() const
{
return calc_row_len(m_bmp->bmiHeader.biWidth, m_bmp->bmiHeader.biBitCount);
}
// static
// 计算bmp指向的整块内存大小
// ------------------------------------------------------------------------
unsigned cbitmap::calc_full_size(BITMAPINFO *bmp)
{
if (bmp == 0)
{
return 0;
}
return sizeof(BITMAPINFOHEADER) +
sizeof(RGBQUAD) * calc_palette_size(bmp) +
bmp->bmiHeader.biSizeImage;
}
// static
// 信息头+调色板的大小(不包括像素buf部分)
// ------------------------------------------------------------------------
unsigned cbitmap::calc_header_size(BITMAPINFO *bmp)
{
if (bmp == 0)
{
return 0;
}
return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * calc_palette_size(bmp);
}
// static
// 计算调色板大小
// ------------------------------------------------------------------------
unsigned cbitmap::calc_palette_size(unsigned clr_used, unsigned bits_per_pixel)
{
int palette_size = 0;
if(bits_per_pixel <= 8)
{
palette_size = clr_used;
if(palette_size == 0)
{
palette_size = 1 << bits_per_pixel;
}
}
return palette_size;
}
// 计算调色板大小
// ------------------------------------------------------------------------
unsigned cbitmap::calc_palette_size(BITMAPINFO *bmp)
{
if (bmp == 0)
{
return 0;
}
return calc_palette_size(bmp->bmiHeader.biClrUsed, bmp->bmiHeader.biBitCount);
}
//static
// 获取像素buf的指针(在bitmap头+调色板之后)
//------------------------------------------------------------------------
unsigned char * cbitmap::calc_img_ptr(BITMAPINFO *bmp)
{
if (bmp == 0)
{
return 0;
}
return ((unsigned char*)bmp) + calc_header_size(bmp);
}
// static
// 创建bitmap信息(后面后面跟随调色板[8位及以下像素才需要调色板],然后跟随rgb_buffer)
// ------------------------------------------------------------------------
BITMAPINFO* cbitmap::create_bitmap_info(unsigned width, unsigned height, unsigned bits_per_pixel)
{
unsigned rgb_size = calc_palette_size(0, bits_per_pixel) * sizeof(RGBQUAD);
unsigned line_len = calc_row_len(width, bits_per_pixel);
unsigned img_size = line_len * height;
unsigned full_size = sizeof(BITMAPINFOHEADER) + rgb_size + img_size;
// 位图信息,后面后面跟随调色板,然后跟随rgb_buffer
BITMAPINFO *bmp = (BITMAPINFO *) new unsigned char[full_size];
bmp->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmp->bmiHeader.biWidth = width;
bmp->bmiHeader.biHeight = height;
bmp->bmiHeader.biPlanes = 1;
bmp->bmiHeader.biBitCount = (unsigned short)bits_per_pixel;
bmp->bmiHeader.biCompression = 0;
bmp->bmiHeader.biSizeImage = img_size;
bmp->bmiHeader.biXPelsPerMeter = 0;
bmp->bmiHeader.biYPelsPerMeter = 0;
bmp->bmiHeader.biClrUsed = 0;
bmp->bmiHeader.biClrImportant = 0;
return bmp;
}
//------------------------------------------------------------------------
// 调色板设置为渐变灰度
void cbitmap::create_gray_scale_palette(BITMAPINFO *bmp)
{
if (bmp == 0)
{
return;
}
unsigned rgb_size = calc_palette_size(bmp);
RGBQUAD *rgb = (RGBQUAD*)(((unsigned char*)bmp) + sizeof(BITMAPINFOHEADER));
for (unsigned i = 0; i < rgb_size; i++)
{
unsigned brightness = (255 * i) / (rgb_size - 1);
rgb->rgbBlue = rgb->rgbGreen = rgb->rgbRed = (unsigned char)brightness;
rgb->rgbReserved = 0;
rgb++;
}
}
// static
// 计算行长度
// ------------------------------------------------------------------------
unsigned cbitmap::calc_row_len(unsigned width, unsigned bits_per_pixel)
{
unsigned n = width;
unsigned k;
switch (bits_per_pixel)
{
// 一个像素1位,一个字节8个像素,如果有余数,需要多一个字节
case 1:
k = n;
n = n >> 3;
if (k & 7)
{
n++;
}
break;
// 一个像素4位,一个字节2个像素,如果有余数,需要多一个字节
case 4:
k = n;
n = n >> 1;
if (k & 3)
{
n++;
}
break;
// 一个像素8位,像素数就是字节数
case 8:
break;
// 一个像素16位,需要两个字节, 下面类似
case 16: n *= 2; break;
case 24: n *= 3; break;
case 32: n *= 4; break;
case 48: n *= 6; break;
case 64: n *= 8; break;
case 96: n *= 12; break;
case 128: n *= 16; break;
default: n = 0; break;
}
// 4字节对齐
return ((n + 3) >> 2) << 2;
}
// 通过bmp获取相关联的信息
// ------------------------------------------------------------------------
void cbitmap::create_from_bmp(BITMAPINFO *bmp)
{
if (bmp)
{
m_img_size = calc_row_len(bmp->bmiHeader.biWidth, bmp->bmiHeader.biBitCount) * bmp->bmiHeader.biHeight;
m_full_size = calc_full_size(bmp);
m_bmp = bmp;
m_pixel_buf = calc_img_ptr(bmp);
}
}
#pragma comment(lib, "gdi32")
#pragma comment(lib, "user32")
#include <windows.h>
#include "cbitmap.h"
cbitmap g_bmp;
void draw_bmp(HDC h_dc)
{
unsigned char* p = g_bmp.buf();
int size = g_bmp.stride() * g_bmp.height();
for (int i = 0; i < size; i++)
{
p[i] = rand();
}
g_bmp.draw(h_dc, 100, 100);
}
// 窗口过程函数的定义
LRESULT CALLBACK WindowProcedure(HWND h_wnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
switch (msg)
{
case WM_CREATE:
SetTimer(h_wnd, 1, 16, 0);
break;
case WM_TIMER:
if (w_param == 1)
{
InvalidateRect(h_wnd, 0, 0);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(h_wnd, &ps);
draw_bmp(ps.hdc);
EndPaint(h_wnd, &ps);
break;
}
// 当窗口被销毁时发送此消息(例如,用户点击关闭按钮)
case WM_DESTROY:
// 退出消息循环,结束程序
PostQuitMessage(0);
break;
// 如果收到其他消息,可以按需处理,或者调用DefWindowProc函数默认处理该消息
default:
// 默认处理其他消息
return DefWindowProc(h_wnd, msg, w_param, l_param);
}
// 返回值通常为0,表示消息已被处理或默认处理了该消息
return 0;
}
int WINAPI WinMain(HINSTANCE h_instance, HINSTANCE h_prev_instance, LPSTR lp_cmd_line, int n_cmd_show)
{
g_bmp.create(200, 200, 24);
// 注册窗口类
// -----------------------------------------------------------------
WNDCLASS wc = {0};
// 窗口过程函数的地址
wc.lpfnWndProc = WindowProcedure;
// 应用程序实例句柄
wc.hInstance = h_instance;
// 窗口类的名称
wc.lpszClassName = L"SampleWindowClass";
if (!RegisterClass(&wc))
{
MessageBox(NULL, L"窗口类注册失败!", L"错误", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// 创建窗口
HWND h_wnd = CreateWindow(L"SampleWindowClass", L"我的窗口", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 480, NULL, NULL, h_instance, NULL);
if (h_wnd == NULL)
{
MessageBox(NULL, L"窗口创建失败!", L"错误", MB_ICONEXCLAMATION | MB_OK);
return 0;
}
// 显示窗口
ShowWindow(h_wnd, n_cmd_show);
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
// 翻译消息(例如,将键盘消息转换为字符消息)
TranslateMessage(&msg);
// 将消息分发给相应的窗口过程函数处理
DispatchMessage(&msg);
}
// 返回值通常为0,表示程序正常退出
return 0;
}
// cl main.cpp class_bitmap.cpp -utf-8 -DUNICODE -D_UNICODE