在CodeBlocks搭建SDL2工程虚拟TFT彩屏解码带压缩形式的Bitmap BMP图像显示
参考文章
- 解码带压缩形式的Bitmap(BMP)图像并使用Python可视化解码后实际图像
- 在CodeBlocks搭建SDL2工程构建TFT彩屏模拟器虚拟TFT彩屏幕显示
- 使用Python可视化有压缩格式的Bitmap(BMP)图像调色板数据
- 有压缩格式的Bitmap(BMP)图像显示调色板数据和图像数据
- Bitmap(BMP)图像信息分析主要说明带压缩的形式
- Bitmap(BMP)图像信息验证
文章说明
1. 在CodeBlocks上搭建SDL2工程,虚拟TFT彩屏模拟器
2. 带压缩的Bitmap(BMP)图像解码后显示在TFT彩屏上
3. Bitmap(BMP)原图垂直翻转后为真实样子
一、创建和退出SDL2
static AppGlobal_TypeDef AppSystem = {0};
AppGlobal_TypeDef * pAppSystem = &AppSystem;
/* 初始化SDL */
static u8 ubInit_SDL2(void)
{
/* 初始化SDL */
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0)
{
SDL_Log("SDL Init Fail......%s\r\n", SDL_GetError());
return 1;
}
/* 创建窗口 */
AppSystem.MainWindow = SDL_CreateWindow("Virtual TFT SDL2", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_PHY_WIDTH, WINDOW_PHY_HEIGHT, SDL_WINDOW_SHOWN);
if (AppSystem.MainWindow == NULL)
{
SDL_Log("SDL Create Window Fail......%s\r\n", SDL_GetError());
return 2;
}
/* 创建渲染器 */
AppSystem.MainRender = SDL_CreateRenderer(AppSystem.MainWindow, -1, SDL_RENDERER_ACCELERATED);
if (AppSystem.MainRender == NULL)
{
SDL_Log("SDL Create Renderer Fail......%s", SDL_GetError());
return 3;
}
/* 创建纹理 */
AppSystem.MainTexture = SDL_CreateTexture(AppSystem.MainRender, SDL_PIXELFORMAT_ARGB8888 , SDL_TEXTUREACCESS_STATIC, TFT_LCD_PHY_XWIDTH, TFT_LCD_PHY_YHEIGHT);
if (AppSystem.MainTexture == NULL)
{
SDL_Log("SDL Create Texture Fail......%s", SDL_GetError());
return 4;
}
/* 设置纹理模式 */
SDL_SetTextureBlendMode(AppSystem.MainTexture, SDL_BLENDMODE_BLEND);
memset(TFT_LCD_DIS_MEMORY, 0x99, TFT_LCD_PHY_XWIDTH * TFT_LCD_PHY_YHEIGHT * sizeof(u32));
SDL_UpdateTexture(AppSystem.MainTexture, NULL, TFT_LCD_DIS_MEMORY, TFT_LCD_PHY_XWIDTH * sizeof(u32));
SDL_RenderClear(AppSystem.MainRender);
SDL_RenderCopy(AppSystem.MainRender, AppSystem.MainTexture, NULL, NULL);
SDL_RenderPresent(AppSystem.MainRender);
return 0;
}
/* 退出SDL */
static void vQuit_SDL2(void)
{
SDL_Log("Complier Date: %s %s %d\r\n", __DATE__, __TIME__, ulSuperTimer_GetTick());
/* 销毁纹理 */
if (AppSystem.MainTexture != NULL) SDL_DestroyTexture(AppSystem.MainTexture);
/* 销毁渲染器 */
if (AppSystem.MainRender != NULL) SDL_DestroyRenderer(AppSystem.MainRender);
/* 销毁窗口 */
if (AppSystem.MainWindow != NULL) SDL_DestroyWindow(AppSystem.MainWindow);
/* 退出SDL */
SDL_Quit();
}
二、 Bitmap(BMP)图片解码图
/* 获取调色板数据 */
void vGet_Color_Palette(const u8 * pSrcDat, u32 * pColorDat, u16 count)
{
u16 i = 0;
u32 * pARGB = (u32 *)(pSrcDat + sizeof(BitmapInfo_TypeDef));
for (i = 0; i < count; ++i)
{
pColorDat[i] = *pARGB++;
}
}
/* 解码数据写入文件中 */
static void vBitmap_Write_File(void)
{
u32 i = 0;
/* 将解码后数据写入文件中 */
FILE * wFileHandler= fopen("xDemo.txt", "a+");
if (wFileHandler == NULL)
{
printf("Open File Error......\n");
return;
}
fprintf(wFileHandler, "Width:%u Height:%u\n", AppBmpDecode->pBmpInfo->InfoHeader.ImgWidth, AppBmpDecode->pBmpInfo->InfoHeader.ImgHeight);
for (i = 0; i < AppBmpDecode->Index; ++i)
{
if (i && ((i % 10) == 0)) fprintf(wFileHandler, "\n");
fprintf(wFileHandler, "'#%08X',", AppBmpDecode->pDisMemory[i]);
}
fprintf(wFileHandler, "\r\n\r\n");
if (wFileHandler == NULL)
{
fclose(wFileHandler);
}
}
/* Bitmap图片解码 */
void vDecode_Bitmap(const u8 * pSrcDat)
{
const u8 * pDat = NULL;
Type8Bits_TypeDef bitDat = {0};
BitmapInfo_TypeDef bitmapInfo = {0};
u32 widthCount = 0, heightCount = 0;
u32 color = 0, temp = 0;
u16 i = 0, num = 0, count = 0;
u16 line = 0, colum = 0;
/* 获取Bitmap信息 */
memcpy((void *)(&bitmapInfo), (const void *)pSrcDat, sizeof(BitmapInfo_TypeDef));
/* 获取调色板数据 */
vGet_Color_Palette(pSrcDat, AppBmpDecode->pColorPalette, bitmapInfo.InfoHeader.ColorPalette);
/* 显示调色板数据 */
// vShow_Color_Palette(AppBmpDecode->pColorPalette, bitmapInfo.InfoHeader.ColorPalette);
/* 颜色数据 */
pDat = pSrcDat + bitmapInfo.FileHeader.ImgDataOffset;
/* 解码索引 */
AppBmpDecode->Index = 0;
while(1)
{
if (*pDat == 0)
{
pDat++;
switch (*pDat)
{
case 0x00: //00 00 行结束
{
pDat++;
/* 宽度计数不够 */
if (bitmapInfo.InfoHeader.ImgWidth >= widthCount)
{
/* 剩余的宽度部分 */
temp = bitmapInfo.InfoHeader.ImgWidth - widthCount;
if (!bitDat.Bits.Bit0)
{
bitDat.Bits.Bit0 = 1;
// printf("Tips2......%u\r\n", AppBmpDecode->Index);
}
}
else
{
/* 宽度计数超过图像宽度 剩余的宽度部分计算 */
temp = bitmapInfo.InfoHeader.ImgWidth - (widthCount % bitmapInfo.InfoHeader.ImgWidth);
/* 跨宽度的高度数量 */
heightCount += (widthCount / bitmapInfo.InfoHeader.ImgWidth);
if (!bitDat.Bits.Bit1)
{
bitDat.Bits.Bit1 = 1;
// printf("Tips3......%u\r\n", AppBmpDecode->Index);
}
}
/* 增加高度计数 */
heightCount++;
/* 高度计数已大于图像高度,提前结束 */
if (heightCount >= bitmapInfo.InfoHeader.ImgHeight)
{
bitDat.Bits.Bit7 = 1;
// printf("Tips5......%u\r\n", AppBmpDecode->Index);
}
/* 清零宽度计数 */
widthCount = 0;
/* 剩余的宽度部分需填充颜色 */
AppBmpDecode->Index += temp;
}
break;
case 0x01: //00 01 图像结束
{
/* 计算剩余需要填充的像素点大小 */
temp = (bitmapInfo.InfoHeader.ImgHeight - heightCount - 1) * bitmapInfo.InfoHeader.ImgWidth + (bitmapInfo.InfoHeader.ImgWidth - widthCount);
// temp = (bitmapInfo.InfoHeader.ImgHeight * bitmapInfo.InfoHeader.ImgWidth) - AppBmpDecode->Index;
// printf("Tips4......%u ", AppBmpDecode->Index);
AppBmpDecode->Index += temp;
bitDat.Bits.Bit7 = 1;
// printf("%u %u %u\r\n", AppBmpDecode->Index, heightCount, temp);
}
break;
case 0x02: //00 02 跳转水平和垂直偏移量
{
colum = *(pDat + 1); //x
line = *(pDat + 2); //y
pDat += 3;
/* 宽度计数 */
widthCount += colum;
/* 高度计数 */
heightCount += line;
// if (!bitDat.Bits.Bit2) printf("Tips1......index0:%u ", AppBmpDecode->Index);
/* 跳转到指定位置 */
AppBmpDecode->Index += bitmapInfo.InfoHeader.ImgWidth * line + colum;
// if (!bitDat.Bits.Bit2)
// {
// bitDat.Bits.Bit2 = 1;
// printf("index0:%u %u %u %u %u\r\n", AppBmpDecode->Index, colum, line, bitmapInfo.InfoHeader.ImgWidth, bitmapInfo.InfoHeader.ImgHeight);
// }
}
break;
default: //00 03~FF 单像素数量+调色板索引
{
count = num = *pDat;
widthCount += num;
pDat++;
for (i = 0; i < num; ++i)
{
/* 单像素颜色 */
AppBmpDecode->pDisMemory[AppBmpDecode->Index++] = AppBmpDecode->pColorPalette[*pDat++];
}
/* 对齐 */
if (count & 0x01)
{
pDat++;
}
}
break;
}
}
else
{
count = *pDat;
color = AppBmpDecode->pColorPalette[*(pDat + 1)];
widthCount += count;
pDat += 2;
for (i = 0; i < count; ++i)
{
AppBmpDecode->pDisMemory[AppBmpDecode->Index++] = color;
}
}
/* 结束 */
if (bitDat.Bits.Bit7)
{
break;
}
}
/* 解码数据写入文件中 */
// vBitmap_Write_File();
}
三、Bitmap解码初始化
/* 初始化Bitmap解码 */
void vInit_Bitmap_Decode(void)
{
BitmapDecode.pDisMemory = BitmapDecodeDisplayMemory;
BitmapDecode.pColorPalette = BitmapDecodeColorPalette;
BitmapDecode.pImageData = BitmapDecodeImageData;
BitmapDecode.pBmpInfo = &BitmapDecodeBitmapInfo;
BitmapDecode.Index = 0;
AppBmpDecode = (BitmapDecode_TypeDef *)(&BitmapDecode);
}
void vClear_BmpDecode_Memory(void)
{
memset((void *)BitmapDecode.pDisMemory, 0, (BMP_DECODE_DISPLAY_MEMORY_SIZE << 2));
memset((void *)BitmapDecode.pColorPalette, 0, (BMP_DECODE_COLOR_PALETTE_SIZE << 2));
memset((void *)BitmapDecode.pImageData, 0, BMP_DECODE_IMAGE_DATA_SIZE);
memset((void *)BitmapDecode.pBmpInfo, 0, sizeof(BitmapInfo_TypeDef));
BitmapDecode.Index = 0;
}
四、测试代码
void vTFT_LCD_FillRect_MultColor1(u32 x, u32 y, u32 width, u32 height, ColorType * pColor)
{
u32 count = 0;
u32 x0 = 0, y0 = 0, ex = 0, ey = 0;
for (y0 = y; y0 <= (y + height - 1); y0++)
{
for (x0 = x; x0 <= (x + width - 1); x0++)
{
AppDevTFT.pDisMem[AppDevTFT.xWidth * y0 + x0] = 0xFF000000 | DEV_RGB(*pColor++);
count++;
}
}
printf("width:%-5u height:%-5u count:%-5u X:%-5u Y:%-5u\r\n", width, height, count, x0, y0);
}
const u8 * xDat[12] =
{
(const u8 *)"xDemoUI\\b128_t_vol3.bmp",
(const u8 *)"xDemoUI\\b064_p_delay.bmp",
(const u8 *)"xDemoUI\\b089_td_meas.bmp",
(const u8 *)"xDemoUI\\b112_t_p2p2.bmp",
(const u8 *)"xDemoUI\\b110_t_level.bmp",
(const u8 *)"xDemoUI\\b106_t_area1.bmp",
(const u8 *)"xDemoUI\\b101_t_2pyth2.bmp",
(const u8 *)"xDemoUI\\b380_td_contmeas.bmp",
(const u8 *)"xDemoUI\\b109_t_cylin2.bmp",
(const u8 *)"xDemoUI\\b127_t_vol2.bmp",
(const u8 *)"xDemoUI\\b042_m_stake2.bmp",
(const u8 *)"xDemoUI\\b120_t_trapz2.bmp",
};
void vDemoTest(void)
{
static u8 count = 0;
const u8 * pSrcDir = NULL;
FILE * pImgFileHandler = NULL;
pSrcDir = xDat[count];
if ((++count) >= 12) count = 0;
/* 打开文件 */
pImgFileHandler = fopen(pSrcDir, "rb");
if (pImgFileHandler == NULL)
{
printf("Open File Error......\r\n");
while (1);
}
vClear_BmpDecode_Memory();
/* 读取Bitmap信息 */
if (!fread(AppBmpDecode->pBmpInfo, sizeof(BitmapInfo_TypeDef), 1, pImgFileHandler))
{
printf("Read Bitmap Info Error......\r\n");
while (1);
}
/* 设置文件指针偏移 */
if (fseek(pImgFileHandler, 0, SEEK_SET))
{
printf("Set Offset Error.....1\r\n");
while (1);
}
/* 读取整个文件内容 */
if (!fread(AppBmpDecode->pImageData, AppBmpDecode->pBmpInfo->FileHeader.FileSize, 1, pImgFileHandler))
{
printf("Read File Data Error......2\r\n");
while (1);
}
vTFT_LCD_FillRect_SingColor(10, 50, AppDevTFT.xWidth - 10, AppDevTFT.yHeight - 10, 0);
vDecode_Bitmap((const u8 *)AppBmpDecode->pImageData);
vTFT_LCD_FillRect_MultColor1(30, 60, AppBmpDecode->pBmpInfo->InfoHeader.ImgWidth, AppBmpDecode->pBmpInfo->InfoHeader.ImgHeight, AppBmpDecode->pDisMemory);
ubSuperTimer_Start(vDemoTest, 1500);
}
五、主函数
int main( int argc, char * argv[] )
{
if (ubInit_SDL2())
{
SDL_Log("Init SDL Fail......%s\r\n", SDL_GetError());
vQuit_SDL2();
return -1;
}
vTFT_Init();
xSuperTimer_Init();
vInit_Bitmap_Decode();
AppSystem.ExitWindow = EXIT_WINDOW_TYPE_RUN;
ubSuperTimer_Start(xDemo, 3000);
while (AppSystem.ExitWindow)
{
vRefresh_KeyEvent_Handler();
vSystem_BasicTick();
vSuperTimer_RunHandler();
}
vQuit_SDL2();
return 0;
}
六、测试结果