1、首先需要了解BMP文件的结构
生成的BMP为32位真彩色图像(一个像素4个字节BGRA),所以不需要调色板。
2、还需要了解的是HSB和RGB的转换公式
3、程序代码
1、bmp.h
#pragma once
#include <string>
typedef long LONG;
typedef unsigned long DWORD;
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef BYTE *LPBYTE;
typedef DWORD *LPDWORD;
#pragma pack(1)
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 文件类型,必须是0x424D,即字符“BM”
DWORD bfSize; // 文件大小
WORD bfReserved1; // 保留字
WORD bfReserved2; // 保留字
DWORD bfOffBits; // 从文件头到实际位图数据的偏移字节数
}BITMAPFILEHEADER; // 位图文件头定义
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // 信息头大小
LONG biWidth; // 图像宽度
LONG biHeight; // 图像高度
WORD biPlanes; // 位平面数,必须为1
WORD biBitCount; // 每像素位数: 1, 2, 4, 8, 16, 24, 32
DWORD biCompression; // 压缩类型
DWORD biSizeImage; // 压缩图像大小字节数
LONG biXPelsPerMeter; // 水平分辨率
LONG biYPelsPerMeter; // 垂直分辨率
DWORD biClrUsed; // 位图实际用到的色彩数
DWORD biClrImportant; // 本位图中重要的色彩数
}BITMAPINFOHEADER; // 位图信息头定义
#pragma pack()
// class BMP
//
// BMP is an image file format that stores bitmap digital images and retains
// information for each pixel of the image. The BMP format stores color data
// for each pixel in the image without any compression. For example, a 10x10
// pixel BMP image will include color data for 100 pixels. This method of
// storing image information allows for crisp, high-quality graphics, but
// also produces large file sizes.
class BMP
{
public:
BMP();
~BMP();
public:
void save(const std::string &location);
void draw(const float bright);
private:
BITMAPFILEHEADER *head;
BITMAPINFOHEADER *info;
BYTE *pixels; // iamge pixel data
}; /* end for class BMP */
2、bmp.cpp
#include <iostream>
#include <fstream>
#include "bmp.h"
BMP::BMP()
{
head = NULL;
info = NULL;
pixels = NULL;
}
BMP::~BMP()
{
if (pixels != NULL)
delete[] pixels;
if (info != NULL)
delete info;
if (head != NULL)
delete head;
}
void BMP::draw(const float bright)
{
head = new BITMAPFILEHEADER;
info = new BITMAPINFOHEADER;
head = new BITMAPFILEHEADER;
info = new BITMAPINFOHEADER;
head->bfType = 0x4D42; //从低位往高位读,反过来了
head->bfSize = 432054; //总字节数
head->bfReserved1 = 0;
head->bfReserved2 = 0;
head->bfOffBits = 54;
info->biSize = 40;
info->biWidth = 360;
info->biHeight = 300;
info->biPlanes = 1;
info->biBitCount = 32;
info->biCompression = 0;
info->biSizeImage = 432000; //360*300*4
info->biXPelsPerMeter = 0;
info->biYPelsPerMeter = 0;
info->biClrUsed = 0;
info->biClrImportant = 0;
unsigned long size = info->biWidth * info->biHeight * 4;
pixels = new BYTE[size];
auto p = pixels;
for (int s=0;s<300;s++) //先绘制底部的像素,所以饱和度由小变大
{
for (int h=0;h<360;h++)
{
BYTE r, g, b;
if (h >= 0 && h < 60)
{
r = BYTE(255 * bright);
b = BYTE((1 - s / 300.0)*r);
g = BYTE(h*(r - b) / 60.0 + b);
}
else if (h >= 60&&h<120)
{
g = BYTE(255 * bright);
b = BYTE((1 - s / 300.0)*g);
r = BYTE((120 - h)*(g - b) / 60.0 + b);
}
else if (h>=120&&h<180)
{
g = BYTE(255 * bright);
r = BYTE((1 - s / 300.0)*g);
b = BYTE((h - 120)*(g - r) / 60.0 + r);
}
else if (h >= 180 && h < 240)
{
b = BYTE(255 * bright);
r = BYTE((1 - s / 300.0)*b);
g = BYTE((240 - h)*(b - r) / 60.0 + r);
}
else if (h >= 240 && h < 300)
{
b = BYTE(255 * bright);
g = BYTE((1 - s / 300.0)*b);
r = BYTE((h-240)*(b - g) / 60.0 + g);
}
else if (h >= 300 && h < 360)
{
r = BYTE(255 * bright);
g = BYTE((1 - s / 300.0)*r);
b = BYTE((360 - h)*(r - g) / 60.0 + g);
}
*p = b;
p++;
*p = g;
p++;
*p = r;
p++;
*p = 0;
p++;
}
}
}
void BMP::save(const std::string &location)
{
std::ofstream file(location, std::ios::binary);
if (!file)
{
std::cout << "Failed to open or create bitmap file." << std::endl;
return;
}
if (head == NULL || info == NULL || pixels == NULL)
{
std::cout << "Failed to save bitmap file." << std::endl;
return;
}
file.write((char*)head, sizeof(BITMAPFILEHEADER));
file.write((char*)info, sizeof(BITMAPINFOHEADER));
file.write((char*)pixels, info->biWidth * info->biHeight * 4);
}
3、main.cpp
#include"bmp.h"
int main()
{
BMP bmp;
bmp.draw(0.5);
bmp.save("0.5.bmp");
bmp.draw(0.8);
bmp.save("0.8.bmp");
bmp.draw(1.0);
bmp.save("1.0.bmp");
return 0;
}
4、最终结果
0.5.bmp
0.8.bmp
1.0.bmp