Loading

数码相框-显示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:

image

修改render文件夹下的makefile:

image

修改format的makefile:

image

修改operation的makefile:

image

测试

image

编译报错,需要补充函数,放在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:

image

拷贝文件和bmp图片到开发板:

image

修改报错

因为文件信息头获取到的字节数是16,不是14,没有正确读到信息,这是因为c语言结构体的内存自动优化了,所以必须强制对齐:

image

​​image

​​image

image​​

测试成功

image

补充

image

这些视频还需要看一遍,我看的b站视频顺序对不上。

posted @ 2024-04-11 09:33  阿四与你  阅读(1)  评论(0编辑  收藏  举报