title: freetypeLCD显示

date: 2019/03/03 13:34:02

toc: true

freetypeLCD显示

安装交叉编译环境

参考文档 : 代码中的docs/INSTALL.CROSS

#解压
$ mkdir freetype-2.4.10_arm
$ tar xjf freetype-2.4.10.tar.bz2 -C ./freetype-2.4.10_arm
#查看说明 docs/INSTALL.CROSS
cd docs/
vi INSTALL.CROSS

配置

./configure --host=arm-linux  --prefix=$PWD/tmp  //配置交叉编译,安装前缀
make
make install
--host 运行位置
--prefix 安装前缀

头文件和库的位置

查看下交叉编译工具的位置

book@100ask:docs$ echo $PATH
/home/book/bin:/home/book/.local/bin:/opt/slickedit-pro2017/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bin/:/opt/smartgit/bin/:/snap/bin
book@100ask:docs$ # /usr/local/arm/4.3.2/bin/

看下编译工具的头文件是怎么放的,应该是要放到

book@100ask:4.3.2$ pwd
/usr/local/arm/4.3.2 book@100ask:4.3.2$ ls
arm-none-linux-gnueabi bin lib libexec share book@100ask:4.3.2$ find -name include
./arm-none-linux-gnueabi/include
./arm-none-linux-gnueabi/libc/usr/include
./lib/gcc/arm-none-linux-gnueabi/4.3.2/install-tools/include
./lib/gcc/arm-none-linux-gnueabi/4.3.2/include book@100ask:4.3.2$ find -name stdio.h
./arm-none-linux-gnueabi/include/c++/4.3.2/tr1/stdio.h
./arm-none-linux-gnueabi/libc/usr/include/bits/stdio.h
./arm-none-linux-gnueabi/libc/usr/include/stdio.h

所以头文件应该是在这个位置

/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include

查看下库的位置


book@100ask:4.3.2$ find -name lib
./arm-none-linux-gnueabi/lib
./arm-none-linux-gnueabi/libc/usr/lib
./arm-none-linux-gnueabi/libc/armv4t/usr/lib
./arm-none-linux-gnueabi/libc/armv4t/lib
./arm-none-linux-gnueabi/libc/lib
./arm-none-linux-gnueabi/libc/thumb2/usr/lib
./arm-none-linux-gnueabi/libc/thumb2/lib
./lib

库文件是在这个位置

/usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib

编译安装

我们可以在配置的时候指定prefix,也可以在make install时指定安装位置

book@100ask:freetype-2.4.10_arm$ cd freetype-2.4.10/
book@100ask:freetype-2.4.10$ mkdir tmp
book@100ask:freetype-2.4.10$ ./configure --host=arm-linux book@100ask:freetype-2.4.10$make
book@100ask:freetype-2.4.10$make DESTDIR=$PWD/tmp install
book@100ask:tmp$ ls
usr

最终的目录结构在tmp下这样的

bin
include
-freetype2
-....h
-ft2build.h
lib
-libfreetype.a
-libfreetype.la
-libfreetype.so
-libfreetype.so.6
-libfreetype.so.6.9.0
-pkgconfig
share

复制到PC编译工具链

# -d 保持链接属性
sudo cp ./include/* /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include -rfd
sudo cp ./lib/* /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/armv4t/lib -rfd

复制到文件系统

这里只需要复制库,不需要头文件,头文件是在编译阶段被读取的,运行阶段只需要库就可以了

cp ../../../demo_tar/freetype-2.4.10_arm/freetype-2.4.10/tmp/usr/local/lib/*.so /usr/lib/ -rfd

运行测试

./example simsun.ttc 123

LCD显示

编码转换问题

编译的时候提示

cc1: error: failure to convert GBK to UTF-8

查看下具体的帮助

**-finput-charset=***charset*

Set the input character set, used for translation from the character set of the input file to the source character set used by GCC . If the locale does not specify, or GCC cannot get this information from the locale, the default is UTF-8 . This can be overridden by either the locale or this command line option. Currently the command line option takes precedence if there's a conflict. charset can be any encoding supported by the system's "iconv" library routine.

也就是说我们尝试使用命令来转换这个文件,

iconv -f GBK -t UTF-8 show_font.c
#没有-o选项 将转换后的utf-8格式打印到控制台

这就会提示哪里不能转换,我们依次修改

/* 128 0x80 'iconv: 未知 50380 处的非法输入序列

接着修改makefile就可以顺利编译了

 arm-linux-gcc  -finput-charset=GBK -fexec-charset=GBK  -o show  show_font.c  -I /usr/local/arm/4.3.2/arm-none-linux-gnueabi/libc/usr/include/freetype2 -lfreetype -lm

简单显示

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; 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]);
}
}
} void ShowByFreetype(int argc,char **argv,int x ,int y )
{ FT_Library library;
FT_Face face; FT_GlyphSlot slot;
FT_Matrix matrix; /* transformation matrix */
FT_Vector pen; /* untransformed origin */
FT_Error error;
FT_Glyph glyph;
FT_BBox bbox;
int target_height;
int n, num_chars; wchar_t * chinese_str=L"韦中aghp"; if (argc!=2) {
printf("Usage : %s <font_file>\n",argv[0]);
return ;
} error = FT_Init_FreeType( &library ); /* initialize library */
error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
error = FT_Set_Pixel_Sizes(face,24,0); pen.x=x*64;
pen.y=y*64; target_height=var.yres;
slot = face->glyph; for ( n = 0; n < wcslen(chinese_str); n++ )
{
/* set transformation */
FT_Set_Transform( face, 0, &pen ); /* load glyph image into the slot (erase previous one) */
error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
if ( error )
continue; /* ignore errors */
/* now, draw to our target surface (convert position) */ draw_bitmap( &slot->bitmap,
slot->bitmap_left,
target_height - slot->bitmap_top ); /* increment pen position */
pen.x += slot->advance.x;
pen.y += slot->advance.y;
} FT_Done_Face ( face );
FT_Done_FreeType( library ); } int main(int argc, char **argv)
{
....
printf("chinese code: %02x %02x\n", str[0], str[1]);
lcd_put_chinese(var.xres/2 + 8, var.yres/2, str); // 上面 var.xres/2 + 8 var.yres/2 是中文字的原点坐标 位于左上角 /* 确定座标:
* lcd_x = var.xres/2 + 8 + 16 这里加16是因为 我们lcd之前用点阵的原点是左上角,现在笛卡尔坐标是左下角,差了16
* lcd_y = var.yres/2 + 16
* 笛卡尔座标系:
* x = lcd_x = var.xres/2 + 8 + 16
* y = var.yres - lcd_y = var.yres/2 - 16
*/
ShowByFreetype(argc,argv,var.xres/2 + 8 + 16,var.yres/2 - 16); }

角度旋转

这里我们用第三个参数指定角度,使用strtoul来转换角度

if (argc!=3) {
printf("Usage : %s <font_file> angle \n",argv[0]);
return ;
} angle = (1.0*strtoul(argv[2],NULL,0) / 360 ) * 3.14159 * 2; /* use 25 degrees */
/* set up matrix */
matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L ); FT_Set_Transform( face, &matrix, &pen );

测试如下

./show simsun.ttc  45
./show simsun.ttc 180

这里会发现有遮挡,我们换个底色看一下

解决方法可以见下一个文档05-freetype字形解析,刷新新字的时候如果颜色是0的时候要跳过去,不刷新

换行显示

所谓换行,也就是计算y的坐标

x坐标我们可以用上一个字符的advanxe的x计算,y的坐标我们需要计算上一行字符advance.y的最大值来确定

也就是通过FT_Glyph_Get_CBox来统计最小的yMin和最大的yMax,下一行的y就在最小的min-24即可,

// 将槽转换为glyph
FT_Get_Glyph( face->glyph, &glyph );
//从glyph 提取边界信息
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );
if (line_box_ymin > bbox.yMin)
line_box_ymin = bbox.yMin;
if (line_box_ymax < bbox.yMax)
line_box_ymax = bbox.yMax;

老师的代码是这么计算的line_box_ymax - line_box_ymin + 24也就是减去了整个边框的大小

	/* 确定座标:
* lcd_x = 0
* lcd_y = line_box_ymax - line_box_ymin + 24
* 笛卡尔座标系:
* x = lcd_x = 0
* y = var.yres - lcd_y = var.yres - (line_box_ymax - line_box_ymin + 24)
*/
pen.x = 0 * 64;
pen.y = (var.yres - (line_box_ymax - line_box_ymin + 24)) * 64;

但是实际上从图上看出来,只有ymin才是在原点的下方的,所以可以这样

	pen.x = 0 * 64;
pen.y = (line_box_ymin - 24) * 64;

居中显示

参考网址 https://www.freetype.org/freetype2/docs/tutorial/step2.html

中文文档 第11页:https://wenku.baidu.com/view/060a0b44f12d2af90342e63a.html?from=search

所谓居中显示,就是先计算字符长度,然后计算出原点的位置

也就是先得到这一行字的所有外观数据,存起来,再去一次性去渲染显示它,流程简述如下

  1. 通过要显示的str 填充具体的 编码,外观(矢量信息),位置信息(基于(0,0)),统一用glyphs[]管理
  2. 遍历所有的外观,计算最大最小的框架信息

    这里得到的虽然是每个边框的信息,但是统计他们的最大最小也就是整体边框的最大最小点了
  3. 计算居中的位置pen
  4. 绘图
    1. 调整外观数据到具体的显示的位置

      FT_Glyph_Transform(glyphs[n].image, 0, &pen);
    2. 转换成位图

      FT_Glyph_To_Bitmap
    3. 显示位图

      draw_bitmap
  5. 内存销毁等

    FT_Done_Glyph

注意

这里需要调整两次位置信息

  • 第一次是在保存到全局数组的外观时,产生行数据是基于pen在(0,0)的位置FT_Glyph_Transform
  • 第二次是实际转换位图前,将实际的pen的位置与之前的位置计算偏移

完整代码

#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> #include <string.h>
#include <math.h>
#include <wchar.h>
#include <ft2build.h>
#include <stdlib.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H 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; /* 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
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; 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]);
}
}
} typedef struct TGlyph_ {
FT_UInt index; /* glyph index 字符编码*/
FT_Vector pos; /* glyph origin on the baseline 以(0,0)为原点的偏移点*/
FT_Glyph image; /* glyph image 矢量外观/*/
} TGlyph, *PGlyph; TGlyph g_glyphs[100]; int Get_Glyphs_Frm_Wstr(FT_Face face, wchar_t * wstr, TGlyph glyphs[])
{
int n;
TGlyph * glyph = glyphs;
FT_GlyphSlot slot = face->glyph;
int pen_x = 0;
int pen_y = 0;
int error; //get encode
for (n = 0; n < wcslen(wstr); n++)
{
glyph->index = FT_Get_Char_Index( face, wstr[n]);
/* store current pen position */
glyph->pos.x = pen_x;
glyph->pos.y = pen_y; /* load时是把glyph放入插槽face->glyph */
error = FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT); FT_Get_Glyph(face->glyph, &glyph->image ); /* translate the glyph image now */
/* 这使得glyph->image里含有位置信息 */
// by layty 这里加入了pen 的位置信息
FT_Glyph_Transform(glyph->image, 0, &glyph->pos ); pen_x += slot->advance.x; /* 1/64 point */ /* increment number of glyphs */
glyph++;
}
return n;
} void calc_all_bbox(TGlyph glyphs[], int num_glyphs, FT_BBox *abbox )
{
FT_BBox bbox;
int n; bbox.xMin = bbox.yMin = 32000;
bbox.xMax = bbox.yMax = -32000; for ( n = 0; n < num_glyphs; n++ )
{
FT_BBox glyph_bbox; FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox ); if (glyph_bbox.xMin < bbox.xMin)
bbox.xMin = glyph_bbox.xMin; if (glyph_bbox.yMin < bbox.yMin)
bbox.yMin = glyph_bbox.yMin; if (glyph_bbox.xMax > bbox.xMax)
bbox.xMax = glyph_bbox.xMax; if (glyph_bbox.yMax > bbox.yMax)
bbox.yMax = glyph_bbox.yMax;
} *abbox = bbox;
} void Draw_Glyphs(TGlyph glyphs[], int num_glyphs, FT_Vector pen)
{
int n;
int error; for (n = 0; n < num_glyphs; n++)
{
/**/
FT_Glyph_Transform(glyphs[n].image, 0, &pen);
/* convert glyph image to bitmap (destroy the glyph copy!) */
error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, 0, /* no additional translation */
1 ); /* destroy copy in "image" */
if ( !error )
{
FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image;
draw_bitmap(&bit->bitmap, bit->left, var.yres - bit->top);
FT_Done_Glyph(glyphs[n].image );
}
}
} void ShowByFreetype(int argc,char **argv)
{ FT_Library library;
FT_Face face;
FT_Glyph glyph; FT_GlyphSlot slot;
FT_Vector pen; /* untransformed origin */
FT_Error error; int n; FT_BBox bbox; int line_box_width;
int line_box_height; wchar_t * str_dis[]={
L"韦中aghp",
L"你1 www.baidu.com",
L"你2 www.baidu.com",
L"你3 www.baidu.com",
L"你4 www.baidu.com",
}; // str[0][...]
// str[1][...] wchar_t * pt=( wchar_t *)&str_dis[0];
int line; if (argc!=2) {
printf("Usage : %s <font_file> \n",argv[0]);
return ;
} error = FT_Init_FreeType( &library ); /* initialize library */
error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
error = FT_Set_Pixel_Sizes(face,24,0); printf("size of str=%d",sizeof(str_dis)/sizeof(wchar_t *)); for (line=0;line<sizeof(str_dis)/sizeof(wchar_t *);line++) {
n = Get_Glyphs_Frm_Wstr(face, str_dis[line], g_glyphs);
calc_all_bbox(g_glyphs, n, &bbox);
line_box_width = bbox.xMax - bbox.xMin;
line_box_height = bbox.yMax - bbox.yMin;
pen.x = (var.xres - line_box_width)/2 * 64;
pen.y = ((var.yres - line_box_height)/2-line*24) * 64;
Draw_Glyphs(g_glyphs, n, pen);
;
} FT_Done_Face ( face );
FT_Done_FreeType( library ); } 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;
} /* 清屏: 全部设为黑色 */
memset(fbmem, 0, screen_size); /* 0 ---------------------->var.xres
|
|
| lcd
|
|
var.yres
^
|
|
| freetype
|
|
0--------------------->var.xres
*/ /*
we set pen to first line , is to (0,24) unit is 1/64 pixel
*/
ShowByFreetype(argc, argv); return 0;
}

代码仓库

移植到arm上的显示 到串口

LCD 显示

LCD换行显示

LCD居中显示

freetypeLCD显示的更多相关文章

  1. win10 环境 gitbash 显示中文乱码问题处理

    gitbash 是 windows 环境下非常好用的命令行终端,可以模拟一下linux下的命令如ls / mkdir 等等,如果使用过程中遇到中文显示不完整或乱码的情况,多半是因为编码问题导致的,修改 ...

  2. 关于textview显示特殊符号居中的问题

    话说这是2017年的第一篇博客,也是一篇技术博客.先从简单的一篇解决问题开始吧,千里之行,始于足下! ------------------------------------------------- ...

  3. IE的F12开发人员工具不显示问题

    按下F12之后,开发人员工具在桌面上看不到,但是任务栏里有显示.将鼠标放在任务栏的开发人员工具上,出现一片透明的区域,选中之后却出不来.将鼠标移动到开发人员工具的缩略图上,右键-最大化,工具就全屏出现 ...

  4. input[tyle="file"]样式修改及上传文件名显示

    默认的上传样式我们总觉得不太好看,根据需求总想改成和上下结构统一的风格…… 实现方法和思路: 1.在input元素外加a超链接标签 2.给a标签设置按钮样式 3.设置input[type='file' ...

  5. css实现单行,多行文本溢出显示省略号……

    1.单行文本溢出显示省略号我们可以直接用text-overflow: ellipsis 实现方法: <style> .div_text{width: 300px; padding:10px ...

  6. MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示(补充)

    在2.1.栏目的前台显示中因右键没有添加视图把微软给鄙视了一下,后来有仔细研究了一下发现应该鄙视自己,其实这个功能是有的,是自己没搞清楚乱吐糟. 其实只要在NuGet中安装两个包(Microsoft. ...

  7. MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示

    上次创建了栏目模型,这次主要做栏目的前台显示.涉及到数据存储层.业务逻辑层和Web层.用到了迁移,更新数据库和注入的一些内容. 一.添加数据存储层 1.添加Ninesky.DataLibrary(与上 ...

  8. 让kindeditor显示高亮代码

    kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: ...

  9. ASP.NET Core应用针对静态文件请求的处理[5]: DefaultFilesMiddleware中间件如何显示默认页面

    DefaultFilesMiddleware中间件的目的在于将目标目录下的默认文件作为响应内容.我们知道,如果直接请求的就是这个默认文件,那么前面介绍的StaticFileMiddleware中间件会 ...

随机推荐

  1. git错误--ssh: Could not resolve hostname ssh.github.com: Name or service not known--解决方式

    错误如下: git push origin ssh: Could not resolve hostname ssh.github.com: Name or service not known fata ...

  2. DVWA-XSS学习笔记

    DVWA-XSS XSS概念:由于web应用程序对用户的输入过滤不严,通过html注入篡改网页,插入恶意脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击. XSS类型: 反射型XSS:只是简单地把 ...

  3. WIn10系统软件默认安装c盘后消失看不见问题

    一.win10系统下c盘,program 文件下 软件一般为32 或者 64位,但是现在win10系统有些C盘会显示program  x86 向这种情况的话我们的软件默认安装在这个盘的话可能会造成很多 ...

  4. 金蝶K3外购入库单单价取数规则调整

    涉及界面: 问题:财务抱怨外购入库单价格取错,单价多除了一次税率 例如,采购单里面注明了价格是不含税15.3256 结果在外购入库单里面,又自做主张除以税率17%,把采购成本搞成了13.0988, 咨 ...

  5. java 根据ip获取地区信息(淘宝和新浪)

    package com.test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStr ...

  6. 突击战 (uva 11729)贪心

    思路:就是把J大的放在前面.为什么这样贪心呢? 看看这个图 #include<iostream> #include<algorithm> #include<vector& ...

  7. django开发新手教程(原创)

    为了帮助新手简单高效解决django开发的问题,从而写了这么一篇,随便转载! 本人用的是windows10操作系统 #联网安装 ==指定版本号      我在自定义的www文件夹安装C:\Users\ ...

  8. JS 设计模式四 -- 模块模式

    概念 模块模式的思路 就是 就是单例模式添加私有属性和私有方法,减少全局变量的使用. 简单的代码结构: var singleMode = (function(){ // 创建私有变量 var priv ...

  9. vue keepalive 动态设置缓存

    场景:A首页.B列表页.C详情页B---->C 缓存‘列表1’详情的数据A---->C 读取‘列表1’详情的数据B---->C (希望清除‘列表1’的缓存,变成缓存‘列表2’详情的数 ...

  10. 使用python抓取数据之菜鸟爬虫1

    ''' Created on 2018-5-27 @author: yaoshuangqi ''' #本代码获取百度乐彩网站上的信息,只获取最近100期的双色球 import urllib.reque ...