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值
具体代码如下:
bmp.h
#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
bmp.c
#include
#include
#include
#include "bmpfile.h"
#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("bf.bfSize = %d\n", bmp.bfSize);
printf("bi.biSize = %d\n", bmp.biSize);
printf("bi.biWidth = %d\n", bmp.biWidth);
printf("bi.biHeight = %d\n", bmp.biHeight);
printf("bi.biBitCount = %d\n", bmp.biBitCount);
printf("bi.bfOffBits = %d\n", bmp.bfOffBits);
// 计算行字节数和总字节数
LineBytes = (uint32_t) WIDTHBYTES(bmp.biWidth * bmp.biBitCount)
; //计算位图的实际宽度并确保它为32的倍数
ImgBytesSize = (uint32_t) LineBytes * bmp.biHeight;
if (bmp.biClrUsed != 0) {
NumColors = (uint32_t) bmp.biClrUsed;
} else {
switch (bmp.biBitCount) {
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 ((bmp.biBitCount != 24) && (bmp.biBitCount != 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 = bmp.biBitCount;
pb->nImgW = bmp.biWidth;
pb->nImgH = bmp.biHeight;
pb->bInit = TRUE;
if ((bmp.biBitCount == 32) || (bmp.biBitCount == 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*) &(bmp.bfType)) = 'B';
*(((char*) &(bmp.bfType)) + 1) = 'M';
bmp.bfReserved1 = 0;
bmp.bfReserved2 = 0;
bmp.bfOffBits = sizeof(BMPFILEHEADER);
bmp.bfSize = pb->nImgW * pb->nImgH * (pb->nBits >> 3) + bmp.bfOffBits;
bmp.biSize = 40;
bmp.biBitCount = pb->nBits;
printf("bi.biBitCount = %d\n", bmp.biBitCount);
bmp.biWidth = pb->nImgW;
bmp.biHeight = pb->nImgH;
bmp.biCompression = 0;
bmp.biPlanes = 1;
bmp.biClrUsed = 0;
fwrite(&bmp, sizeof(BMPFILEHEADER), 1, fp);
if (bmp.biClrUsed != 0) {
NumColors = (uint32_t) bmp.biClrUsed;
} else {
switch (bmp.biBitCount) {
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 ((bmp.biBitCount != 24) && (bmp.biBitCount != 32)) {
ipRGB = (RGBQUAD *) malloc(NumColors * sizeof(RGBQUAD));
fread(ipRGB, sizeof(RGBQUAD), NumColors, fp);
}
if ((bmp.biBitCount != 24) && (bmp.biBitCount != 32)) {
fwrite(ipRGB, sizeof(RGBQUAD), NumColors, fp);
for (i = (bmp.biHeight) - 1; i >= 0; i--) {
fwrite(pb->pData + nLineBytes * i, sizeof(uint8_t), nLineBytes, fp);
}
} else {
for (i = (bmp.biHeight) - 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[] = "./1.bmp";
char filename2[] = "./2.bmp";
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;
}
上面的代码是笔者实现的,不足是肯定有的,下面的代码是老师给的参考代码,可以实现上面的功能,还可以画框。
bmpfile.c:
#include
#include
#include
#include "bmpfile.h"
#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 = header.biWidth;
pb->height = header.biHeight;
pb->stride = ALIGN(header.biWidth * 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; iheight; 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;
header.bfType = ('B' << 0) | ('M' << 8);
header.bfSize = sizeof(header) + pb->stride * pb->height;
header.bfOffBits = sizeof(header);
header.biSize = 40;
header.biWidth = pb->width;
header.biHeight = pb->height;
header.biPlanes = 1;
header.biBitCount = pb->cdepth;
header.biSizeImage= 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; iheight; 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(header.biWidth * 3, 4);
pbyte[x * (pb->cdepth / 8) + 2 + y * pb->stride] = r;//header.biWidth 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= 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
bmpfile.h:
#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