赞
踩
(1)需求分析
1)上电,LCD显示界面
2)根据配置文件,停留在当前界面,或者自动播放下一幅
3)点击,出现对话框,选择手动/自动播放
4)滑动:上——放大,下——缩小,左——上一幅,右——下一幅
5)左右移动速度较快,显示下下一幅
(2)包含进程
1)输入进程:
主控线程:得到事件,socket。
ts线程:使用tslib读触摸屏,封装上报。
按键线程:获取按键值。
2)显示进程
socket线程:上报事件
提前准备好的图片:上一幅、下一幅等。
(3)驱动:触摸屏、LCD,DMA,mmap
根据存储的数字找到对应的字符,并以相应的字体表示出来,即关注:数字–>字符–>字体。
(1)字符表示方法
1)ASCII
一个字节,只包含英文等少量字符。
2)GB2312
2个字节,与ASCII码兼容,一个小于127的字符意义与原来的相同,但是两个大于127的字符连在一起时,就表示一个汉字。
将字符进行分区处理,共有94个区,每个区有94个位。第一个字节代表区,第二个字节代表位。
以GB2312字符集的第一个汉字“啊”字为例,它的区号16,位号01,则区位码是1601,在大多数计算机程序中,高字节和低字节分别加0xA0得到程序的汉字处理编码0xB0A1。计算公式是:0xB0=0xA0+16,0xA1=0xA0+1。
3)BIG5
繁体字使用。
4)Unicode
将世界上所有的符号都纳入其中。
Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。常用UTF-8、UTF-16LE、UTF-16BE等表示。
由于存储的编码不同,所以显示的结果不同。编译时指定字符集:
-finput-charset=charset
-fexec-charset=charset
//例:gcc -finput-charset=GBK -fexec-charset=UTF-8 -o utf ansi.c
(1)点阵字符
英文字符点阵:在内核中,有font_8x16.c等文件描述了ASCII码字库的点阵。
汉字点阵:使用HZK16来表示汉字,HZK16是按分区表排列的点阵文件。对于一个汉字的位置,需要计算。
区码:区号(汉字的第一个字节)-0xa0 (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)
位码:位号(汉字的第二个字节)-0xa0
这样我们就可以得到汉字在HZK16中的绝对偏移位置:
offset=(94*(区码-1)+(位码-1))*32
(2)fbmem
mamp()函数:申请一段用户空间的内存区域,并映射到内核空间某个内存区域。
使用mamp申请一块内存映射到fb0文件,然后应用程序直接向内存写数据,即可直接写入fb0文件(显存地址)。
功能:在LCD中间显示字符“A中”。
#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <linux/fb.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #define FONTDATAMAX 4096 static const unsigned char fontdata_8x16[FONTDATAMAX] = { //内容太多,与内核中fontdata_8x16中相同 }; int fd_fb; struct fb_var_screeninfo var; /* Current var */ struct fb_fix_screeninfo fix; /* Current fix */ int screen_size; unsigned char *fbmem; unsigned int line_width; unsigned int pixel_width; int fd_hzk16; struct stat hzk_stat; unsigned char *hzkmem; /* color : 0x00RRGGBB */ void lcd_put_pixel(int x, int y, unsigned int color) { unsigned char *pen_8 = fbmem+y*line_width+x*pixel_width; unsigned short *pen_16; unsigned int *pen_32; unsigned int red, green, blue; pen_16 = (unsigned short *)pen_8; pen_32 = (unsigned int *)pen_8; switch (var.bits_per_pixel) { case 8: { *pen_8 = color; break; } case 16: { /* 565 */ red = (color >> 16) & 0xff; green = (color >> 8) & 0xff; blue = (color >> 0) & 0xff; color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3); *pen_16 = color; break; } case 32: { *pen_32 = color; break; } default: { printf("can't surport %dbpp\n", var.bits_per_pixel); break; } } } void lcd_put_ascii(int x, int y, unsigned char c) { unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16]; int i, b; unsigned char byte; for (i = 0; i < 16; i++) { byte = dots[i]; for (b = 7; b >= 0; b--) { if (byte & (1<<b)) { /* show */ lcd_put_pixel(x+7-b, y+i, 0xffffff); /* 白 */ } else { /* hide */ lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */ } } } } void lcd_put_chinese(int x, int y, unsigned char *str) { unsigned int area = str[0] - 0xA1; unsigned int where = str[1] - 0xA1; unsigned char *dots = hzkmem + (area * 94 + where)*32; unsigned char byte; int i, j, b; for (i = 0; i < 16; i++) for (j = 0; j < 2; j++) { byte = dots[i*2 + j]; for (b = 7; b >=0; b--) { if (byte & (1<<b)) { /* show */ lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff); /* 白 */ } else { /* hide */ lcd_put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */ } } } } int main(int argc, char **argv) { unsigned char str[] = "中"; fd_fb = open("/dev/fb0", O_RDWR); if (fd_fb < 0) { printf("can't open /dev/fb0\n"); return -1; } if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) { printf("can't get var\n"); return -1; } if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) { printf("can't get fix\n"); return -1; } line_width = var.xres * var.bits_per_pixel / 8; pixel_width = var.bits_per_pixel / 8; screen_size = var.xres * var.yres * var.bits_per_pixel / 8; fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); if (fbmem == (unsigned char *)-1) { printf("can't mmap\n"); return -1; } fd_hzk16 = open("HZK16", O_RDONLY); if (fd_hzk16 < 0) { printf("can't open HZK16\n"); return -1; } if(fstat(fd_hzk16, &hzk_stat)) { printf("can't get fstat\n"); return -1; } hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0); if (hzkmem == (unsigned char *)-1) { printf("can't mmap for hzk16\n"); return -1; } /* 清屏: 全部设为黑色 */ memset(fbmem, 0, screen_size); lcd_put_ascii(var.xres/2, var.yres/2, 'A'); printf("chinese code: %02x %02x\n", str[0], str[1]); lcd_put_chinese(var.xres/2 + 8, var.yres/2, str); return 0; }
(1)矢量字体
问题:上面的测试程序,字体不能缩放。
使用矢量字体。矢量字体,记录关键点,例如
矢量字体:
1)存若干条闭合曲线的关键点。
2)使用数学曲线(贝塞尔曲线等方式)连接关键点。
3)填充内部空间。
(2)文字显示过程
1)给定文字,对于不同的编码,确定编码值
2)根据编码值,从字体文件中找到glyph
3)设置字体大小
4)用某些函数把glyph里的点缩放为字体大小
5)转换为位图点阵
6)显示出来
(3)Freetype
文字的存储由两部分组成,一部分是汉字的索引信息,一部分是汉字的字形(glyph)数据。查看freetype文档上述文字显示过程,对应程序:
1)初始化,FT_Init_Freetype
2)加载字体Face,从文件/内存,FT_New_Face
3)设置字体大小,FT_Set_Char_size、FT_Set_Pixel_Sizes
4)根据编码值,加载glyph
a.选择charmap:FT_Select_charmap
b.找到索引:glyph_index = FT_Get_char_Index
c.取出:FT_Load_Glyph
a\b\c等同FT_Load_Char
转成位图:FT_Render_Glyph
5)变换,移动、旋转……,
在PC上安装
tar xjf freetype-2.4.10.tar.bz2 //解压
./config
make
sudo make install
找到freetype-doc-2.4.10.tar.bz2/freetype-2.4.10/docs/tutorial/example1.c。
修改example1.c显示大小。
#define WIDTH 80
#define HEIGHT 80
将C:/Windows/Fonts下的simsun.ttc(宋体)字体文件拷到虚拟机里,运行
gcc -o test example1.c -I/usr/local/include/freetype2 -lfreetype -lm
./test ./simsun.ttc abc
(1)问题1:中文+英文
上述程序问题:若是中文+英文,出错。
原因:中文和英文字符占用内存不同,字符串要为wchar_t类型。
(2)问题2:显示的中文和英文的对齐。
freetype给出的每个字符的显示示意图。
参考: /freetype-2.4.10/docs/reference/ft2-index.html,获取字符的坐标。
FT_Glyph_Get_CBox( FT_Glyph glyph, //该值通过FT_Get_Glyph()来获取
FT_UInt bbox_mode, //模式,填入FT_GLYPH_BBOX_TRUNCATE即可
FT_BBox *acbox ); //用来存放获取到的xMin, xMax, yMin, yMax信息
(1)安装freetype
#交叉编译: tar xjf freetype-2.4.10.tar.bz2 ./configure --host=arm-linux make make DESTDIR=$PWD/tmp install #编译出来的头文件应该放入: /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include #编译出来的库文件应该放入: /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib #把tmp/usr/local/lib/* 复制到 /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib sudo cp * /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib -d -rf #nfs根文件系统下放入so链接文件 cp *so* /work/nfs_root/fs_mini_mdev_new/lib -d #把tmp/usr/local/include/* 复制到 /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include cp * /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include -rf cd /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include mv freetype2/freetype .
(2)在开发板上运行
在上次代码上修改。
得到的点阵在LCD上要做转换,因为LCD的坐标是:
void draw_bitmap( FT_Bitmap* bitmap, FT_Int x, FT_Int y) { FT_Int i, j, p, q; FT_Int x_max = x + bitmap->width; FT_Int y_max = y + bitmap->rows; //printf("x = %d, y = %d\n", x, y); for ( i = x, p = 0; i < x_max; i++, p++ ) { for ( j = y, q = 0; j < y_max; j++, q++ ) { if ( i < 0 || j < 0 || i >= var.xres || j >= var.yres ) continue; //image[j][i] |= bitmap->buffer[q * bitmap->width + p]; lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]); } } } int main(int argc, char **argv) { unsigned char str[] = "中"; wchar_t *chinese_str = L"繁"; FT_Library library; FT_Face face; int error; FT_Vector pen; FT_GlyphSlot slot; if (argc != 2) { printf("Usage : %s <font_file>\n", argv[0]); return -1; } fd_fb = open("/dev/fb0", O_RDWR); if (fd_fb < 0) { printf("can't open /dev/fb0\n"); return -1; } if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) { printf("can't get var\n"); return -1; } if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) { printf("can't get fix\n"); return -1; } line_width = var.xres * var.bits_per_pixel / 8; pixel_width = var.bits_per_pixel / 8; screen_size = var.xres * var.yres * var.bits_per_pixel / 8; fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0); if (fbmem == (unsigned char *)-1) { printf("can't mmap\n"); return -1; } fd_hzk16 = open("HZK16", O_RDONLY); if (fd_hzk16 < 0) { printf("can't open HZK16\n"); return -1; } if(fstat(fd_hzk16, &hzk_stat)) { printf("can't get fstat\n"); return -1; } hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0); if (hzkmem == (unsigned char *)-1) { printf("can't mmap for hzk16\n"); return -1; } /* 清屏: 全部设为黑色 */ memset(fbmem, 0, screen_size); lcd_put_ascii(var.xres/2, var.yres/2, 'A'); printf("chinese code: %02x %02x\n", str[0], str[1]); lcd_put_chinese(var.xres/2 + 8, var.yres/2, str); /* 显示矢量字体 */ error = FT_Init_FreeType( &library ); /* initialize library */ /* error handling omitted */ error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */ /* error handling omitted */ slot = face->glyph; FT_Set_Pixel_Sizes(face, 24, 0); /* 确定座标: * lcd_x = var.xres/2 + 8 + 16 * lcd_y = var.yres/2 + 16 * 笛卡尔座标系: * x = lcd_x = var.xres/2 + 8 + 16 * y = var.yres - lcd_y = var.yres/2 - 16 */ pen.x = (var.xres/2 + 8 + 16) * 64; pen.y = (var.yres/2 - 16) * 64; /* set transformation */ FT_Set_Transform( face, 0, &pen); /* load glyph image into the slot (erase previous one) */ error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER ); if (error) { printf("FT_Load_Char error\n"); return -1; } draw_bitmap( &slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top); return 0; }
编译运行
arm-linux-gcc -finput-charset=GBK -o example1 example1.c -lfreetype -lm
./example1 ./simsun.ttc
(3) 显示多行文字
需要考虑显示的位置,防止重叠。
1)从左显示:先描画,算出边框
2)居中显示:算出需要显示内容的边框,再描画
通过FT_Glyph_Get_CBox获取位置。
typedef struct FT_BBox_
{
FT_Pos xMin, yMin;
FT_Pos xMax, yMax;
} FT_BBox;
(待续…)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。