数码相框-显示bmp图片
写主函数和测试功能
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <config.h>
#include <draw.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <disp_manager.h>
#include <input_manager.h>
#include <pic_operation.h>
#include <render.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
/*
* 程序入口:处理命令行参数,打开BMP文件,读取并显示图像。
* argc: 命令行参数个数。
* argv: 命令行参数数组。
* 返回值:成功返回0,失败返回-1。
*/
int main(int argc, char **argv)
{
int iFdBmp; // 文件描述符
int iRet; // 操作返回值
unsigned char *pucBMPmem; // BMP文件内存映射指针
struct stat tBMPstat; // 文件状态结构体
PT_DispOpr ptDispOpr; // 显示操作结构体指针
extern T_PicFileParser g_tBMPParser; // BMP文件解析器
T_PixelDatas tPixelDatas; // 原始像素数据结构体
T_PixelDatas tPixelDatasSmall; // 缩小后的像素数据结构体
T_PixelDatas tPixelDatasFB; // 显示帧缓冲区的像素数据结构体
// 检查命令行参数是否正确
if (argc != 2)
{
printf("%s <bmp_file>\n", argv[0]);
return -1;
}
// 初始化调试信息输出
DebugInit();
InitDebugChanel();
// 初始化显示系统
DisplayInit();
// 初始化并设置显示设备
ptDispOpr = GetDispOpr("fb");
ptDispOpr->DeviceInit();
ptDispOpr->CleanScreen(0);
/* 打开BMP文件 */
iFdBmp = open(argv[1], O_RDWR);
if (iFdBmp == -1)
{
DBG_PRINTF("can't open %s\n", argv[1]);
}
// 获取BMP文件状态,用于后续内存映射
fstat(iFdBmp, &tBMPstat);
// 使用内存映射方式加载BMP文件
pucBMPmem = (unsigned char *)mmap(NULL , tBMPstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFdBmp, 0);
if (pucBMPmem == (unsigned char *)-1)
{
DBG_PRINTF("mmap error!\n");
return -1;
}
/* 检测是否是一个合格的bmp文件 */
iRet = g_tBMPParser.isSupport(pucBMPmem);
if (iRet == 0)
{
DBG_PRINTF("%s is not bmp file\n", argv[1]);
return -1;
}
// 解析BMP文件像素数据
tPixelDatas.iBpp = ptDispOpr->iBpp;
iRet = g_tBMPParser.GetPixelDatas(pucBMPmem, &tPixelDatas);
if (iRet)
{
DBG_PRINTF("GetPixelDatas error!\n");
return -1;
}
// 设置帧缓冲区的像素数据结构体
tPixelDatasFB.iWidth = ptDispOpr->iXres;
tPixelDatasFB.iHeight = ptDispOpr->iYres;
tPixelDatasFB.iBpp = ptDispOpr->iBpp;
tPixelDatasFB.iLineBytes = ptDispOpr->iXres * ptDispOpr->iBpp / 8;
tPixelDatasFB.aucPixelDatas = ptDispOpr->pucDispMem;
// 将BMP图像数据合并到帧缓冲区显示
PicMerge(0, 0, &tPixelDatas, &tPixelDatasFB);
// 缩小1/2图像并显示
tPixelDatasSmall.iWidth = tPixelDatas.iWidth/2;
tPixelDatasSmall.iHeight = tPixelDatas.iHeight/2;
tPixelDatasSmall.iBpp = tPixelDatas.iBpp;
tPixelDatasSmall.iLineBytes = tPixelDatasSmall.iWidth * tPixelDatasSmall.iBpp / 8;
tPixelDatasSmall.aucPixelDatas = malloc(tPixelDatasSmall.iLineBytes * tPixelDatasSmall.iHeight);
PicZoom(&tPixelDatas, &tPixelDatasSmall);
PicMerge(128, 128, &tPixelDatasSmall, &tPixelDatasFB);
return 0;
}
修改makefile
修改工程下的makefile:
修改render文件夹下的makefile:
修改format的makefile:
修改operation的makefile:
测试
编译报错,需要补充函数,放在Disp_manager.c:
#include <config.h>
#include <disp_manager.h>
#include <string.h>
// 定义显示操作的链表头
static PT_DispOpr g_ptDispOprHead;
// 定义默认显示操作
static PT_DispOpr g_ptDefaultDispOpr;
/**
* 注册显示操作
* @param ptDispOpr 显示操作的结构体指针
* @return 总是返回0
*/
int RegisterDispOpr(PT_DispOpr ptDispOpr)
{
PT_DispOpr ptTmp;
// 如果链表为空,将传入的操作设置为链表头
if (!g_ptDispOprHead)
{
g_ptDispOprHead = ptDispOpr;
ptDispOpr->ptNext = NULL;
}
else
{
// 遍历链表,将新的显示操作添加到链表尾部
ptTmp = g_ptDispOprHead;
while (ptTmp->ptNext)
{
ptTmp = ptTmp->ptNext;
}
ptTmp->ptNext = ptDispOpr;
ptDispOpr->ptNext = NULL;
}
return 0;
}
/**
* 展示所有已注册的显示操作
*/
void ShowDispOpr(void)
{
int i = 0;
PT_DispOpr ptTmp = g_ptDispOprHead;
// 遍历链表,打印每个显示操作的名称
while (ptTmp)
{
printf("%02d %s\n", i++, ptTmp->name);
ptTmp = ptTmp->ptNext;
}
}
/**
* 获取指定名称的显示操作
* @param pcName 指向要获取的显示操作名称的指针
* @return 找到的显示操作的结构体指针,如果未找到则返回NULL
*/
PT_DispOpr GetDispOpr(char *pcName)
{
PT_DispOpr ptTmp = g_ptDispOprHead;
// 遍历链表,查找名称匹配的显示操作
while (ptTmp)
{
if (strcmp(ptTmp->name, pcName) == 0)
{
return ptTmp;
}
ptTmp = ptTmp->ptNext;
}
return NULL;
}
/**
* 选择默认的显示设备
* @param name 指向默认显示设备名称的指针
*/
void SelectDefaultDispDev(char *name)
{
g_ptDefaultDispOpr = GetDispOpr(name); // 通过名称获取显示操作,并设置为默认
}
/**
* 获取默认显示设备的分辨率
* @param piXres 指向存储宽度的整型指针
* @param piYres 指向存储高度的整型指针
* @return 成功返回0,失败返回-1
*/
int GetDispResolution(int *piXres, int *piYres)
{
if (g_ptDefaultDispOpr) // 检查是否有默认显示操作
{
*piXres = g_ptDefaultDispOpr->iXres; // 设置宽度
*piYres = g_ptDefaultDispOpr->iYres; // 设置高度
return 0;
}
else
{
return -1;
}
}
/**
* 初始化显示设备
* @return 初始化错误码,0表示成功
*/
int DisplayInit(void)
{
int iError;
iError = FBInit(); // 初始化帧缓冲区
return iError;
}
这段代码定义了一个显示操作的链表,提供了注册显示操作、展示所有已注册的显示操作、获取指定名称的显示操作、选择默认的显示设备、获取默认显示设备的分辨率和初始化显示设备等功能。
具体来说:
-
RegisterDispOpr
函数用于注册显示操作,将传入的操作添加到链表中。 -
ShowDispOpr
函数用于展示所有已注册的显示操作,遍历链表并打印每个操作的名称。 -
GetDispOpr
函数用于获取指定名称的显示操作,遍历链表并查找名称匹配的操作。 -
SelectDefaultDispDev
函数用于选择默认的显示设备,通过名称获取显示操作并设置为默认。 -
GetDispResolution
函数用于获取默认显示设备的分辨率,检查是否有默认显示操作,并返回宽度和高度。 -
DisplayInit
函数用于初始化显示设备,调用FBInit
函数进行初始化并返回错误码。
编译之后生成digitpic:
拷贝文件和bmp图片到开发板:
修改报错
因为文件信息头获取到的字节数是16,不是14,没有正确读到信息,这是因为c语言结构体的内存自动优化了,所以必须强制对齐:
测试成功
补充
这些视频还需要看一遍,我看的b站视频顺序对不上。