数码相册——在LCD上显示BMP图片
- 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
- 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
- 参考资料:《嵌入式Linux应用开发手册》、《嵌入式Linux应用开发手册第2版》、【bitmap格式分析】
- 开发环境:Linux 3.4.2内核、arm-linux-gcc 4.3.2工具链
- 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3
目录
-
数码相册——在LCD上显示BMP图片
一、数码相册
1、软件框架
对于数码相册的软件框架,在电子书框架的基础上修改进而实现数码相册功能,并在此基础上实现文件浏览器的功能,具体的框架如下:
对于上述完成主要功能的7个部分:encoding编码部分、fonts获取字体点阵部分、display显示部分、input输入部分、debug调试部分、page页面管理部分、render渲染部分
- encoding编码部分:去文件中获得编码信息,对于每个文件,保存的时候,系统对自动或手动的根据编码规范,对文件的信息进行编码:如保存为
ASCII、GBK、UTF-8、UTF16LE、UTF16BE
; - fonts获取字体点阵部分:根据获得的编码信息得到字体数据(LCD上表示为点阵);
- display显示部分:把字体数据(点阵)显示在LCD上;
- input输入部分:管理不同的输入方式,定制不同的输入方式所实现的控制,满足多种控制场合;
- debug调试部分:设置打印等级和打印通道,通过打印等级来控制程序打印的调试信息、错误信息、警告信息等,通过打印通道设置来控制程序打印的输出的流向是标准输出还是网络打印输出。
- page页面管理部分:负责对多种页面进行管理,通过触控进行不同页面的切换与功能实现;
- render渲染部分:负责对bmp文件进行读取、解析、提取有效的像素信息、显示到LCD上;
至多个部分的协调,通过在main.c
文件中实现。
2、页面管理
为了满足多种需求,设计了如下页面:
当程序一运行时,进入的是主页面,通过触控不同的区域进入以下到不同的页面:
- 点击浏览模式,进入文件浏览模式,在这里可以对根文件系统中的文件进行图片与文字浏览、上下页切换、选择文件、返回上一级操作。在浏览图片信息时,可以实现缩放、移动、上下张切换,点击返回区域即可回到文件浏览模式;
- 点击连播模式,可以对指定的目录的图片进行连续播放,每张图片播放时间间隔可以进行设置;
- 点击设置,可对连播模式的目录与时间间隔进行设置。
3、Makefile框架
这个Makefile针对的是实现显示bmp文件程序,对于完整的会在后面进行完善。
二、bmp文件
bmp图片是无损的,同时这种图片格式几乎没有对数据进行压缩,所以通常具有较大的文件大小,同时支持索引色和直接色。
1、组成
bmp位图信息主要由以下3部分组成:
块名称 | 块名称 | 大小(Byte) |
---|---|---|
文件信息头 | BITMAPFILEHEADER | 14 |
位图信息头 | BITMAPINFOHEADER | 40 |
RGB颜色阵列 | RGB颜色阵列 | RGB颜色阵列 |
1.1 文件信息头BITMAPFILEHEADER
- 结构体定义如下:
/* WINDOW系统下 */
typedef struct tagBITMAPFILEHEADER { /* bmfh */
UINT bfType;
DWORD bfSize;
UINT bfReserved1;
UINT bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
/* Linux系统下 */
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType; //文件类型
unsigned long bfSize; //文件大小
unsigned short bfReserved1; //保留位,必须为0
unsigned short bfReserved2; //保留位,必须为0
unsigned long bfOffBits; //文件头开始到实际的图象数据之间的字节的偏移量
} BITMAPFILEHEADER;
- 参数介绍:
bfType | 说明文件的类型,该值必需是0x4D42,也就是字符’BM’。 |
---|---|
bfSize | 说明该位图文件的大小,用字节为单位 |
bfReserved1 | 保留,必须设置为0 |
bfReserved2 | 保留,必须设置为0 |
bfOffBits | 说明从文件头开始到实际的图象数据之间的字节的偏移量。这个参数是非常有用的,因为位图信息头和调色板的长度会根据不同情况而变化,所以你可以用这个偏移值迅速的从文件中读取到位数据。 |
- 举例说明:
通过用二进制文件打开一个.bmp
格式文件,注意其二进制数据存储为低位在前,高位在后
1.2 位图信息头BITMAPINFOHEADER
- 结构体定义如下:
/* WINDOW系统下 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
/* Linux系统下 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
unsigned long biSize; //文件信息头结构体需要的自身
unsigned long biWidth; //图像宽度
unsigned long biHeight; //图像高度
unsigned short biPlanes; //位面数,总被设为1
unsigned short biBitCount; //bpp
unsigned long biCompression; //数据压缩的类型
unsigned long biSizeImage; //图象的大小
unsigned long biXPelsPerMeter;//水平分辨率
unsigned long biYPelsPerMeter;//垂直分辨率
unsigned long biClrUsed; //使用的彩色表中的颜色索引,0-使用所有调色板项
unsigned long biClrImportant; //对图象显示有重要影响的颜色索引的数目,0-都重要
} BITMAPINFOHEADER;
- 参数介绍:
biSize | 说明BITMAPINFOHEADER结构所需要的字数 |
---|---|
biWidth | 说明图象的宽度,以象素为单位 |
biHeight | 说明图象的高度,以象素为单位。注:这个值除了用于描述图像的高度之外,它还有另一个用处,就是指明该图像是倒向的位图,还是正向的位图。如果该值是一个正数,说明图像是倒向的,如果该值是一个负数,则说明图像是正向的。大多数的BMP文件都是倒向的位图,也就是时,高度值是一个正数 |
biPlanes | 为目标设备说明位面数,其值将总是被设为1。 |
biBitCount | 说明比特数/象素,其值为1、4、8、16、24、或32。但是由于我们平时用到的图像绝大部分是24位和32位的,所以我们讨论这两类图像 |
biCompression | 说明图象数据压缩的类型,同样我们只讨论没有压缩的类型:BI_RGB |
biSizeImage | 说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0 |
biXPelsPerMeter | 说明水平分辨率,用象素/米表示 |
biYPelsPerMeter | 说明垂直分辨率,用象素/米表示 |
biClrUsed | 说明位图实际使用的彩色表中的颜色索引数(设为0的话,则说明使用所有调色板项) |
biClrImportant | 说明对图象显示有重要影响的颜色索引的数目,如果是0,表示都重要 |
- 举例说明:
1.3 RGB颜色阵列
在Windows下,RGB颜色阵列存储的格式其实BGR。也就是说,对于24位的RGB位图像素数据格式是:
蓝色B值 | 绿色G值 | 红色R值 |
---|
对于32位的RGB位图像素数据格式是:
蓝色B值 | 绿色G值 | 红色R值 | 透明通道A值 |
---|
- 举例说明
注意:bmp二进制文件格式存储的像素是从图片的左下角开始,从左往右一行一行的上去。
三、代码编写
代码以实现显示bmp文件为主,对于其他部分后面的博客会慢慢完善。
1、pic_operation.h
bmp描述头文件
- 定义两个结构体变量,用来存储bmp文件信息与bmp文件像素信息,拓展文件可以根据自己的情况:分配结构体、设置结构体;
#ifndef _PIC_OPERATION_H
#define _PIC_OPERATION_H
typedef struct PixelDatas{
int bpp;
int width;
int height;
int linebytes;
unsigned char *PixelDatas;
}T_PixelDatas, *PT_PixelDatas;
typedef struct PicFileParser {
char *name;
int (*isSupport)(unsigned char *pFileHead);
int (*GetPixelDatas)(unsigned char *pFileHead, PT_PixelDatas ptPixelID);
int (*FreePixelDatas)(PT_PixelDatas ptPixelDatas);
}T_PicFileParser, *PT_PicFileParser;
#endif /* _PIC_OPERATION_H */
2、render.h
渲染头文件
定义如下函数
#ifndef _RENDER_H
#define _RENDER_H
int PicZoom(PT_PixelDatas ptOriginPic, PT_PixelDatas ptZoomPic); //图片压缩
int PicMerge(int x, int y, PT_PixelDatas ptSmallPic, PT_PixelDatas ptBigPic); //图片LCD显示
#endif /* _RENDER_H */
3、bmp.c
bmp文件解析
在这个文件中,进行分配结构体、设置结构体
- 结构体对齐:在定义如下结构体时,需要添加如下语句,使得结构体呈现1字节对齐,否则系统默认4字节对齐,最终定位不到bmp文件中有效信息。
#pragma pack(push) /* 将当前pack设置压栈保存 */
#pragma pack(1) /* 必须在结构体定义之前使用 */
#pragma pack(pop) /* 恢复先前的pack设置 */
#pragma pack(push) /* 将当前pack设置压栈保存 */
#pragma pack(1) /* 必须在结构体定义之前使用 */
/* bmp文件信息头 */
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType; //文件类型
unsigned long bfSize; //文件大小
unsigned short bfReserved1; //保留位,必须为0
unsigned short bfReserved2; //保留位,必须为0
unsigned long bfOffBits; //文件头开始到实际的图象数据之间的字节的偏移量
} BITMAPFILEHEADER;
/* 位图信息头 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
unsigned long biSize; //文件信息头结构体需要的自身
unsigned long biWidth; //图像宽度
unsigned long biHeight; //图像高度
unsigned short biPlanes; //位面数,总被设为1
unsigned short biBitCount; //bpp
unsigned long biCompression; //数据压缩的类型
unsigned long biSizeImage; //图象的大小
unsigned long biXPelsPerMeter;//水平分辨率
unsigned long biYPelsPerMeter;//垂直分辨率
unsigned long biClrUsed; //使用的彩色表中的颜色索引,0-使用所有调色板项
unsigned long biClrImportant; //对图象显示有重要影响的颜色索引的数目,0-都重要
} BITMAPINFOHEADER;
#pragma pack(pop) /* 恢复先前的pack设置 */
- 解析bmp文件信息,提取像素数据
注意:1、在bmp二进制文件中,像素数据存在向四取整的情况,在代码中需要进行处理。
2、由于bmp文件中一开始存储的是图片左下角的像素数据,LCD从图片的左上角开始像素描画,所以需要如下的转换:
/**
* @Description: 从bmp文件中获取像素数据,并分配缓冲区存放像素信息,供外部文件调用
* @param pFileHead - 文件头,ptPixelDatas - 位图信息,存储像素信息,其bpp用户设定
* @return 0 - 成功,-1 - 失败
*/
int GetPixelDatasFrmBMP(unsigned char *pFileHead, PT_PixelDatas ptPixelDatas)
{
int y;
int width;
int height;
int BMPbpp;
int LineWidthReal;
int LineWidthAlign;
unsigned char *pSrc;
unsigned char *pDest;
BITMAPFILEHEADER *ptBITMAPFILEHEADER;
BITMAPINFOHEADER *ptBITMAPINFOHEADER;
ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)pFileHead;
ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(pFileHead + sizeof(BITMAPFILEHEADER));
/* 获取bmp文件信息 */
width = ptBITMAPINFOHEADER->biWidth;
height = ptBITMAPINFOHEADER->biHeight;
BMPbpp = ptBITMAPINFOHEADER->biBitCount;
if (BMPbpp != 24) {
DebugPrint(APP_ERR"can not support %d bpp\n", BMPbpp);
return -1;
}
/* 设置结构体 */
ptPixelDatas->height = height;
ptPixelDatas->width = width;
ptPixelDatas->linebytes = width * ptPixelDatas->bpp / 8;
/* 分配缓冲区 */
ptPixelDatas->PixelDatas = (unsigned char *)malloc(width * height * ptPixelDatas->bpp / 8);
if (ptPixelDatas->PixelDatas == NULL) {
DebugPrint(APP_ERR"malloc ptPixelDatas->PixelDatas err\n");
return -1;
}
/* 获取bmp像素信息:存储像素的起始是图片左下角 */
LineWidthReal = width * BMPbpp / 8; //每行像素所占的字节
LineWidthAlign = (LineWidthReal + 3) & ~0x3; //向4取整后的每行像素所占的字节
pSrc = pFileHead + ptBITMAPFILEHEADER->bfOffBits; //像素信息的源地址
pSrc = pSrc + LineWidthAlign * (height- 1); //移动到存储图片左上角的数据地址
pDest = ptPixelDatas->PixelDatas; //数据最终的去向
for (y = 0; y < height; y++) {
//memcpy(pDest, pSrc, LineWidthReal);
CoverOneLine(width, BMPbpp, ptPixelDatas->bpp, pSrc, pDest);
pSrc -= LineWidthAlign; //bmp二进制数据
pDest += ptPixelDatas->linebytes; //LCD显示数据
}
return 0;
}
- 完整的文件:
/**
* @file bmp.c
* @brief 处理bmp文件,对其进行解析
* @version 1.0 (版本声明)
* @author Dk
* @date July 7,2020
*/
#include <stdlib.h>
#include <string.h>
#include "pic_operation.h"
#include "debug_manager.h"
#pragma pack(push) /* 将当前pack设置压栈保存 */
#pragma pack(1) /* 必须在结构体定义之前使用 */
/* bmp文件信息头 */
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType; //文件类型
unsigned long bfSize; //文件大小
unsigned short bfReserved1; //保留位,必须为0
unsigned short bfReserved2; //保留位,必须为0
unsigned long bfOffBits; //文件头开始到实际的图象数据之间的字节的偏移量
} BITMAPFILEHEADER;
/* 位图信息头 */
typedef struct tagBITMAPINFOHEADER { /* bmih */
unsigned long biSize; //文件信息头结构体需要的自身
unsigned long biWidth; //图像宽度
unsigned long biHeight; //图像高度
unsigned short biPlanes; //位面数,总被设为1
unsigned short biBitCount; //bpp
unsigned long biCompression; //数据压缩的类型
unsigned long biSizeImage; //图象的大小
unsigned long biXPelsPerMeter;//水平分辨率
unsigned long biYPelsPerMeter;//垂直分辨率
unsigned long biClrUsed; //使用的彩色表中的颜色索引,0-使用所有调色板项
unsigned long biClrImportant; //对图象显示有重要影响的颜色索引的数目,0-都重要
} BITMAPINFOHEADER;
#pragma pack(pop) /* 恢复先前的pack设置 */
/**
* @Description: 判断是否为bmp文件
* @param pFileHead - 文件头
* @return 1 - bmp文件, 0 - 非bmp文件
*/
static int isBMPFormat(unsigned char *pFileHead)
{
/* bmp文件最开始的两字节数据为0x4D42 */
if ((pFileHead[0] != 0x42) || (pFileHead[1] != 0x4d))
return 0;
else
return 1;
}
/**
* @Description: 从源数据中按照DstBpp的值,转换到目的数据
* @param width - bmp位图的宽度,SrcBpp - bmp位图的bpp
* DstBpp - LCD上显示位图的bpp,SrcDatas - bmp位图的一行像素起始地址
* DstDatas - LCD上显示位图的一行像素起始地址
* @return 0 - 支持转换,-1 - 不支持转换
*/
static int CoverOneLine(int width, int SrcBpp, int DstBpp, unsigned char *SrcDatas, unsigned char *DstDatas)
{
int i;
int pos;
unsigned int red;
unsigned int green;
unsigned int blue;
unsigned int color;
unsigned short *DstData16Bpp;
unsigned int *DstData32Bpp;
pos = 0;
DstData16Bpp = (unsigned short *)DstDatas;
DstData32Bpp = (unsigned int *)DstDatas;
if (SrcBpp != 24) {
DebugPrint(APP_NOTICE"can not support %bpp\n", SrcBpp);
return -1;
}
if (DstBpp == 24)
memcpy(DstDatas, SrcDatas, width * 3);
else {
/* 提取有效的数据 */
for (i = 0; i < width; i++) {
blue = SrcDatas[pos++];
green = SrcDatas[pos++];
red = SrcDatas[pos++];
if (DstBpp == 32) {
color = (red << 16) | (green << 8) | blue;
*DstData32Bpp = color;
DstData32Bpp++;
} else if (DstBpp == 16) {
/* RGB:565 */
red = red >> 3;
green = green >> 2;
blue = blue >> 3;
color = (red << 11) | (green << 5) | blue;
*DstData16Bpp= color;
DstData16Bpp++;
}
}
}
return 0;
}
/**
* @Description: 从bmp文件中获取像素数据,并分配缓冲区存放像素信息,供外部文件调用
* @param pFileHead - 文件头,ptPixelDatas - 位图信息,存储像素信息,其bpp用户设定
* @return 0 - 成功,-1 - 失败
*/
int GetPixelDatasFrmBMP(unsigned char *pFileHead, PT_PixelDatas ptPixelDatas)
{
int y;
int width;
int height;
int BMPbpp;
int LineWidthReal;
int LineWidthAlign;
unsigned char *pSrc;
unsigned char *pDest;
BITMAPFILEHEADER *ptBITMAPFILEHEADER;
BITMAPINFOHEADER *ptBITMAPINFOHEADER;
ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)pFileHead;
ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(pFileHead + sizeof(BITMAPFILEHEADER));
/* 获取bmp文件信息 */
width = ptBITMAPINFOHEADER->biWidth;
height = ptBITMAPINFOHEADER->biHeight;
BMPbpp = ptBITMAPINFOHEADER->biBitCount;
if (BMPbpp != 24) {
DebugPrint(APP_ERR"can not support %d bpp\n", BMPbpp);
return -1;
}
/* 设置结构体 */
ptPixelDatas->height = height;
ptPixelDatas->width = width;
ptPixelDatas->linebytes = width * ptPixelDatas->bpp / 8;
/* 分配缓冲区 */
ptPixelDatas->PixelDatas = (unsigned char *)malloc(width * height * ptPixelDatas->bpp / 8);
if (ptPixelDatas->PixelDatas == NULL) {
DebugPrint(APP_ERR"malloc ptPixelDatas->PixelDatas err\n");
return -1;
}
/* 获取bmp像素信息:存储像素的起始是图片左下角 */
LineWidthReal = width * BMPbpp / 8; //每行像素所占的字节
LineWidthAlign = (LineWidthReal + 3) & ~0x3; //向4取整后的每行像素所占的字节
pSrc = pFileHead + ptBITMAPFILEHEADER->bfOffBits; //像素信息的源地址
pSrc = pSrc + LineWidthAlign * (height- 1); //移动到存储图片左上角的数据地址
pDest = ptPixelDatas->PixelDatas; //数据最终的去向
for (y = 0; y < height; y++) {
//memcpy(pDest, pSrc, LineWidthReal);
CoverOneLine(width, BMPbpp, ptPixelDatas->bpp, pSrc, pDest);
pSrc -= LineWidthAlign; //bmp二进制数据
pDest += ptPixelDatas->linebytes; //LCD显示数据
}
return 0;
}
/**
* @Description: 释放存储bmp文件中的像素信息的内存
* @param ptPixelDatas - 位图信息,存储像素信息
* @return 0 - 释放成功
*/
static int FreePixelDatasForBMP(PT_PixelDatas ptPixelDatas)
{
free(ptPixelDatas->PixelDatas);
return 0;
}
T_PicFileParser s_tBMPParser = {
.name = "bmp",
.isSupport = isBMPFormat,
.GetPixelDatas = GetPixelDatasFrmBMP,
.FreePixelDatas = FreePixelDatasForBMP,
};
4、zoom.c
处理图片缩放
设计思路:
- 外部函数调用时,源图片信息存储在
ptOriginPic结构体
,缩放信息存储在ptZoomPic结构体
,在调用前用户已经设置好缩放图片的height、width
等信息。 - 通过以下公式计算得到缩放图片中每个像素在源图片的对应位置
- 根据缩放图片每一行起始像素对应在源图片的像素的位置,以源图片的像素的位置为起始点,复制长度为缩放图片一行宽度的像素数量到缩放图片对应的内存中。
/**
* @file bmp.c
* @brief 处理bmp文件的坐标信息,计算实现缩放
* @version 1.0 (版本声明)
* @author Dk
* @date July 7,2020
*/
#include <stdlib.h>
#include <string.h>
#include "pic_operation.h"
#include "debug_manager.h"
/**
* @Description: 对图片数据处理进行实现缩放,采用近邻取样插值
* @param ptOriginPic - 缩放前图片信息, ptZoomPic - 缩放后图片信息
* @return 0 - 成功缩放,-1 - 不支持缩放
*/
int PicZoom(PT_PixelDatas ptOriginPic, PT_PixelDatas ptZoomPic)
{
unsigned long x, y;
unsigned long PixelBytes;
unsigned long SrcY;
unsigned long DstWidth;
unsigned long *pSrcXTable;
unsigned char *pDest;
unsigned char *pSrc;
if (ptOriginPic->bpp != ptZoomPic->bpp) {
DebugPrint(APP_NOTICE"can not support bpp where the source %d and destination %d are different\n"
, ptOriginPic->bpp, ptZoomPic->bpp);
return -1;
}
DstWidth = ptZoomPic->width;
PixelBytes = ptOriginPic->bpp / 8;
/* 分配空间 */
pSrcXTable = (unsigned long *)malloc(sizeof(unsigned long) * DstWidth);
if (pSrcXTable == NULL) {
DebugPrint(APP_ERR"pSrcXTable malloc err\n");
return -1;
}
/* 获取源图片一行中像素点的x坐标 */
for (x = 0; x < DstWidth; x++)
pSrcXTable[x]=(x * ptOriginPic->width / ptZoomPic->width);
/* 计算缩放后的坐标信息 */
for (y = 0; y < ptZoomPic->height; y++) {
SrcY = (y * ptOriginPic->height / ptZoomPic->height); //获取源图片一列中像素点的y坐标
pSrc = ptOriginPic->PixelDatas + SrcY * ptOriginPic->linebytes; //原图每行起始像素在内存的地址
pDest = ptZoomPic->PixelDatas + y * ptZoomPic->linebytes; //缩放图每行起始像素在内存的地址
/* 原图坐标:(pSrcXTable[x], SrcY)
* 缩放坐标:(x, y)
*/
for (x = 0; x < DstWidth; x++){
memcpy(pDest + x * PixelBytes, pSrc + pSrcXTable[x] * PixelBytes, PixelBytes);
}
}
/* 释放空间 */
free(pSrcXTable);
return 0;
}
5、merge.c
处理缩放后的数据到Frambufer中
/**
* @file merge.c
* @brief 把zoom.c缩放后处理的像素信息存放到Framebuffer中
* @version 1.0 (版本声明)
* @author Dk
* @date July 7,2020
*/
#include <stdlib.h>
#include <string.h>
#include "pic_operation.h"
#include "debug_manager.h"
int PicMerge(int x, int y, PT_PixelDatas ptSmallPic, PT_PixelDatas ptBigPic)
{
int i;
unsigned char *pDst;
unsigned char *pSrc;
if ((ptSmallPic->width > ptBigPic->width) ||
(ptSmallPic->height > ptBigPic->height) ||
(ptSmallPic->bpp != ptBigPic->bpp)) {
DebugPrint(APP_ERR"SmallPic > BigPic || SmallPic.bpp != BigPic.bpp\n");
return -1;
}
pSrc = ptSmallPic->PixelDatas;
pDst = ptBigPic->PixelDatas + y * ptBigPic->width + x * ptBigPic->bpp / 8;
for (i = 0; i < ptSmallPic->height; i++) {
memcpy(pDst, pSrc, ptSmallPic->linebytes);
pSrc += ptSmallPic->linebytes;
pDst += ptBigPic->linebytes;
}
return 0;
}
6、main.c
协调
#include <unistd.h>
#include <stdlib.h>
#include <stdio.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>
#include "config.h"
#include "page_manager.h"
#include "encoding_manager.h"
#include "fonts_manager.h"
#include "disp_manager.h"
#include "input_manager.h"
#include "debug_manager.h"
#include "pic_operation.h"
#include "render.h"
/* digitpic <bmp_file> */
int main(int argc, char **argv)
{
PT_DispOpr ptDispOpr;
int error;
int FDbmp;
int ret;
unsigned char *BMPmem;
struct stat BMPstat;
extern T_PicFileParser s_tBMPParser;
T_PixelDatas BMPPixelDatas;
T_PixelDatas BMPSamllPic;
T_PixelDatas PixelDataFB;
if (argc != 2) {
DebugPrint(APP_NOTICE" %s <bmp_file>\n", argv[0]);
return -1;
}
/* 初始化调试系统 */
error = DebugInit();
if (error) {
DBG_PRINTF("DebugInit error!\n");
return -1;
}
error = InitDebugChanel();
if (error) {
printf("InitDebugChanel error!\n");
return -1;
}
error = DisplayInit();
if (error) {
DBG_PRINTF("DisplayInit error!\n");
return -1;
}
/* 获得负责显示的结构体 */
ptDispOpr = GetDispOpr("fb");
/* 初始化显示设备 */
ptDispOpr->DeviceInit();
/* 清屏 */
ptDispOpr->CleanScreen(0);
/* 打开bmp文件 */
FDbmp = open(argv[1], O_RDWR);
if (FDbmp < 0) {
DebugPrint(APP_ERR"can not open %s\n", argv[1]);
return -1;
}
/* 获得文件的大小 */
fstat(FDbmp, &BMPstat);
/* 直接映射到内存 */
BMPmem = (unsigned char *)mmap(NULL, BMPstat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, FDbmp, 0);
if (BMPmem == (unsigned char *)-1) {
DebugPrint(APP_ERR"mmap err\n");
return -1;
}
/* 打开bmp文件 */
ret = s_tBMPParser.isSupport(BMPmem);
if (ret == 0) {
DebugPrint(APP_ERR"can not support bmp_file: %s\n", argv[1]);
return -1;
}
BMPPixelDatas.bpp = ptDispOpr->Bpp;
/* 获得图片数据 */
ret = s_tBMPParser.GetPixelDatas(BMPmem, &BMPPixelDatas);
if (ret != 0) {
DebugPrint(APP_ERR"GetPixelDatas err\n");
return -1;
}
/* 设置LCD上显示图片的信息 */
PixelDataFB.height = ptDispOpr->Yres;
PixelDataFB.width = ptDispOpr->Xres;
PixelDataFB.bpp = ptDispOpr->Bpp;
PixelDataFB.linebytes = ptDispOpr->Xres * ptDispOpr->Bpp / 8;
PixelDataFB.PixelDatas = ptDispOpr->pDispMem;
/* 显示原始图片 */
PicMerge(0, 0, &BMPPixelDatas, &PixelDataFB);
/* 设置LCD上显示缩小图片的信息 */
BMPSamllPic.height = BMPPixelDatas.height / 4;
BMPSamllPic.width = BMPPixelDatas.width / 4;
BMPSamllPic.bpp = BMPPixelDatas.bpp;
BMPSamllPic.linebytes = BMPSamllPic.width * BMPSamllPic.bpp / 8;
BMPSamllPic.PixelDatas = (unsigned char *)malloc(BMPSamllPic.linebytes * BMPSamllPic.height);
if (BMPSamllPic.PixelDatas == NULL) {
DebugPrint(APP_ERR"malloc BMPSamllPic.PixelDatas err\n");
return -1;
}
/* 缩放图片,原来的1/4 */
PicZoom(&BMPPixelDatas, &BMPSamllPic);
/* 显示缩小的图片 */
PicMerge(128, 128, &BMPSamllPic, &PixelDataFB);
/* 释放 */
free(BMPSamllPic.PixelDatas);
/* 缩放 */
return 0;
}
四、Makefile修改
1、/render目录下Makefile
# render子目录Makefile
obj-y += render.o
obj-y += operation/
obj-y += format/
1.1 /render/format目录下Makefile
# /render/format子目录Makefile
obj-y += bmp.o
1.2 /render/operation目录下Makefile
# /render/operation子目录Makefile
obj-y += merge.o
obj-y += zoom.o
1.3 顶层目录Makefile
- 添加render目录:
obj-y += render/
- 完整文件:
# 顶层目录Makefile
#
# 目的:
# 1、每个子目录都会建立一个Makefile,包含当前目录下.c文件.h文件
# 2、顶层目录下
# 交叉编译工具链
CROSS_COMPILE = arm-linux-
# 定义一些变量 $(CROSS_COMPILE):取出该变量的值 $(CROSS_COMPILE)gcc->arm-linux-gcc
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
# 取出变量的值
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
# := 简单扩展型变量的值是一次扫描永远使用
# CFLAGS 方便您利用隐含规则指定编译C语言源程序的旗标
# -Wall 帮助列出所有警告信息
# -02 多优化一些,除了涉及空间和速度交换的优化选项,执行几乎所有的优化工作
# -g 可以认为它是缺省推荐的选项
CFLAGS := -Wall -O2 -g
# 把当前目录下的include目录下指定为系统目录
# += 为已经定以过的变量的值追加更多的文本
# -I 指定搜寻包含makefile文件的路径
# $(shell pwd) 执行shell命令的pwd命令,获取执行命令的结果
CFLAGS += -I $(shell pwd)/include
# LDFLAGS 用于调用linker(‘ld’)的编译器的额外标志
# -l 连接库的搜寻目录 -lm调用math库 -lfreetype调用freetype库
LDFLAGS := -lm -lfreetype -lts -lpthread
# 取出变量的值
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
# TARGET 目标变量
# := 简单扩展型变量的值是一次扫描永远使使用
TARGET := digitpic
obj-y += main.o
obj-y += display/
obj-y += encoding/
obj-y += fonts/
obj-y += input/
obj-y += debug/
obj-y += render/
# 规则 arm-linux-gcc -lm -lfreetype -o show_file built-in.o
all :
make -C ./ -f $(TOPDIR)/Makefile.build
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o
# clean 删除所有make正常创建的文件
# 规则 找到所有make创建出来.o文件进行删除
# 删除show_file
clean :
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
# distclean 删除所有正常创建的文件
# 配置文件或为编译正常创建的准备文件,甚至makefile文件自身不能创建的文件
# 规则 找到所有mkae创建出来的.o文件进行删除
# 删除show_file
distclean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
五、编译与运行
- 执行
make
,获得digitpic
可执行文件
- 把可执行文件与显示的图片文件上传到开发板的根文件系统
- 执行
./digitpic time.bmp