bmp文件信息头、文件头结构体:
#pragma pack(1)
typedef struct {
uint16_t bfType;//位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为'BM'
uint32_t bfSize;//BMP图像文件的大小
uint16_t bfReserved1;//总为0
uint16_t bfReserved2;//总为0
uint32_t bfOffBits;//BMP图像数据的地址 54
uint32_t biSize;//本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节
uint32_t biWidth;// BMP图像的宽度,单位像素
uint32_t biHeight;//总为0
uint16_t biPlanes;//总为0
uint16_t biBitCount;//BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
uint32_t biCompression;//压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
uint32_t biSizeImage;// BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
uint32_t biXPelsPerMeter;//水平分辨率,单位像素/m
uint32_t biYPelsPerMeter;//垂直分辨率,单位像素/m
uint32_t biClrUsed;//BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
uint32_t biClrImportant;//重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
} BMPFILEHEADER, *bmpFileHead;
#pragma pack()
注意上面要使用内存对齐#pragma pack(1) #pragma pack()
代码封装了五个接口函数:
int bmp_load(BMP *pb, char *file);//读取图片
int bmp_save(BMP *pb, char *file);//存储图片
void bmp_free(BMP *pb);//清除内存
void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b);//画点
void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b);//获取点的rgb值
具体代码如下:
#ifndef __BMPFILE_H__
#define __BMPFILE_H__
typedef unsigned short int uint16_t;
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#define TRUE 1
typedef struct{
uint8_t *pData; // 图像数据
int nImgW; // 图像宽度
int nImgH; // 图像高度
int nBits; // 1,4,8,24,32
char bInit; // 是否已进行初始化,TRUE:已初始化。不能直接用指针来判断pData是否已初始化,因为pData的初始值不为NULL
// 也不能用(!bInit)来判断是否初始化,必须用(TRUE!=bInit)
} BMP;
int bmp_load(BMP *pb, char *file);
int bmp_save(BMP *pb, char *file);
void bmp_free(BMP *pb);
void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b);
void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b);
#endif
#include <>
#include <>
#include <>
#include ""
#define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4);
#pragma pack(1)
typedef struct {
uint16_t bfType;//位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为'BM'
uint32_t bfSize;//BMP图像文件的大小
uint16_t bfReserved1;//总为0
uint16_t bfReserved2;//总为0
uint32_t bfOffBits;//BMP图像数据的地址 54
uint32_t biSize;//本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节
uint32_t biWidth;// BMP图像的宽度,单位像素
uint32_t biHeight;//总为0
uint16_t biPlanes;//总为0
uint16_t biBitCount;//BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
uint32_t biCompression;//压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
uint32_t biSizeImage;// BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
uint32_t biXPelsPerMeter;//水平分辨率,单位像素/m
uint32_t biYPelsPerMeter;//垂直分辨率,单位像素/m
uint32_t biClrUsed;//BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
uint32_t biClrImportant;//重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
} BMPFILEHEADER, *bmpFileHead;
typedef struct tagRGBQUAD {
uint8_t rgbBlue;
uint8_t rgbGreen;
uint8_t rgbRed;
uint8_t rgbReserved;
} RGBQUAD, *PRGB;
#pragma pack()
int bmp_load(BMP *pb, char *file){
BMPFILEHEADER bmp; //BMP文件头 信息头结构体
FILE* fp; //指向文件的指针
RGBQUAD *ipRGB = NULL;
uint32_t LineBytes; // 每行的字节数
uint32_t ImgBytesSize; // 图像总字节数
uint32_t NumColors;
int i;
// 先释放图像空间
if (pb->bInit == TRUE) {
free(pb->pData);
}
pb->pData = NULL;
// 打开文件
fp = fopen(file, "rb");
if (fp == NULL) {
printf("fopen error\n");
return -1;
}
//读取信息头、文件头
//把指针fp所指向的文件的头信息写入bf(地址)
if (fread(&bmp, sizeof(BMPFILEHEADER), 1, fp) == 0)
{
printf("fread error\n");
}
printf(" = %d\n", );
printf(" = %d\n", );
printf(" = %d\n", );
printf(" = %d\n", );
printf(" = %d\n", );
printf(" = %d\n", );
// 计算行字节数和总字节数
LineBytes = (uint32_t) WIDTHBYTES( * )
; //计算位图的实际宽度并确保它为32的倍数
ImgBytesSize = (uint32_t) LineBytes * ;
if ( != 0) {
NumColors = (uint32_t) ;
} else {
switch () {
case 1:
NumColors = 2;
break;
case 4:
NumColors = 16;
break;
case 8:
NumColors = 256;
break;
case 24:
NumColors = 0;
break;
case 32:
NumColors = 0;
break;
}
}
//分配调色板内存
if (( != 24) && ( != 32)) {
ipRGB = (RGBQUAD *) malloc(NumColors * sizeof(RGBQUAD));
fread(ipRGB, sizeof(RGBQUAD), NumColors, fp);
}
// 初始化图像bi
printf("ImgBytesSize = %d\n", ImgBytesSize); //2430000
pb->pData = (uint8_t*) malloc(sizeof(uint8_t) * ImgBytesSize); // 分配图像内存, 外部释放
if (pb->pData == NULL) {
free(ipRGB);
return -1;
}
pb->nBits = ;
pb->nImgW = ;
pb->nImgH = ;
pb->bInit = TRUE;
if (( == 32) || ( == 24)) {
//fseek(fp, 4, SEEK_CUR); //SEEK_CUR:表示文件的相对当前位置
for (i = pb->nImgH - 1; i >= 0; --i) {
fread(pb->pData + i * LineBytes, 1, LineBytes, fp);
}
} else {
for (i = pb->nImgH - 1; i >= 0; --i) {
fread(pb->pData + i * LineBytes, 1, LineBytes, fp);
}
}
fclose(fp);
fp = NULL;
free(ipRGB);
return 0;
}
int bmp_save(BMP *pb, char *file) {
BMPFILEHEADER bmp; //BMP文件头 信息头结构体
RGBQUAD *ipRGB = NULL;
uint32_t NumColors;
int i;
uint32_t nLineBytes = (uint32_t) WIDTHBYTES(pb->nImgW * pb->nBits);
FILE* fp = NULL;
if ((!file) || (TRUE != pb->bInit)) {
return -1;
}
// 写入另一个文件
fp = fopen(file, "wb");
memset(&bmp, 0, sizeof(bmp));
*((char*) &()) = 'B';
*(((char*) &()) + 1) = 'M';
bmp.bfReserved1 = 0;
bmp.bfReserved2 = 0;
= sizeof(BMPFILEHEADER);
= pb->nImgW * pb->nImgH * (pb->nBits >> 3) + ;
= 40;
= pb->nBits;
printf(" = %d\n", );
= pb->nImgW;
= pb->nImgH;
= 0;
= 1;
= 0;
fwrite(&bmp, sizeof(BMPFILEHEADER), 1, fp);
if ( != 0) {
NumColors = (uint32_t) ;
} else {
switch () {
case 1:
NumColors = 2;
break;
case 4:
NumColors = 16;
break;
case 8:
NumColors = 256;
break;
case 24:
NumColors = 0;
break;
case 32:
NumColors = 0;
break;
}
}
//分配调色板内存
if (( != 24) && ( != 32)) {
ipRGB = (RGBQUAD *) malloc(NumColors * sizeof(RGBQUAD));
fread(ipRGB, sizeof(RGBQUAD), NumColors, fp);
}
if (( != 24) && ( != 32)) {
fwrite(ipRGB, sizeof(RGBQUAD), NumColors, fp);
for (i = () - 1; i >= 0; i--) {
fwrite(pb->pData + nLineBytes * i, sizeof(uint8_t), nLineBytes, fp);
}
} else {
for (i = () - 1; i >= 0; i--) {
fwrite(pb->pData + nLineBytes * i, sizeof(uint8_t), nLineBytes,fp);
}
}
fclose(fp);
fp = NULL;
free(ipRGB);
return 0;
}
void bmp_free(BMP *pb){
if (pb != NULL) {
free(pb);
pb = NULL;
}
}
void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b) {
pb->pData[y * pb->nImgW * 3 + x * 3 + 0] = b;
pb->pData[y * pb->nImgW * 3 + x * 3 + 1] = g;
pb->pData[y * pb->nImgW * 3 + x * 3 + 2] = r;
}
void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b) {
*b = pb->pData[y * pb->nImgW * 3 + x * 3 + 0];
*g = pb->pData[y * pb->nImgW * 3 + x * 3 + 1];
*r = pb->pData[y * pb->nImgW * 3 + x * 3 + 2];
}
int main(void) {
char filename1[] = "./";
char filename2[] = "./";
BMP* pmi = (BMP *) malloc(sizeof(BMP));
if(pmi == NULL){
printf("malloc error\n");
}
if ((bmp_load((BMP *)&pmi,filename1)) < 0) {
printf("bmp_load error\n");
}
//测试画点
for (int y = 50; y < 60; y++) {
for (int x = 50; x < 100; x++) {
bmp_setpixel((BMP *)&pmi, x, y, 0, 0, 255);
}
}
if ((bmp_save((BMP *)&pmi,filename2)) < 0) {
printf("bmp_save error\n");
}
bmp_free(pmi);
return EXIT_SUCCESS;
}
上面的代码是笔者实现的,不足是肯定有的,下面的代码是老师给的参考代码,可以实现上面的功能,还可以画框。
:
#include <>
#include <>
#include <>
#include ""
#define ALIGN(a, b) (((a) + (b) - 1) & ~((b) - 1))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define _TEST2_ 1
//++ for bmp file ++//
// 内部类型定义
#pragma pack(1)
//typedef struct {
// uint16_t bfType;
// uint32_t bfSize;
// uint16_t bfReserved1;
// uint16_t bfReserved2;
// uint32_t bfOffBits;
// uint32_t biSize;
// uint32_t biWidth;
// uint32_t biHeight;
// uint16_t biPlanes;
// uint16_t biBitCount;
// uint32_t biCompression;
// uint32_t biSizeImage;
// uint32_t biXPelsPerMeter;
// uint32_t biYPelsPerMeter;
// uint32_t biClrUsed;
// uint32_t biClrImportant;
//} BMPFILEHEADER;
typedef struct {
uint16_t bfType;//位图类别,根据不同的操作系统而不同,在Windows中,此字段的值总为'BM'
uint32_t bfSize;//BMP图像文件的大小
uint16_t bfReserved1;//总为0
uint16_t bfReserved2;//总为0
uint32_t bfOffBits;//BMP图像数据的地址 54
uint32_t biSize;//本结构的大小,根据不同的操作系统而不同,在Windows中,此字段的值总为28h字节=40字节
uint32_t biWidth;// BMP图像的宽度,单位像素
uint32_t biHeight;//总为0
uint16_t biPlanes;//总为0
uint16_t biBitCount;//BMP图像的色深,即一个像素用多少位表示,常见有1、4、8、16、24和32,分别对应单色、16色、256色、16位高彩色、24位真彩色和32位增强型真彩色
uint32_t biCompression;//压缩方式,0表示不压缩,1表示RLE8压缩,2表示RLE4压缩,3表示每个像素值由指定的掩码决定
uint32_t biSizeImage;// BMP图像数据大小,必须是4的倍数,图像数据大小不是4的倍数时用0填充补足
uint32_t biXPelsPerMeter;//水平分辨率,单位像素/m
uint32_t biYPelsPerMeter;//垂直分辨率,单位像素/m
uint32_t biClrUsed;//BMP图像使用的颜色,0表示使用全部颜色,对于256色位图来说,此值为100h=256
uint32_t biClrImportant;//重要的颜色数,此值为0时所有颜色都重要,对于使用调色板的BMP图像来说,当显卡不能够显示所有颜色时,此值将辅助驱动程序显示颜色
} BMPFILEHEADER, *bmpFileHead;
#pragma pack()
/* 函数实现 */
int bmp_load(BMP *pb, char *file)
{
BMPFILEHEADER header = {0};
FILE *fp = NULL;
uint8_t *pdata = NULL;
int i;
fp = fopen(file, "rb");
if (!fp) return -1;
fread(&header, sizeof(header), 1, fp);
pb->width = ;
pb->height = ;
pb->stride = ALIGN( * 3, 4);//琛屽瓧鑺傛暟pb->stride
//鍦?4浣峛mp鍥句腑锛屼竴涓儚绱犳槸涓€涓偣锛岃€屼竴涓儚绱犳湁24浣嶏紝鍗?涓瓧鑺傘€?
pb->cdepth = 24;
pb->pdata = malloc(pb->stride * pb->height);
if (pb->pdata) {
pdata = (uint8_t*)pb->pdata + pb->stride * pb->height;//鎸囧悜鏈€鍚庝竴琛?
for (i=0; i<pb->height; i++) {
pdata -= pb->stride;//鍚戜笂
fread(pdata, pb->stride, 1, fp);//鎸夎璇诲彇
}
}
fclose(fp);
return pb->pdata ? 0 : -1;
}
int bmp_create(BMP *pb)
{
pb->stride = ALIGN(pb->width * (pb->cdepth / 8), 4);
//鍍忕礌閫氬父鐢ㄦ潵琛ㄧず浣嶅浘涓殑涓€涓偣銆備竴涓瓧鑺傚寘鍚?涓瘮鐗癸紝
//鍦ㄥ鏉備竴浜涚殑浣嶅浘锛堜緥濡?4浣嶇湡褰╄壊BMP锛夛紝涓€涓儚绱犵敱涓変釜瀛楄妭鏋勬垚锛屾瘡涓瓧鑺傚垎鍒〃绀?56绉嶇姸鎬佺殑绾€佺豢銆佽摑銆傝繖鏍峰彲浠ヨ〃鐜扮浉褰撲赴瀵岀殑鑹插僵銆?
pb->pdata = calloc(1, pb->width * pb->stride);
return pb->pdata ? 0 : -1;
}
int bmp_save(BMP *pb, char *file)
{
BMPFILEHEADER header = {0};
FILE *fp = NULL;
uint8_t *pdata;
int i;
= ('B' << 0) | ('M' << 8);
= sizeof(header) + pb->stride * pb->height;
= sizeof(header);
= 40;
= pb->width;
= pb->height;
= 1;
= pb->cdepth;
= pb->stride * pb->height;
fp = fopen(file, "wb");
if (fp) {
fwrite(&header, sizeof(header), 1, fp);
pdata = (uint8_t*)pb->pdata + pb->stride * pb->height;
for (i=0; i<pb->height; i++) {
pdata -= pb->stride;
fwrite(pdata, pb->stride, 1, fp);//鎸夎鍐欏叆
}
fclose(fp);
}
return fp ? 0 : -1;
}
void bmp_free(BMP *pb)
{
if (pb->pdata) {
free(pb->pdata);
pb->pdata = NULL;
}
pb->width = 0;
pb->height = 0;
pb->stride = 0;
pb->cdepth = 0;
}
void bmp_setpixel(BMP *pb, int x, int y, int r, int g, int b)//x,y琛ㄧず鍦ㄥ摢涓儚绱犵偣
{
uint8_t *pbyte = pb->pdata;
if (x < 0 || y < 0 || x >= pb->width || y >= pb->height) return;
// r = r < 0 ? 0 : r < 255 ? r : 255;
// g = g < 0 ? 0 : g < 255 ? g : 255;
// b = b < 0 ? 0 : b < 255 ? b : 255;
pbyte[x * (pb->cdepth / 8) + 0 + y * pb->stride] = b;//pb->cdepth鍍忕礌浣嶆暟 pb->cdepth = 24;x鏄儚绱犵偣鐨勬í鍧愭爣锛?4浣峛mp涓竴涓儚绱犵偣涓変釜瀛楄妭銆?
pbyte[x * (pb->cdepth / 8) + 1 + y * pb->stride] = g;//pb->stride 琛屽瓧鑺傛暟 pb->stride = ALIGN( * 3, 4);
pbyte[x * (pb->cdepth / 8) + 2 + y * pb->stride] = r;// BMP鍥惧儚鐨勫搴︼紝鍗曚綅鍍忕礌
void bmp_getpixel(BMP *pb, int x, int y, int *r, int *g, int *b)
{
uint8_t *pbyte = pb->pdata;
if (x < 0 || y < 0 || x >= pb->width || y >= pb->height) { *r = *g = *b = 0; return; }
*b = pbyte[x * (pb->cdepth / 8) + 0 + y * pb->stride];
*g = pbyte[x * (pb->cdepth / 8) + 1 + y * pb->stride];
*r = pbyte[x * (pb->cdepth / 8) + 2 + y * pb->stride];
}
void bmp_dotmatrix(BMP *pb, int x, int y, int r, int g, int b, char *matrix, int mw, int mh)
{
int i;
mw = ALIGN(mw, 8);
for (i=0; i<mw * mh; i++) {
if (matrix[i / 8] & (1 << (7 - i % 8))) bmp_setpixel(pb, x + i % mw, y + i / mw, r, g, b);
}
}
void bmp_drawtext(BMP *pb, int x, int y, int r, int g, int b, char *text, char *ascfont, int ascw, int asch, char *hzfont, int hzw, int hzh)
{
FILE *fpasc = fopen(ascfont, "rb");
FILE *fphz = fopen(hzfont , "rb");
int szasc = ALIGN(ascw, 8) * asch / 8;
int szhz = ALIGN(hzw , 8) * hzh / 8;
int cx = x, cy = y, dx, mw, mh;
char *matbuf= malloc(MAX(szhz, szasc));
if (!matbuf) {
printf("bmp_drawtext failed to allocate buffer !\n");
return;
}
while (*text) {
if (text[0] == '\n') {
cx = x;
cy += MAX(asch, hzh) + hzh / 4;
text++; continue;
} else if ((uint8_t)text[0] < 0xA1) {
mw = ascw, mh = asch, dx = ascw;
if (fpasc) {
fseek(fpasc, *text * szasc, SEEK_SET);
fread(matbuf, 1, szasc, fpasc);
} else goto next;
} else {
mw = hzw , mh = hzh , dx = hzw;
if (text[1] == '\0') break;
else if (fphz && (uint8_t)text[1] >= 0xA1) {
int qm = (uint8_t)text[0] - 0xA1, wm = (uint8_t)text[1] - 0xA1;
fseek(fphz, (qm * 94 + wm) * szhz, SEEK_SET);
fread(matbuf, 1, szhz, fphz);
text++;
} else goto next;
}
bmp_dotmatrix(pb, cx, cy + MAX(asch, hzh) - mh, r, g, b, matbuf, mw, mh);
next: cx += dx, text++;
}
if (fpasc) fclose(fpasc);
if (fphz ) fclose(fphz );
free(matbuf);
}
void bmp_fillrect(BMP *pb, int x, int y, int w, int h, int r, int g, int b, int alpha)
{
int fr = r, fg = g, fb = b, br, bg, bb, i, j;
for (i=0; i<h; i++) {
for (j=0; j<w; j++) {
if (alpha) {
bmp_getpixel(pb, x + j, y + i, &br, &bg, &bb);
fr = r + alpha * (br - r) / 255;
fg = g + alpha * (bg - g) / 255;
fb = b + alpha * (bb - b) / 255;
}
bmp_setpixel(pb, x + j, y + i, fr, fg, fb);
}
}
}
void bmp_bitblt(BMP *pbdst, int dstx, int dsty, BMP *pbsrc, int srcx, int srcy, int w, int h)
{
int r, g, b, i, j;
for (i=0; i<h; i++) {
for (j=0; j<h; j++) {
bmp_getpixel(pbsrc,srcx + j, srcy + i, &r, &g, &b);
bmp_setpixel(pbdst, dstx + j, dstx + i, r, g, b);
}
}
}
#if _TEST1_
int main(int argc, char *argv[])
{
BMP bmp24 = {};
BMP bmp32 = {};
int x, y, r, g, b;
char file[256];
if (argc < 2) {
printf("\n");
printf("tool for convert 24bit bitmap to 32bit\n\n");
printf("usage:\n");
printf(" bmp24to32 bmpfile \n\n");
return 0;
}
bmp_load(&bmp24, argv[1]);
= ;
= ;
= 32;
bmp_create(&bmp32);
for (y=0; y<; y++) {
for (x=0; x<; x++) {
bmp_getpixel(&bmp24, x, y, &r, &g, &b);
bmp_setpixel(&bmp32, x, y, r, g, b);
}
}
snprintf(file, sizeof(file), "%s.32", argv[1]);
bmp_save(&bmp32, file);
bmp_free(&bmp24);
bmp_free(&bmp32);
}
#endif
#if _TEST2_
int main(void)
{
BMP bmp1 = {0}, bmp2 = {0};
bmp_load(&bmp1, "");
bmp_load(&bmp2, "" );
bmp_bitblt (&bmp1, 20, 20, &bmp2, 0, 0, , );
bmp_fillrect(&bmp1, 200, 150, 300, 80, 0, 0, 255, 120);
bmp_drawtext(&bmp1, 220, 160, 255, 255, 255, "hello 中英文混合文本输出\n中英文混合文本输出 hello", "", 8, 14, "", 16, 16);
bmp_save(&bmp1, "");
bmp_free(&bmp1);
bmp_free(&bmp2);
return 0;
}
#endif
:
#ifndef __BMPFILE_H__
#define __BMPFILE_H__
/* BMP 对象的类型定义 */
typedef struct {
int width; /* 宽度 */
int height; /* 高度 */
int stride; /* 行字节数 */
int cdepth; /* 像素位数 */
void *pdata; /* 指向数据 */
} BMP;
int bmp_load(BMP *pb, char *file);
int bmp_save(BMP *pb, char *file);
void bmp_free(BMP *pb);
void bmp_setpixel (BMP *pb, int x, int y, int r, int g, int b);
void bmp_getpixel (BMP *pb, int x, int y, int *r, int *g, int *b);
void bmp_dotmatrix(BMP *pb, int x, int y, int r, int g, int b, char *matrix, int mw, int mh);
void bmp_drawtext (BMP *pb, int x, int y, int r, int g, int b, char *text, char *ascfont, int ascw, int asch, char *hzfont, int hzw, int hzh);
void bmp_fillrect (BMP *pb, int x, int y, int w, int h, int r, int g, int b, int alpha);
void bmp_bitblt (BMP *pbdst, int dstx, int dsty, BMP *pbsrc, int srcx, int srcy, int w, int h);
#endif