bmp_888
使用场景以及原理
代码示例
语言:C
编译器:Keil5
stm32库:HAL-1.5.x
串口:UART1
//你的屏幕一共有多少像素点
#define BMP_BUFFER (320*240)
//RGB888格式数据结构体,注意在内存中存储是以BGR的顺序(非RGB)
typedef struct {
u8 B;
u8 G;
u8 R;
} bmp_24bit;
/* BMP的信息头文件一共占54个字节,由于保存的是24bit的RGB888像素数据,所以不需要调色板结构体 */
//BMP头文件
typedef __packed struct
{
u16 bfType ; //文件标志.只对'BM',用来识别BMP位图类型
u32 bfSize ; //文件大小,占四个字节
u16 bfReserved1 ;//保留
u16 bfReserved2 ;//保留
u32 bfOffBits ; //从文件开始到位图数据(bitmap data)开始之间的的偏移量
}BITMAPFILEHEADER ;
//BMP信息头
typedef __packed struct
{
u32 biSize ; //说明BITMAPINFOHEADER结构所需要的字数。
long biWidth ; //说明图象的宽度,以象素为单位
long biHeight ; //说明图象的高度,以象素为单位
u16 biPlanes ; //为目标设备说明位面数,其值将总是被设为1
u16 biBitCount ; //说明比特数/象素,其值为1、4、8、16、24、或32
/*说明图象数据压缩的类型。其值可以是下述值之一:
BI_RGB:没有压缩;
BI_RLE8:每个象素8比特的RLE压缩编码,压缩格式由2字节组成(重复象素计数和颜色索引);
BI_RLE4:每个象素4比特的RLE压缩编码,压缩格式由2字节组成
BI_BITFIELDS:每个象素的比特由指定的掩码决定。*/
u32 biCompression ;
u32 biSizeImage ; //说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0
long biXPelsPerMeter ; //说明水平分辨率,用象素/米表示
long biYPelsPerMeter ; //说明垂直分辨率,用象素/米表示
u32 biClrUsed ; //说明位图实际使用的彩色表中的颜色索引数
u32 biClrImportant ; //说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要。
}BITMAPINFOHEADER ;
//整体信息头
typedef __packed struct
{
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bmiHeader;
}BITMAPINFO;
//定义接下来在主函数中使用的头文件变量
BITMAPINFO bmp_head;
//文件系统相关变量
FIL fnew;
FRESULT res_file;
UINT fnum;
int main(void)
{
//省略
LCD_Init(); //初始化LCD
SRAM_Init(); //初始化外部SRAM
//省略
my_mem_init(SRAMIN); //初始化内部内存池
my_mem_init(SRAMEX); //初始化外部内存池
//省略挂载Fatfs,默认SD卡挂载到":0"
//给bmp_data开辟内存空间
bmp_data = (bmp_24bit *)mymalloc(SRAMEX,BMP_BUFFER*sizeof(bmp_24bit));
//填写文件信息头信息
bmp_head.bmfHeader.bfType = 0x4D42; //bmp_head类型 "BM"
bmp_head.bmfHeader.bfSize= sizeof(BITMAPINFO) + BMP_BUFFER*sizeof(bmp_24bit); //文件大小(信息结构体+像素数据)
printf("bfSize = 0x%x \r\n",bmp_head.bmfHeader.bfSize);
bmp_head.bmfHeader.bfReserved1 = 0x0000; //保留,必须为0
bmp_head.bmfHeader.bfReserved2 = 0x0000; //保留,必须为0
bmp_head.bmfHeader.bfOffBits=sizeof(BITMAPINFO); //位图信息结构体所占的字节数
//填写位图信息头信息
bmp_head.bmiHeader.biSize=40; //位图信息头的大小(固定)
bmp_head.bmiHeader.biWidth=240; //位图的宽度
bmp_head.bmiHeader.biHeight=320; //图像的高度
bmp_head.bmiHeader.biPlanes=1; //目标设别的级别,必须是1
bmp_head.bmiHeader.biBitCount=24; //每像素位数
bmp_head.bmiHeader.biCompression=0; //RGB888格式,不用压缩
bmp_head.bmiHeader.biSizeImage= 0; //实际位图所占用的字节数(仅考虑位图像素数据)
bmp_head.bmiHeader.biXPelsPerMeter=0; //水平分辨率
bmp_head.bmiHeader.biYPelsPerMeter=0; //垂直分辨率
bmp_head.bmiHeader.biClrImportant=0; //说明图像显示有重要影响的颜色索引数目,0代表所有的颜色一样重要
bmp_head.bmiHeader.biClrUsed=0; //位图实际使用的彩色表中的颜色索引数,0表示使用所有的调色板项
/*--------------------- 文件系统测试:写测试 -----------------------*/
/* 打开文件,如果文件不存在则创建它 */
printf("》写bmp头文件!\r\n");
res_file = f_open(&fnew, "0:bmp测试.bmp",FA_CREATE_ALWAYS|FA_WRITE);
if(res_file == FR_OK)
{
printf("》正在写bmp头中...!\r\n");
res_file = f_write(&fnew, &bmp_head,sizeof(bmp_head), &fnum);
if(res_file == FR_OK)
{
printf("》文件写入成功,写入字节数据:%d\n",fnum);
}
else
{
printf("!!文件写入失败:(%d)\n",res_file);
}
f_close(&fnew);
}
else
{
printf("!!创建文件失败:(%d)\n",res_file);
}
p_bmp = bmp_data;
//获取LCD显示数据
for(temp_y = 319;temp_y != 0xffff;temp_y --)
{
for(temp_x = 0;temp_x < 240;temp_x ++)
{
rgb_16bit = LCD_ReadPoint(temp_x,temp_y);
p_bmp->R = (u8)((rgb_16bit & 0xF800) >> 8);
p_bmp->G = (u8)((rgb_16bit & 0x07E0) >> 3);
p_bmp->B = (u8)((rgb_16bit & 0x001F) << 3);
//·printf("p_bmp = 0X%x, R = 0X%x, G = 0X%x, B = 0X%x \r\n",(uint32_t )p_bmp, (uint32_t )p_bmp->R, (uint32_t )p_bmp->G, (uint32_t )p_bmp->B);
p_bmp ++;
}
}
//printf("bmp_data = 0X%x, R = 0X%x, G = 0X%x, B = 0X%x \r\n",(uint32_t )bmp_data, (uint32_t )bmp_data->R, (uint32_t )bmp_data->G, (uint32_t )bmp_data->B);
printf("\n\r 》写bmp数据!\r\n");
res_file = f_open(&fnew, "0:bmp测试.bmp",FA_OPEN_EXISTING|FA_WRITE);
if(res_file == FR_OK)
{
//寻找到打开文件的末尾,添加数据
f_lseek(&fnew,f_size(&fnew));
printf("》寻找文件的结尾成功,写入bmp数据中...!\r\n");
//这里注意第二个参数直接填写数组名就可以,默认指向最开始的地址
res_file = f_write(&fnew, bmp_data, BMP_BUFFER*sizeof(bmp_24bit), &fnum);
if(res_file == FR_OK)
{
printf("》文件写入成功,写入字节数据:%d\n",fnum);
}
else
{
printf("!!文件写入失败:(%d)\n",res_file);
}
f_close(&fnew);
}
else
{
printf("!!写入数据失败:(%d)\n",res_file);
}
}
待解决问题
在开辟内存空间bmp_data = (bmp_24bit )mymalloc(SRAMEX,320240*sizeof(bmp_24bit));的时候,如果开辟到SRAMIN的话就会出现错误,但是SRAMEX就没有BUG,待解决。
注意
指向新开辟内存的指针不能动,比如bmp_data,可以设置一个p_bmp,使用这个指针对bmp_data数组进行修改等操作。