kehuadong

绘制像素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

 

posted on 2024-01-16 16:40  kehuadong  阅读(6)  评论(0编辑  收藏  举报

导航