数码相框_电子书之代码阅读及编写(7)
数码相框_电子书之代码阅读及编写(7)
在LCD显示任意编码的文本文件,类似电子书
怎样在LCD上显示文件:
需要哪几个文件?
1、顶部文件
通过main.c分析命令行的操作,然后初始化各个管理文件下的结构体,比如DisplayInit();
然后进入draw.c,在draw.c里按顺序调用3个管理文件,并控制显示。
2、encoding_manager.c管理文件
管理4个编码子文件:utf-8.c,utf-16be.c,utf-16le.c,ascii.c
比如utf-8.c:判断某个文件是否以0xEF,0xBB,0xBF开头, 若是,则接下来通过utf-8规律,来转换字节编码
3、font_maneger.c管理文件
管理3个字体子文件:ascii.c(英文点阵),gbk.c(中文点阵),freetype(矢量字体)
用来将获取的字符编码转换为点阵信息。
4、disp_manager.c管理文件
管理2个显示文件:fb.c(LCD显示) crt.c(串口显示)
主要负责将点阵信息发送到显存或串口上。
在3个管理.h头文件里,声明3个不同的结构体
T_DispOpr:显示操作结构体
T_FontOpr:字体操作结构体
T_EncodingOpr:编码操作结构体
5、首先来写显示部分
fb.c需要用到fb初始化函数,以及显示像素函数,当我们换页时,还需要一个清屏函数,所以有3个函数
typedef struct DispOpr {char *name;int iXres; //x像素个数int iYres; //y像素个数int iBpp; //每个像素多少位int (*DeviceInit)(void); //该函数对于fb.c,是用来打开/dev/fb0,获取var和fix,然后mmapint (*ShowPixel)(int iPenX, int iPenY, unsigned int dwColor); //显示一个像素点int (*CleanScreen)(void); //清屏struct DispOpr *ptNext; //指向下一个注册的T_DispOpr结构体
}T_DispOpr, *PT_DispOpr;
在disp_managet.c里
定义一个空链表:static PT_DispOpr g_ptDispOprHead = NULL;
写一个Register DispOpr()函数,子文件通过调用该函数来注册到链表g_ptDispOprHead里
在disp_manager.c里
定义一个DisplayInit()函数,用来被main.c初始化时调用。
在fb.c里定义g_tFBOpr:
static T_DispOpr g_tFBOpr = {.name = "fb",.DeviceInit = FBDeviceInit, //该函数打开/dev/fb0,然后获取fix和var成员,来mmap().ShowPixel = FBShowPixel, //该函数根据x,y,color这3个函数参数,来显示一个像素点.CleanScreen = FBCleanScreen, //该函数,通过memset来将显存清0
};
并定义一个FBInit()函数,将结构体g_tFBOpr注册到g_ptDispOprHead链表里:
int FBInit(void)
{return RegisterDispOpr(&g_tFBOpr);
}
由于FBInit()被disp_managet.c文件的disp_manager.c文件的DisplayInit()调用,所以不能写static了。
6、写字体部分
和显示部分思路一样,在fonts_managet.h里的声明了两个结构体,如下所示:
typedef struct FontBitMap {int iXLeft; //文字最左边X坐标int iYTop; //文字最顶部Y坐标int iXMax; //文字的一行像素有多大int iYMax; //文字的一列像素有多大int iBpp; //像素格式int iPitch; /* 对于单色位图, 两行象素之间的跨度,比如8*16,则跨度是8(文字的一行像素有8位) */int iCurOriginX; //当前原点x坐标int iCurOriginY; //当前原点y坐标int iNextOriginX; //下个文字的原点x坐标int iNextOriginY; //下个文字的原点y坐标unsigned char *pucBuffer; //存放文字的像素数据
}T_FontBitMap, *PT_FontBitMap;
typedef struct FontOpr {char *name;int (*FontInit)(char *pcFontFile, unsigned int dwFontSize); //初始化字体文件int (*GetFontBitmap)(unsigned int dwCode, PT_FontBitMap ptFontBitMap); //根据dwCode编码获取字体位图,并将信息(坐标,数据,格式等)存到ptFontBitMap里struct FontOpr *ptNext;
}T_FontOpr, *PT_FontOpr;
在fonts_manager.c里
定义一个空链表:static PT_FontOpr g_ptFontOprHead = NULL;
写一个RegisterFontOpr()函数,子文件通过调用该函数来注册到链表g_ptFontOprHead里
写一个GetFontOpr()函数,用来获取字体的name
写一个FontsInit()函数,用来被main.c初始化时调用:
int FontsInit(void)
{int iError;iError = ASCIIInit(); //调用./fonts/ascii.c里的ASCIIInit()函数if (iError){DBG_PRINTF("ASCIIInit error!\n");return -1;}iError = GBKInit(); //调用./fonts/gbk.c里的GBKInit ()函数if (iError){DBG_PRINTF("GBKInit error!\n");return -1;}iError = FreeTypeInit(); //调用./fonts/freetype.c里的FreeTypeInit ()函数if (iError){DBG_PRINTF("FreeTypeInit error!\n");return -1;}return 0;
}
写一个GetFontOpr()函数,该函数被编码文件调用,来使编码文件与字体关联起来,比如通过utf-8编码找到对应的freetype字体。
写字体文件,以freetype.c(矢量字体)为例
首先定义一个T_FontOpr结构体
定义FreeTypeFontInit成员函数,初始化freetype库,设置字体大小等
定义GetFontBitmap成员函数,FT_Load_Char()转换位图,保存在PT_FontBitMap里
具体内容如下:
#include <config.h>
#include <fonts_manager.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_Hstatic int FreeTypeFontInit(char *pcFontFile, unsigned int dwFontSize);
static int FreeTypeGetFontBitmap(unsigned int dwCode, PT_FontBitMap ptFontBitMap);static T_FontOpr g_tFreeTypeFontOpr = {.name = "freetype",.FontInit = FreeTypeFontInit,.GetFontBitmap = FreeTypeGetFontBitmap,
};static FT_Library g_tLibrary;
static FT_Face g_tFace;
static FT_GlyphSlot g_tSlot;static int FreeTypeFontInit(char *pcFontFile, unsigned int dwFontSize)
{int iError;/* 显示矢量字体 */iError = FT_Init_FreeType(&g_tLibrary ); /* initialize library *//* error handling omitted */if (iError){DBG_PRINTF("FT_Init_FreeType failed\n");return -1;}iError = FT_New_Face(g_tLibrary, pcFontFile, 0, &g_tFace); /* create face object *//* error handling omitted */if (iError){DBG_PRINTF("FT_Init_FreeType failed\n"); return -1;}g_tSlot = g_tFace->glyph;iError = FT_Set_Pixel_Sizes(g_tFace, dwFontSize, 0);if (iError){DBG_PRINTF("FT_Set_Pixel_Sizes failed : %d\n", dwFontSize);return -1;}return 0;
}static int FreeTypeGetFontBitmap(unsigned int dwCode, PT_FontBitMap ptFontBitMap)
{int iError;int iPenX = ptFontBitMap->iCurOriginX; //初始值为:0 dwFontSizeint iPenY = ptFontBitMap->iCurOriginY;
#if 0FT_Vector tPen;tPen.x = 0;tPen.y = 0;/* set transformation */FT_Set_Transform(g_tFace, 0, &tPen);
#endif/* load glyph image into the slot (erase previous one) *///iError = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER );iError = FT_Load_Char(g_tFace, dwCode, FT_LOAD_RENDER | FT_LOAD_MONOCHROME);if (iError){DBG_PRINTF("FT_Load_Char error for code : 0x%x\n", dwCode);return -1;}//DBG_PRINTF("iPenX = %d, iPenY = %d, bitmap_left = %d, bitmap_top = %d, width = %d, rows = %d\n", iPenX, iPenY, g_tSlot->bitmap_left, g_tSlot->bitmap_top, g_tSlot->bitmap.width, g_tSlot->bitmap.rows);/*笛卡尔坐标的左上角是(bitmap_left,bitmap_top),对应LCD的左上角是(Y+bitmap_left,Y-bitmap_top)*/ptFontBitMap->iXLeft = iPenX + g_tSlot->bitmap_left;ptFontBitMap->iYTop = iPenY - g_tSlot->bitmap_top;ptFontBitMap->iXMax = ptFontBitMap->iXLeft + g_tSlot->bitmap.width;ptFontBitMap->iYMax = ptFontBitMap->iYTop + g_tSlot->bitmap.rows;ptFontBitMap->iBpp = 1;ptFontBitMap->iPitch = g_tSlot->bitmap.pitch;ptFontBitMap->pucBuffer = g_tSlot->bitmap.buffer;ptFontBitMap->iNextOriginX = iPenX + g_tSlot->advance.x / 64;ptFontBitMap->iNextOriginY = iPenY;//DBG_PRINTF("iXLeft = %d, iYTop = %d, iXMax = %d, iYMax = %d, iNextOriginX = %d, iNextOriginY = %d\n", ptFontBitMap->iXLeft, ptFontBitMap->iYTop, ptFontBitMap->iXMax, ptFontBitMap->iYMax, ptFontBitMap->iNextOriginX, ptFontBitMap->iNextOriginY);return 0;
}int FreeTypeInit(void)
{return RegisterFontOpr(&g_tFreeTypeFontOpr);
}
7、写编码部分
在encoding_managet.h里的T_EncodingOpr结构体,声明如下:
typedef struct EncodingOpr {char *name;int iHeadLen; //文件以多少字节开头PT_FontOpr aptFontOprSupported[4]; //指针数组,用来存放支持该编码的字体结构体,以后就通过这个来显示文字int (*isSupport)(unsigned char *pucBufHead); //该函数判断要显示的文件是否支持XX格式int (*GetCodeFrmBuf)(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode); //将文件里的字节转为编码,存到*pdwCode里struct EncodingOpr *ptNext; //链表
}T_EncodingOpr, *PT_EncodingOpr;
在encoding_manager.c里
定义一个空链表:static PT_EncodingOpr g_ptEncodingOprHeaad = NULL
写一个RegisterEncodingOpr()函数,子文件通过调用该函数来注册到链表g_ptEncodingOprHead里
写一个SelectEncodingOprForFile()函数,通过链表来找isSupport()成员函数,判断要显示的文字支持哪种格式
写一个EncodingInit()函数,调用每个编码文件的init()函数,里面会初始化编码T_EncodingOpr结构体,并添加编码所支持的文字结构体
写编码文件,以utf-8.c为例
比如:
对于ansi.c(编码文件),其实就是GBK编码,ascii占1字节,使用ascii点阵库,汉字占2字节,使用HZK16汉字库。
对于utf-8.c(编码文件),ascii只占1字节,使用ascii点阵库,而汉字占2~4字节,由于freetype字库默认支持的是utf-16格式,所以需要utf-8转换为utf-16后,再使用freetype字库,转换如下图所示:
8、写draw.c
8.1 首先定义一个T_PageDesc结构体
用来控制分页换行用,需要用到双向链表
typedef struct PageDesc {int iPage; //当前页数unsigned char *pucLcdFirstPosAtFile; //在LCD上第一个字符位置位于在文件哪个位置unsigned char *pucLcdNextPageFirstPosAtFile; //下一页的LCD上第一个字符位置位于文件哪位置struct PageDesc *ptPrePage; //上一页链表,指向上一个T_PageDesc结构体struct PageDesc *ptNextPage; //下一页链表,指向下一个T_PageDesc结构体} T_PageDesc, *PT_PageDesc;
8.2 写一个OpenTextFile()函数
用来打开文本文件,然后mmap(),并判断支持哪种编码,并获取文件第一个字符位置
static int g_iFdTextFile; //文件描述符
static unsigned char *g_pucTextFileMem; //内存映射基地址
static unsigned char *g_pucTextFileMemEnd; //内存映射结尾地址
static PT_EncodingOpr g_ptEncodingOprForFile; //用来指向该文件支持的编码EncodingOpr结构体static unsigned char *g_pucLcdFirstPosAtFile; //第一个字符位于文件的位置
int OpenTextFile(char *pcFileName)
{g_iFdTextFile = open(pcFileName, O_RDONLY);... ...if(fstat(g_iFdTextFile, &tStat)){DBG_PRINTF("can't get fstat\n");return -1;}
g_pucTextFileMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ, MAP_SHARED, g_iFdTextFile, 0);
g_pucTextFileMemEnd = g_pucTextFileMem + tStat.st_size; g_ptEncodingOprForFile = SelectEncodingOprForFile(g_pucTextFileMem); //获取支持的编码格式if (g_ptEncodingOprForFile){g_pucLcdFirstPosAtFile = g_pucTextFileMem + g_ptEncodingOprForFile->iHeadLen; //去掉文件编码前缀的开头位置return 0;}else{return -1;}
}
8.3 写一个ShowOnePage()显示一页函数
首先设置原点xy为(0, fontsize),通过编码结构体的成员函数获取编码,判断编码是否为\r \n \t,然后通过字体结构体的成员函数将编码转换为位图,然后判断是否换行,满页,最后显示
8.4 写一个SetTextDetail()函数
通过支持的编码,来设置HZK,freetype,ascii字体文件,以及字体大小,供给main.c调用
9、写main.c
main.c主要用来通过main.c分析命令行的操作,然后初始化各个管理文件下的结构体,比如DisplayInit();
命令行:
./show_file [-l] [-s Size] [-d Dispshow] [-f freetype_font_file] [-h HZK] <text_file>//-l :列出选项//-s :设置文字大小//-d :选择显示到哪里,是fb还是crt//-f :指定矢量文字文件位置//-h :指定汉字库文件位置// text_file:指定要显示哪个文件
main.c流程:
1、通过getopt(argc, argv, "ls:f:h:d:")来解析命令行,获取每个选项后的参数
2、然后调用管理文件的初始化函数,去初始化显示文件fb.c,字体文件freetype.c,gbk.c等,以及添加链表,比如:iError = DisplayInit();//最终调用FBInit();->RegisterDispOpr(&g_tFBOpr);
3、因为optind等于<text_file>位置,所以通过optind打开<text_file>文件:
strncpy(acTextFile, argv[optind], 128);acTextFile[127] = '\0';
iError = OpenTextFile(acTextFile); //里面进行mmap(),并获取该文件所支持的编码结构体
4、设置文本细节(HZK库,freetype库,文字大小)
iError = SetTextDetail(acHzkFile, acFreetypeFile, dwFontSize); //该函数位于draw.c
5、调用SelectAndInitDisplay()函数,通过[-d Dispshow]来从g_ptDisOprHead显示链表里,找到name相同的结构体,并放入g_ptDispOpr结构体,然后执行g_ptDispOpr->DeviceInit();来初始化LCD
iError = SelectAndInitDisplay(acDisplay);
6、调用ShowNextPage()显示第一页
7、然后进入while(1)里,通过getchar()来获取命令行参数
输入n,则调用ShowNextPage(),显示下一页
输入u,则调用ShowNextPage(),显示上一页
输入q退出
数码相框_电子书之代码阅读及编写(7)相关推荐
- linux vim ctags,Linux环境上代码阅读与编写的利器-vim+ctags+cscope
Linux环境下代码阅读与编写的利器----vim+ctags+cscope 所谓工欲善其事,必先利其器. 从事Linux程序开发,特别是Linux驱动程序的开发,不管是通过windows下虚拟一个L ...
- python程序中的空格和空行可有可无_为了让代码更加紧凑,编写Python程序时应尽量避免加入空格和空行。_学小易找答案...
[判断题]Python 代码的注释只有一种方式,那就是使用#符号. [判断题]为了让代码更加紧凑,编写Python程序时应尽量避免加入空格和空行. [多选题]脱水后的污泥可采取( )方法进行最终处理. ...
- 3、数码相框之电子书
文章目录 1.效果及框架 2.代码阅读及编写 2.1.显示器模块实现大致思路 2.2.字体点阵模块大致思路 2.3.提取文件编码模块大致思路 2.4.测试 3.指针的操作 4.链表的操作 5.在PC上 ...
- vsc 搜索特定代码_特定问题的通用解决方案:何时编写代码以及何时编写代码...
vsc 搜索特定代码 by Rina Artstain 通过丽娜·阿斯特斯坦 特定问题的通用解决方案:何时编写代码以及何时编写代码 (Generic solutions to specific pro ...
- 如何读懂python代码_教你如何阅读 Python 开源项目代码
作者: Destiny 来源:https://learnku.com/articles/23010/teach-you-to-read-the-python-open-source-project-c ...
- 安卓pdf阅读器_电子书阅读器买哪个好?除了kindle,还有这几个品牌可以选
如今越来越多的人喜欢看电子书了,因为电子书不管是阅读还是携带,都十分方便,价格也普遍比实体书便宜.出于护眼的目的,很多小伙伴都有过购买专业电子书阅读器的想法,但不太清楚电子书阅读器哪个好.今天我来给大 ...
- 【代码阅读】PointNet++中ball query的CUDA实现
文章目录 本文为PointNet++ CUDA代码阅读系列的第三部分,其他详见: (一)PointNet++代码梳理 (二)PointNet++中的FPS的CUDA实现 (三)PointNet++中b ...
- epub 电子书软件代码销售
epub 电子书软件代码销售 本套代码用来读取epub 格式电子书. 主要面向:有一定开发能力的人员,和有一定制作水平的朋友们. 用途:自己开发学习,钻研,出appstore 应用,卖钱,加广告赚钱等 ...
- ORB_SLAM2代码阅读(5)——Bundle Adjustment
ORB_SLAM2代码阅读(5)--Bundle Adjustment 1. 说明 2. Bundle Adjustment(BA)的物理意义 3. BA的数学表达 4. BA的求解方法 4.1 最速 ...
最新文章
- 【LeetCode从零单排】No189	.Rotate Array
- ad09机械层说明_悉数PCB上的各种层
- laravel5.6 php,Laravel5.6中的队列简单使用
- Unity3dShader_边缘发光效果
- VS调试时怎么跳过for循环?
- 接水 2019-12-27
- (视频+图文)机器学习入门系列-第7章 KNN算法
- mysql 批量修改数据库存储引擎_mysql批量修改表存储引擎
- [SIR数据集实验][2]Java类数据集相应工具使用的小经验
- 理论基础 —— 排序 —— 堆排序
- 14的虚拟机可以用在15上面吗_环氧底漆是什么漆,分很多种吗?环氧底漆都可以用在什么上面...
- go 语言随机数的生成
- 橙子君正在维护服务器,橙子VR常见问题有哪些 橙子VR常见问题答案汇总
- WIndowsServer2012 DHCP服务器配置
- 【SASS】 一个Opacity混合器(外加如何让背景透明 文字不透明)
- 《X战警:逆转未来》热映 破福斯海外开画纪录
- [游泳] 游泳学习课程
- 大漠穷秋:全面解读Angular 4.0核心特性
- 《Photoshop修饰与合成专业技法》—第1章伪造的抠像:第一部分
- 转载 学写钢笔字应该注意些什么
热门文章
- 计算机丢失MdFunc32,win10系统启动游戏提示计算机丢失xinpUT1-3.dll的图文办法
- Spring Cloud Gateway 503 Service Unavailable
- Ubuntu 通过无线 连PPPOE的 上网
- 报错:axis2.AxisFault: Transport error: 401 Error: Unauthorized
- 自学XML——基本用法
- tyvj 2054 [Nescafé29]四叶草魔杖
- python双色球选号_用Python帮你选注双色球号码 赠送清华大学出版社Python从小白到大牛电子书籍一本...
- 如何用应用程序模拟键盘和鼠标按键
- uniapp获取元素的宽度、高度
- 党员管理系统 spring boot