C++读写bmp图并显示图像
C++读写bmp图并显示图像预备知识位图文件头位图信息头fopenfseekfreadSetPixel代码运行截图思路&解释注意预备知识位图文件头typedef struct tagBITMAPFILEHEADER {WORD bfType;//文件类型,必须为BM(1-2字节)DWORD bfSize;//文件大小,以字节为单位(3-6字节,低位在前)WORD bfReserved1;/
预备知识
位图文件头
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //文件类型,必须为BM(1-2字节)
DWORD bfSize; //文件大小,以字节为单位(3-6字节,低位在前)
WORD bfReserved1; //保留字,必须为0(7-8字节)
WORD bfReserved2; //保留字,必须为0(9-10字节)
DWORD bfOffBits; //位图数据的起始位置,以相对于位图(11-14字节,低位在前)
} BITMAPFILEHEADER;
位图信息头
typedef struct tagBITMAPINFOHEADER{
DWORD biSize; //本结构所占用字节数(15-18字节)
LONG biWidth; //位图的宽度(19-22字节)
LONG biHeight; //位图的高度(23-26字节)
WORD biPlanes; //目标设备的级别,必须为1(27-28字节)
WORD biBitCount; //每个像素所需的位数,必须是1(双色),4(16色),8(256色)16(高彩色)或24(真彩色)之一(29-30字节)
DWORD biCompression; //位图压缩类型,必须是0(不压缩),1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一(31-34字节)
DWORD biSizeImage; //位图的大小(4字节对齐),以字节为单位(35-38字节)
LONG biXPelsPerMeter;//位图水平分辨率,每米像素数(39-42字节)
LONG biYPelsPerMeter;//位图垂直分辨率,每米像素数(43-46字节)
DWORD biClrUsed; //位图实际使用的颜色表中的颜色数(47-50字节)
DWORD biClrImportant;//位图显示过程中重要的颜色数(51-54字节)
}
fopen
FILE * fopen(const char * path,const char * mode);
path是字符串类型的bmp图片路径;mode读取方式,等下回用到"rb",读写打开一个二进制文件,允许读写数据,文件必须存在。
fseek
int fseek(FILE *stream, long offset, int fromwhere);
函数设置文件指针stream的位置,stream指向以fromwhere为基准,偏移offset个字节的位置。
fread
size_t fread ( void *buffer, size_t size, size_t count, FILE *stream);
从stream中读取count个单位大小为size个字节,存在buffer中。
SetPixel
函数功能:该函数将指定坐标处的像素设为指定的颜色。
函数原型:COLORREF SetPixel(HDC hdc, int X,int Y, COLORREF crColor);
参数:
hdc:设备环境句柄。
X:指定要设置的点的X轴坐标,按逻辑单位表示坐标。
Y:指定要设置的点的Y轴坐标,按逻辑单位表示坐标。
crColor:指定要用来绘制该点的颜色。
返回值:如果函数执行成功,那么返回值就是函数设置像素的RGB颜色值。这个值可能与crColor指定的颜我色有不同,之所以有时发生这种情况是因为没有找到对指定颜色进行真正匹配造成的;如果函数失败,那么返回值是C1。
代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<Windows.h>
using namespace std;
int main()
{
//读取图像文件
FILE* fp = fopen("1.bmp", "rb");//读入的文件
if (!fp) {
cout << "文件未打开!\n";
exit(0);
}
long width, height;
BITMAPFILEHEADER fileHead;//位图文件头
fread(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);//从fp中读取BITMAPFILEHEADER信息到fileHead中,同时fp的指针移动
BITMAPINFOHEADER infoHead;//位图信息头
fread(&infoHead, sizeof(BITMAPINFOHEADER), 1, fp);//从fp中读取BITMAPINFOHEADER信息到infoHead中,同时fp的指针移动
width = infoHead.biWidth;
height = infoHead.biHeight;
cout << "width = " << width << endl << "height = " << height << endl;
char* bmpBuf = new char[width * height * 3];
fseek(fp, long(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)), 0);//定位到起始位置
fread(bmpBuf, sizeof(char), width * height * 3, fp);
fclose(fp);
//写入文件信息
FILE* outFile = fopen("show.bmp", "wb");//输出文件
fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, outFile);
fwrite(&infoHead, sizeof(BITMAPINFOHEADER), 1, outFile);
char* tmp = bmpBuf;
for (int j = 0;j < height;j++)
for (int i = 0;i < width * 3;i++)
fwrite(tmp++, 1, 1, outFile);
fclose(outFile);
//显示图像
HWND hwnd = GetForegroundWindow();//窗口句柄
HDC hdc = GetDC(hwnd);//绘图句柄
BYTE b, g, r, rgb;
tmp = bmpBuf;
for (int j = 0;j < height;j++) {
for (int i = 0;i < width;i++) {
b = *tmp++;
g = *tmp++;
r = *tmp++;
SetPixel(hdc, i, 150 + height - j, RGB(r, g, b));
}
}
}
运行截图
思路&解释
- 使用分别读取图像的位图文件头和位图信息头的数据,其中位图信息头结构中包含图像的宽、高等信息,因此使用biWidth,biHeight来获取图像的宽和高;
- 为bmpBuf分配空间,大小为width * height * 3,因为每一像素由RGB三个分量组成;
- 由于使用fread读取了位图文件头和位图信息头,此时fp也随之偏移,偏移长度即为 sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) ,因此需要使用fseek函数将fp调整到指向初始位置,然后才能将从fp中读取相应数据到bmpBuf中;
- 写文件时使用一个临时变量tmp指向bmpBuf头部,然后依次写入即可,注意每行的数据是 width * 3 个,同样是因为每一像素由RGB三个分量组成;
- 显示图像时使用Windows.h中自带的HWND、HDC数据类型和GetForegroundWindow()、GetDC(HWND hwnd)函数获取窗口和绘图句柄,再调用SetPixel(HDC hdc, int x,int y, COLORREF color)函数进行绘图即可。其中,获取rgb数据时,文件中每一像素中的颜色信息按顺序依次为b ,g ,r。
注意
读取的图片应该是 24位bmp图,否则程序可能无法运行。
有些系统默认保存的bmp图可能不是24位的,只需要在windows系统中自带的「画图」软件中打开图片,然后点击 另存为,选择 24位位图 即可。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)