1、bitmap格式分析
参考文件夹里:bitmap格式分析.htm
https://blog.51cto.com/redwolf/229096
1)位图文件(*.BMP)的格式
int 2字节 DWORD 4字节
LONG 4字节 WORD 2字节
以某bmp文件信息为例:
这里我们需要注意的是:
图片信息的第一个数据对应的是LCD左下角第一个像素,第二个数据对应的是左下角第一个像素的右边。(从左往右存完第一行, 再往上的从左往右存第
二行)
所以,LCD上第一个像素应该去图片信息的左下角提取。
2)实现加载
1、加载文件头
2、加载位图信息头
3、行对齐(由于Windows在进行行扫描的时候最小的单位为4个字节)
4、加载图片数据
5、绘制
2、编写代码
在render目录里建立format文件夹
在inlude里创建pic_operation.h
1)pic_operation.h
#ifndef _PIC_OPERATION_H
#define _PIC_OPERATION_H
typedef struct PixelDatas {
int iWidth;
int iHeight;
int iBpp;
int iLineBytes;
unsigned char *aucPixelDatas;
}T_PixelDatas, *PT_PixelDatas;
typedef struct PicFileParser {
char *name;
int (*isSupport)(unsigned char *aFileHead);
int (*GetPixelDatas)(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas);
int (*FreePixelDatas)(PT_PixelDatas ptPixelDatas);//释放内存
}T_PicFileParser, *PT_PicFileParser;
#endif /* _PIC_OPERATION_H */
2)bitmap.c
注意结构体的字节对齐
#pragma pack(push) /* 将当前pack设置压栈保存*/
#pragma pack(1) /*必须在结构体定义之前使用 */
#pragma pack(pop) /*恢复先前的pack设置 */
#include <config.h>
#include <pic_operation.h>
#include <stdlib.h>
#include <string.h>
#pragma pack(push) /* 将当前pack设置压栈保存 */
#pragma pack(1) /* 必须在结构体定义之前使用 */
为什么要压栈呢? 因为结构体要字节对齐,所以 sizeof(BITMAPFILEHEADER)) 为16字节,然而我们文件信息头为14字节。
typedef struct tagBITMAPFILEHEADER { /* bmfh */
unsigned short bfType;
unsigned long bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned long bfOffBits;
} BITMAPFILEHEADER;
typedef struct tagBITMAPINFOHEADER { /* bmih */
unsigned long biSize;
unsigned long biWidth;
unsigned long biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned long biCompression;
unsigned long biSizeImage;
unsigned long biXPelsPerMeter;
unsigned long biYPelsPerMeter;
unsigned long biClrUsed;
unsigned long biClrImportant;
} BITMAPINFOHEADER;
#pragma pack(pop) /* 恢复先前的pack设置 */
static int isBMPFormat(unsigned char *aFileHead);
static int GetPixelDatasFrmBMP(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas);
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas);
T_PicFileParser g_tBMPParser = {
.name = "bmp",
.isSupport = isBMPFormat,
.GetPixelDatas = GetPixelDatasFrmBMP,
.FreePixelDatas = FreePixelDatasForBMP,
};
static int isBMPFormat(unsigned char *aFileHead)
{
if (aFileHead[0] != 0x42 || aFileHead[1] != 0x4d)
return 0;
else
return 1;
}
static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
unsigned int dwRed;
unsigned int dwGreen;
unsigned int dwBlue;
unsigned int dwColor;
unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
unsigned int *pwDstDatas32bpp = (unsigned int *)pudDstDatas;
int i;
int pos = 0;
if (iSrcBpp != 24)
{
return -1;
}
if (iDstBpp == 24)
{
memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
}
else
{
for (i = 0; i < iWidth; i++)
{
dwBlue = pudSrcDatas[pos++];
dwGreen = pudSrcDatas[pos++];
dwRed = pudSrcDatas[pos++];
if (iDstBpp == 32)
{
dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue;
*pwDstDatas32bpp = dwColor;
pwDstDatas32bpp++;
}
else if (iDstBpp == 16)
{
/* 565 */
dwRed = dwRed >> 3;
dwGreen = dwGreen >> 2;
dwBlue = dwBlue >> 3;
dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue);
*pwDstDatas16bpp = dwColor;
pwDstDatas16bpp++;
}
}
}
return 0;
}
/*
* ptPixelDatas->iBpp 是输入的参数, 它决定从BMP得到的数据要转换为该格式
*/
static int GetPixelDatasFrmBMP(unsigned char *aFileHead, PT_PixelDatas ptPixelDatas)
{
BITMAPFILEHEADER *ptBITMAPFILEHEADER;
BITMAPINFOHEADER *ptBITMAPINFOHEADER;
int iWidth;
int iHeight;
int iBMPBpp;
int y;
unsigned char *pucSrc;
unsigned char *pucDest;
int iLineWidthAlign;
int iLineWidthReal;
//1、加载文件信息头
ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead;
//2、加载位图信息头
ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER));
iWidth = ptBITMAPINFOHEADER->biWidth;
iHeight = ptBITMAPINFOHEADER->biHeight;
iBMPBpp = ptBITMAPINFOHEADER->biBitCount;
if (iBMPBpp != 24)
{
DBG_PRINTF("iBMPBpp = %d\n", iBMPBpp);
DBG_PRINTF("sizeof(BITMAPFILEHEADER) = %d\n", sizeof(BITMAPFILEHEADER));
return -1;
}
ptPixelDatas->iWidth = iWidth;
ptPixelDatas->iHeight = iHeight;
//ptPixelDatas->iBpp = iBpp;
ptPixelDatas->aucPixelDatas = malloc(iWidth * iHeight * ptPixelDatas->iBpp / 8);
ptPixelDatas->iLineBytes = iWidth * ptPixelDatas->iBpp / 8;
if (NULL == ptPixelDatas->aucPixelDatas)
{
return -1;
}
//由于Windows在进行行扫描的时候最小的单位为4个字节,所以当
//图片宽 X 每个像素的字节数 != 4的整数倍时要在每行的后面补上缺少的字节,以0填充
iLineWidthReal = iWidth * iBMPBpp / 8;
iLineWidthAlign = (iLineWidthReal + 3) & ~0x3; /* 向4 向上取整 */ /* 与上 ~0x3 的意思是把低两位去掉 */
//因为图片的左下角的对应的是LCD左上角
pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits; //指向图片的第一个像素
pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign; //指向图片左下角
pucDest = ptPixelDatas->aucPixelDatas;
//一行一行赋值
for (y = 0; y < iHeight; y++)
{
//memcpy(pucDest, pucSrc, iLineWidthReal);不能直接用memset是因为LCD和bmp的 bpp可能不一样
CovertOneLine(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest);
pucSrc -= iLineWidthAlign;
pucDest += ptPixelDatas->iLineBytes;
}
return 0;
}
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{
free(ptPixelDatas->aucPixelDatas);
return 0;
}