文件结构
Makefile:
1 CROSSCOMPILE := arm-linux- 2 CFLAGS := -Wall -O2 -c 3 LDFLAGS := -lm -lfreetype 4 CC := $(CROSSCOMPILE)gcc 5 LD := $(CROSSCOMPILE)ld 6 7 OBJS := main.o 8 font/font_manager.o 9 font/font_gbk.o 10 font/font_asc.o 11 display/display_manager.o 12 display/lcd_fb.o 13 draw/draw.o 14 15 all: $(OBJS) 16 $(CC) $(LDFLAGS) -o txt $^ 17 18 clean: 19 rm -f txt 20 rm -f $(OBJS) 21 22 %.o:%.c 23 $(CC) $(CFLAGS) -o $@ $<
main.c
1 #include <stdio.h> 2 #include "font/font_manager.h" 3 #include "display/display_manager.h" 4 #include "draw/draw.h" 5 6 int main(int argc,char **argv) 7 { 8 //命令操作 9 char cmd; 10 //第一个参数 要显示的TXT 文件 11 char *file = argv[1]; 12 13 if(-1 == font_init()) 14 { 15 printf("font manager init error "); 16 return -1; 17 } 18 printf("font init ok "); 19 20 if(-1 == display_init()) 21 { 22 printf("display manager init error "); 23 return -1; 24 } 25 printf("display init ok "); 26 27 if(-1 == open_txt(file)) 28 { 29 printf("cat't open %s txt ", file); 30 return -1; 31 } 32 printf("read file : %s ok ", file); 33 show_page(); 34 35 while(1) 36 { 37 cmd = getchar(); 38 if('n' == cmd) 39 { 40 show_page_next(); 41 } 42 if('p' == cmd) 43 { 44 show_page_pre(); 45 } 46 if('q' == cmd) 47 { 48 return 0; 49 } 50 } 51 return 0; 52 }
HZK16 这个就不发了,网上自己找吧。
display/display_manager.h
1 #ifndef __DISPLAY_MANAGER__ 2 #define __DISPLAY_MANAGER__ 3 4 #include <stdio.h> 5 #include <string.h> 6 7 typedef struct display{ 8 char *name; 9 int width; 10 int height; 11 int (*display_init)(void); 12 int (*display_px)(int color, int x, int y); 13 struct display *next; 14 } T_display, *PT_display; 15 16 int display_init(void); 17 int display_register(PT_display new_display); 18 PT_display display_select(char *name); 19 20 int init_lcd_fb(); 21 22 #endif
display/display_manager.c
1 #include "display_manager.h" 2 3 static PT_display head_pt_display; 4 5 PT_display display_select(char *name) 6 { 7 PT_display temp_pt_display = head_pt_display; 8 while(temp_pt_display) 9 { 10 if(0 == strcmp(name, temp_pt_display->name)) 11 { 12 temp_pt_display->display_init(); 13 return temp_pt_display; 14 } 15 else 16 { 17 temp_pt_display = temp_pt_display->next; 18 } 19 } 20 return NULL; 21 } 22 23 int display_init(void) 24 { 25 if(-1 == init_lcd_fb()) 26 { 27 printf("lcd fb init error "); 28 return -1; 29 } 30 return 0; 31 } 32 33 int display_register(PT_display new_display) 34 { 35 PT_display temp_pt_display = head_pt_display; 36 new_display->next = NULL; 37 if(! head_pt_display) 38 { 39 head_pt_display = new_display; 40 } 41 else 42 { 43 while(temp_pt_display->next) 44 { 45 temp_pt_display = temp_pt_display->next; 46 } 47 temp_pt_display = new_display; 48 } 49 return 0; 50 }
display/lcd_fb.c
1 #include "display_manager.h" 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 7 #include <linux/fb.h> 8 9 #include <sys/ioctl.h> 10 11 #include <unistd.h> 12 13 #include <string.h> 14 15 #include <sys/mman.h> 16 17 static int lcd_fb_display_init(void); 18 static int lcd_fb_display_px(int color, int x, int y); 19 20 static int fb_fd; 21 static unsigned char *fb_mem; 22 static int px_width; 23 static int line_width; 24 static int screen_width; 25 static struct fb_var_screeninfo var; 26 27 static T_display lcd_disp = { 28 .name = "lcd_fb", 29 .display_init = lcd_fb_display_init, 30 .display_px = lcd_fb_display_px, 31 }; 32 33 int init_lcd_fb() 34 { 35 return display_register(&lcd_disp); 36 } 37 38 static int lcd_fb_display_init(void) 39 { 40 //如果使用 mmap 打开方式 必须是 读定方式 41 fb_fd = open("/dev/fb0", O_RDWR); 42 if(-1 == fb_fd) 43 { 44 printf("cat't open /dev/fb0 "); 45 return -1; 46 } 47 //获取屏幕参数 48 if(-1 == ioctl(fb_fd, FBIOGET_VSCREENINFO, &var)) 49 { 50 close(fb_fd); 51 printf("cat't ioctl /dev/fb0 "); 52 return -1; 53 } 54 //计算参数 55 px_width = var.bits_per_pixel / 8; 56 line_width = var.xres * px_width; 57 screen_width = var.yres * line_width; 58 59 fb_mem = (unsigned char *)mmap(NULL, screen_width, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0); 60 if(fb_mem == (void *)-1) 61 { 62 close(fb_fd); 63 printf("cat't mmap /dev/fb0 "); 64 return -1; 65 } 66 //清屏 67 memset(fb_mem, 0 , screen_width); 68 69 //设置参数 70 lcd_disp.width = var.xres; 71 lcd_disp.height = var.yres; 72 73 return 0; 74 } 75 76 static int lcd_fb_display_px(int color, int x, int y) 77 { 78 unsigned char *pen8; 79 unsigned short *pen16; 80 81 unsigned char r,g,b; 82 83 pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width); 84 pen16 = (unsigned short *)pen8; 85 86 //合并为 565 格式 16bbp 87 r = (color>>16) & 0xff; 88 g = (color>>8) & 0xff; 89 b = (color>>0) & 0xff; 90 *pen16 = (r>>3)<<11 | (g>>2)<<5 | (b>>3); 91 92 return 0; 93 }
draw/draw.h
1 #include <stdio.h> 2 #include <sys/mman.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 7 #include <unistd.h> 8 9 #include "../display/display_manager.h" 10 #include "../font/font_manager.h" 11 12 //定义一个用来实现 上下 翻页的链表 13 typedef struct t_draw_page{ 14 int p; 15 int pos; //相对于 基地址的 位置 16 struct t_draw_page *pre; 17 struct t_draw_page *next; 18 } T_draw_page, *PT_draw_page; 19 20 int open_txt(char *file); 21 int show_page_pre(); 22 int show_page_next(); 23 int show_page(); 24 int draw_page(unsigned char **pos); 25 26 int draw_font(int color, PT_fontMap pt_font); 27 void draw_screen(int color);
draw/draw.c
1 #include "draw.h" 2 int txt_fd; 3 struct stat txt_stat; 4 unsigned char *txt_mem; 5 6 #define TXT_COLOR 0xff0000 7 #define BACKGROUND_COLOR 0xE7DBB5 8 9 PT_display disp; 10 PT_font gbk_font; 11 PT_font asc_font; 12 unsigned char *pos; //当前文件指针位置 13 PT_draw_page pt_head_draw_page; 14 15 //读取文件后使用 内存映射 缺点是大文件时死机,实际上也没有几百M 的文件 16 int open_txt(char *file) 17 { 18 txt_fd = open(file, O_RDONLY); 19 if(-1 == txt_fd) 20 { 21 printf("cat't get txt stat "); 22 return -1; 23 } 24 if(-1 == fstat(txt_fd, &txt_stat)) 25 { 26 close(txt_fd); 27 printf("cat't get txt stat "); 28 return -1; 29 } 30 txt_mem = (unsigned char *)mmap(NULL, txt_stat.st_size, PROT_READ, MAP_SHARED, txt_fd, 0); 31 if(txt_mem == (void *)-1) 32 { 33 close(txt_fd); 34 printf("cat't mmap txt "); 35 return -1; 36 } 37 38 //打开文件成功后 初始化 lcd 39 disp = display_select("lcd_fb"); 40 41 //初始化字库 42 asc_font = font_select("asc"); 43 gbk_font = font_select("gbk"); 44 45 //当前文件指针位置 46 pos = txt_mem; 47 48 printf("lcd width : %d height : %d ", disp->width, disp->height); 49 return 0; 50 } 51 52 void draw_screen(int color) 53 { 54 int x,y; 55 for(x=0; x< disp->width; x++) 56 { 57 for(y=0; y< disp->height; y++) 58 { 59 disp->display_px(color, x, y); 60 } 61 } 62 } 63 64 //渲染一个字模 65 int draw_font(int color, PT_fontMap pt_font) 66 { 67 int i,j,k,x,y; 68 unsigned char *buffer = pt_font->buffer; 69 x = pt_font->x; 70 y = pt_font->y; 71 72 //循环字模 y 73 for(i=0; i<pt_font->height; i++) 74 { 75 //循环字模 x 76 for(j=0; j<pt_font->width/8;j++) 77 { 78 //循环字模 1 字节的数据 79 for(k=7; k>=0; k--) 80 { 81 if(*buffer & (1<<k)) 82 { 83 disp->display_px(color, x+7-k + j*8, y+i); 84 } 85 else 86 { 87 disp->display_px(BACKGROUND_COLOR, x+7-k + j*8, y+i); 88 } 89 } 90 //移动下 1 字节数据 91 buffer++; 92 } 93 } 94 //移动下一个字符显示位置 这里会比较 x y 当显示满屏幕时 退出 返回 -1 95 pt_font->x += pt_font->width; 96 if(pt_font->x >= disp->width) 97 { 98 pt_font->x = 0; 99 pt_font->y += pt_font->height; 100 } 101 //width 已满 height 已满 102 if(pt_font->y >= disp->height) 103 { 104 return -1; 105 } 106 return 0; 107 } 108 109 //渲染一页 110 int draw_page(unsigned char **pos) 111 { 112 T_fontMap font = { 113 .x = 0, /* 字要显示的位置x */ 114 .y = 0, /* 字要显示的位置y */ 115 .width = 0, /* 字高度 */ 116 .height = 0, /* 字大小 */ 117 }; 118 //绘一个背景颜色 119 //draw_screen(0xE7DBB5); 120 draw_screen(BACKGROUND_COLOR); 121 //如何实别是 asc 码 还是 gbk 码 122 //asc 小于 128 123 //gbk 要减去 0xa1 124 //递归读取文字绘制在屏幕上,当屏幕满时退出 125 while(1) 126 { 127 //显示到文本最后了 128 if((*pos - txt_stat.st_size) >= txt_mem ) 129 { 130 return -1; 131 } 132 133 //处理 换行 134 if(' ' == **pos) 135 { 136 (*pos)++; 137 continue; 138 } 139 if(' ' == **pos) 140 { 141 //换行 y + 上一个字符的高度 这里有一点问题,如果 上一行 和下一行 142 //显示的文字高度不同? 不过这不是HTML TXT 每行都一样 143 (*pos)++; 144 font.x = 0; 145 font.y += font.height; 146 //换行时还要检查屏幕是否满 147 if(font.y >= disp->height) 148 { 149 return -1; 150 } 151 continue; 152 } 153 if(' ' == **pos) 154 { 155 //换行 y + 上一个字符的高度 这里有一点问题,如果 上一行 和下一行 156 //显示的文字高度不同? 不过这不是HTML TXT 每行都一样 157 (*pos)++; 158 font.x += font.width; 159 continue; 160 } 161 162 if(0x80 > **pos) 163 { 164 asc_font->font_getMap(*pos, &font); 165 166 //asc 码每次移动1个 167 (*pos)++; 168 } 169 else if((0xa0 < **pos) && (0xa0 < *(*pos+1))) 170 { 171 gbk_font->font_getMap(*pos, &font); 172 173 //gbk 码每次移动2个 174 (*pos) += 2; 175 } 176 //1 屏幕显示完毕 177 if(-1 == draw_font(TXT_COLOR, &font)) 178 { 179 return -1; 180 } 181 } 182 return 0; 183 } 184 185 //显示一页 186 int show_page() 187 { 188 //首次初始化头链表 189 pt_head_draw_page = malloc(sizeof(T_draw_page)); 190 //默认时等于 文件开头 191 draw_page(&pos); 192 pt_head_draw_page->pos = 0; 193 pt_head_draw_page->pre = NULL; 194 pt_head_draw_page->next = NULL; 195 return 0; 196 } 197 198 int show_page_pre() 199 { 200 PT_draw_page now_draw_page = pt_head_draw_page->pre; 201 if(NULL == now_draw_page) 202 { 203 printf("no pre page "); 204 return -1; 205 } 206 207 //重新定义指针 208 pos = txt_mem + now_draw_page->pos; 209 draw_page(&pos); 210 211 pt_head_draw_page = now_draw_page; 212 213 return 0; 214 } 215 216 int show_page_next() 217 { 218 //首次初始化头链表 219 PT_draw_page now_draw_page = pt_head_draw_page; 220 if(! now_draw_page->next) 221 { 222 now_draw_page = malloc(sizeof(T_draw_page)); 223 //先记录下来当前位置在渲染 224 now_draw_page->pos = pos - txt_mem; 225 //默认时等于 文件开头 226 draw_page(&pos); 227 now_draw_page->pre = pt_head_draw_page; 228 now_draw_page->next = NULL; 229 230 //当前链表位置 等于 新生成的 231 pt_head_draw_page = now_draw_page; 232 } 233 else 234 { 235 //如果当前节点有下节点 直接赋值 236 pt_head_draw_page = pt_head_draw_page->next; 237 pos = txt_mem + now_draw_page->pos; 238 draw_page(&pos); 239 } 240 return 0; 241 }
font/font_manager.h
1 #ifndef __FONT_MANAGER__ 2 #define __FONT_MANAGER__ 3 #include <stdio.h> 4 #include <string.h> 5 6 /* 定义一个存放 字模数据,字模显示位置等信息的struct */ 7 typedef struct{ 8 int x; /* 字要显示的位置x */ 9 int y; /* 字要显示的位置y */ 10 int width; /* 字高度 */ 11 int height; /* 字大小 */ 12 unsigned char *buffer; /* 字模的数据 */ 13 } T_fontMap, *PT_fontMap; 14 15 /* 定义一个用来管理字体的 struct */ 16 typedef struct Font{ 17 char *name; 18 int (*font_init)(void); 19 int (*font_getMap)(unsigned char *str, PT_fontMap pfontMap); 20 struct Font *next; 21 } T_font, *PT_font; 22 23 /* 所有字体初始化 */ 24 int font_init(); 25 26 /* 字体注册 */ 27 int font_register(PT_font); 28 29 /* 获取一个字体 */ 30 PT_font font_select(char *name); 31 32 /* gbk 字体初始化 */ 33 int gbk_init(); 34 /* asc 字体初始化 */ 35 int asc_init(); 36 37 #endif
font/font_manager.c
1 #include "font_manager.h" 2 3 /* 静态变量 全局变量 未初始化时内容为 0 局部变量未初始化时内容为垃圾值 */ 4 static PT_font tfont_head; 5 6 /* 工作流程:font_init() 中调用 gbk asc 的初始化方法, gbk_init 中调用 7 * font_register 注册到链表中 在对每个进行 init 操作 8 */ 9 10 /* 所有字体初始化 */ 11 int font_init() 12 { 13 if(-1 == gbk_init()) 14 { 15 printf("gbk font init error "); 16 return -1; 17 } 18 if(-1 == asc_init()) 19 { 20 printf("asc font init error "); 21 return -1; 22 } 23 return 0; 24 } 25 26 /* 字体注册 */ 27 int font_register(PT_font new_font) 28 { 29 PT_font temp_font = tfont_head; 30 //设置链表下一个为 NULL 31 new_font->next = NULL; 32 //注册时初始化字体 33 if(-1 == new_font->font_init()) 34 { 35 return -1; 36 } 37 //没有时添加第一个 38 if(! tfont_head) 39 { 40 tfont_head = new_font; 41 } 42 else 43 { 44 //判断是否有 下个节点 45 while(temp_font->next) 46 { 47 temp_font = temp_font->next; 48 } 49 temp_font->next = new_font; 50 } 51 return 0; 52 } 53 54 PT_font font_select(char *name) 55 { 56 PT_font temp_pt_font = tfont_head; 57 while(temp_pt_font) 58 { 59 if(0 == strcmp(name, temp_pt_font->name)) 60 { 61 return temp_pt_font; 62 } 63 else 64 { 65 temp_pt_font = temp_pt_font->next; 66 } 67 } 68 return NULL; 69 }
font/font_gbk.c
1 #include "font_manager.h" 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <fcntl.h> 6 7 #include <sys/mman.h> 8 9 #include <unistd.h> 10 11 #include <stdio.h> 12 13 14 static int hzk_fd; 15 static struct stat hzk_stat; 16 static unsigned char *hzk_mem; 17 18 static int gbk_font_init(void); 19 static int gbk_font_getMap(unsigned char *str,PT_fontMap pfontMap); 20 21 //语法只适用于 初始化时,不适用在 函数内部。 22 static T_font tfont_gbk = { 23 .name = "gbk", 24 .font_init = gbk_font_init, 25 .font_getMap = gbk_font_getMap, 26 }; 27 28 int gbk_init() 29 { 30 return font_register(&tfont_gbk); 31 } 32 33 /** 34 * 打开字库 35 * 内存映射 36 */ 37 static int gbk_font_init(void) 38 { 39 hzk_fd = open("HZK16", O_RDONLY); 40 if(-1 == hzk_fd) 41 { 42 printf("cat't open HZK16 "); 43 return -1; 44 } 45 if(-1 == fstat(hzk_fd, &hzk_stat)) 46 { 47 printf("cat't get HZK16 size "); 48 return -1; 49 } 50 hzk_mem = (unsigned char *)mmap(NULL, hzk_stat.st_size, PROT_READ, MAP_SHARED, hzk_fd, 0); 51 if(hzk_mem == (void *)-1) 52 { 53 printf("cat't mmap HZK16 "); 54 return -1; 55 } 56 return 0; 57 } 58 59 static int gbk_font_getMap(unsigned char *str, PT_fontMap pfontMap) 60 { 61 //编码规则 62 //GBK 字库 区码 -0xA0 位码 -0xA0 , 每个区中有 94个字符 63 //每个汉字使用16bit * 16bit 表示 64 //高位在左侧显示 65 //16bit 16行 66 pfontMap->buffer = hzk_mem +((*str - 0xa1)*94 + (*(str+1) - 0xa1))*32; 67 pfontMap->width = 16; 68 pfontMap->height = 16; 69 return 0; 70 }
font_asc.c
1 #include "font_manager.h" 2 3 static int asc_font_init(void); 4 static int asc_font_getMap(unsigned char *str, PT_fontMap pfontMap); 5 6 static T_font tfont_asc = { 7 .name = "asc", 8 .font_init = asc_font_init, 9 .font_getMap = asc_font_getMap, 10 }; 11 12 #define FONTDATAMAX 4096 13 static const unsigned char fontdata_8x16[FONTDATAMAX] = { 14 //..... 内容太多 .... 去 linux 内核里面找吧 15 }; 16 17 int asc_init() 18 { 19 return font_register(&tfont_asc); 20 } 21 22 static int asc_font_init(void) 23 { 24 return 0; 25 } 26 27 static int asc_font_getMap(unsigned char *str, PT_fontMap pfontMap) 28 { 29 unsigned char *asc_base = (unsigned char *)fontdata_8x16; 30 //编码规则 31 //8bit 16行 32 pfontMap->buffer = asc_base + *str * 16; 33 pfontMap->width = 8; 34 pfontMap->height = 16; 35 return 0; 36 }