4.数码相框-freetype多行显示,居中显示
本章主要内容如下:
- 1)多行显示
- 2)居中显示
在上章3.数码相框-通过freetype库实现矢量显示里,我们使用矢量坐标时,该坐标仅仅在原点位置处,所以文字有可能会超出坐标,如下图所示:
既然超出了坐标,会不会被下一行的文字覆盖掉?
答:对于几行同样大的文字而言,不会的.
以 24*24的韦字为例,让它显示在(0,40)处,所以文字的y范围在17~40,如下图所示,发现该文字超过了原点,而上方数据又会空出来一段,就不会覆盖到上一行数据.
对于几行规格大小不同的文字,则有可能会被覆盖.以20*20的韦字为例,如下图,可以发现空出的数据比24*24的少1行,若上一行的规格很大时(超出原点很大一部分), 那么这个20*20的韦字,就会覆盖掉上一行文字底部的数据.
1.从左显示多行24*24文字
内容如下:
定义一个两个标志变量line_box_ymax和line_box_ymin.
通过FT_Glyph_Get_CBox()测量字形图像,获取一行文字的yMax,Min最大值,最小值.
显示第一行时:
pen.x = * ;
pen.y = ( fb_var.yres- ) * ; // fb_var.yres:LCD总高度, 原点为(0,24)
显示第2~n行时:
pen.x = * ;
pen.y-= (line_box_ymax - line_box_ymin )* ; //在上行的pen.y基础上,减去上行的边框高
代码如下:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/fb.h>
#include <math.h>
#include<wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H unsigned char *fbmem;
unsigned char *hzkmem; struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo fb_fix; unsigned int screensize;
#define FONTDATAMAX 4096 /*rgb565*/
void pixel_show(int x,int y, unsigned int color)
{
unsigned int red,green,blue;
switch(fb_var.bits_per_pixel) //rgb 像素
{
case :
{
unsigned int *addr=(unsigned int *)fbmem+(fb_var.xres*y+x);
*addr=color;
break;
}
case :
{
unsigned int *addr=(unsigned int *)fbmem+(fb_var.xres*y+x);
*addr=color;
break;
}
case : //将RGB888 转为RGB565
{
unsigned short *addr=(unsigned short *)fbmem+(fb_var.xres*y+x);
red = (color >> ) & 0xff;
green = (color >> ) & 0xff;
blue = (color >> ) & 0xff;
color = ((red >> ) << ) | ((green >> ) << ) | (blue >> );
*addr = color;
break;
}
case :
{
unsigned char *addr=(unsigned char *)fbmem+(fb_var.xres*y+x);
*addr = (unsigned char)color;
break;
}
default:
{
printf("can't surport %dbpp \n",fb_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; //x:当前X位置, bitmap->width:该字宽度
FT_Int y_max = y + bitmap->rows; for ( i = x, p = ; i < x_max; i++, p++ ) //i:lcd的x轴
{
for ( j = y, q = ; j < y_max; j++, q++ ) //j:lcd的y轴
{
if ( i < || j < ||
i >= fb_var.xres || j >= fb_var.yres )
continue;
pixel_show( i, j, bitmap->buffer[q * bitmap->width + p]);
}
}
} unsigned int line_box_ymax=;
unsigned int line_box_ymin=; void lcd_vector_show(char *argv,wchar_t *str[],unsigned int lines)
{
FT_Glyph glyph;
FT_BBox acbox;
FT_Library library;
FT_Face face;
FT_GlyphSlot slot;
FT_Vector pen; /* untransformed origin */
unsigned char error;
unsigned int line_nums=;
unsigned char n,font_size;
error = FT_Init_FreeType( &library ); /* initialize library */
if(error)
{
printf("FT_Init_FreeType ERROR\n");
return ;
} error = FT_New_Face( library, argv, , &face ); /* create face object */
if(error)
{
printf("FT_New_Face ERROR\n");
return ;
}
slot = face->glyph; error = FT_Set_Pixel_Sizes( face, ,); /* set character size */ for(line_nums=;line_nums<lines;line_nums++)
{
/*设置笔记落下位置*/
/*显示坐标(从LCD左上方显示3 行)
*x=0
*y=fb_var.yres-24 (减24,是因为笛卡尔坐标以左下方开始计算坐标值的)
*/
if(line_nums==)
{
pen.x = * ;
pen.y = ( fb_var.yres- ) * ;
}
else
{
pen.x = * ;
pen.y-= (line_box_ymax - line_box_ymin )* ; //在上行的Y值上减去边框高
/*清空标志位,因为上一行的ymin永远当前行小*/
line_box_ymax=;
line_box_ymin=;
}
for ( n = ; n < wcslen(str[line_nums]); n++ )
{
FT_Set_Transform( face, , &pen );
error = FT_Load_Char( face,str[line_nums][n], FT_LOAD_RENDER );
if ( error )
{
printf("FT_Load_Char ERROR\n");
continue;
}
FT_Get_Glyph( face->glyph, &glyph ); //获取字形图像 的信息
FT_Glyph_Get_CBox( glyph,FT_GLYPH_BBOX_TRUNCATE,&acbox ); //获取此行文字的box if(acbox.yMax>acbox.yMin)
{
if(line_box_ymax<acbox.yMax)
line_box_ymax=acbox.yMax;
if(line_box_ymin>acbox.yMin)
line_box_ymin=acbox.yMin;
}
draw_bitmap( &slot->bitmap,
slot->bitmap_left,
fb_var.yres- slot->bitmap_top );
pen.x += slot->advance.x; }
}
FT_Done_Face( face );
FT_Done_FreeType( library );
} int main(int argc,char **argv)
{
int fd_fb,fd_hzk;
struct stat hzk_start; //HZK16文件信息 wchar_t *chinese_str[]={L"韦东山gh",L"abc 中国chinese",L"哈哈哈哈wqe"}; if ( argc != )
{
printf ("usage: %s font_file \n", argv[] );
return ;
} fd_fb=open("/dev/fb0", O_RDWR);
if(fd_fb<)
{
printf("can't open /dev/fb0 \n");
return ;
} if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&fb_var)<)
{
printf("can't get var \n");
return ;
} if(ioctl(fd_fb,FBIOGET_FSCREENINFO,&fb_fix)<)
{
printf("can't get fix \n");
return ;
} screensize=fb_var.xres*fb_var.yres*(fb_var.bits_per_pixel/); //显存大小 fbmem =(unsigned char *)mmap(NULL,screensize, PROT_READ|PROT_WRITE,MAP_SHARED,
fd_fb, ); //映射fb0 if(!fbmem)
{
printf("can't map /dev/fb0 \n");
return ;
} memset(fbmem, , screensize); //清屏黑色 /*显示3 行 矢量文字*/
lcd_vector_show(argv[], chinese_str,); munmap(fbmem,screensize);
return ;
}
2.居中显示
参考第11页:https://wenku.baidu.com/view/060a0b44f12d2af90342e63a.html?from=search
1)首先定义一个用来存储一行文字的字形图像数组
#define MAX_GLYPHS 100 //最多存储一行100个字 TGlyph glyphs[MAX_GLYPHS]; /* glyphs table */
2)首先以坐标(0,0)为基值,获取每个文字的字形图像和坐标值,存到glyphs[]里
/*初始化库,获取face,设置字体*/
error = FT_Init_FreeType( &library ); /* initialize library */
if(error)
{ //... ...}
error = FT_New_Face( library, argv[], , &face ); /* create face object */
if(error)
{//... ...}
FT_Set_Pixel_Sizes(face, , ); ... ...
int num_glyphs = ;
PGlyph glyph = glyphs; // Pglyph在库里被定义为Tglyph *, glyph指向glyphs
int pen_x = ;
int pen_y = ; for (n = ; n < wcslen(wstr); n++) // wstr: wchar_t类型的文字数组
{
glyph->index = FT_Get_Char_Index( face, wstr[n]); //存储每个文字的索引值 glyph->pos.x = pen_x; //记录每个文字的坐标值,后面会用来设置字形图像的位置信息
glyph->pos.y = pen_y; error=FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT);
//通过索引值,找到face(字体文件)里的字形图像,并放到face->glyph字符槽里.
if ( error )
continue; FT_Get_Glyph(face->glyph, &glyph->image );//然后存储每个文字的字形图像
if ( error )
continue; FT_Glyph_Transform(glyph->image, , &glyph->pos );
//使用FT_Glyph_Transform(),使glyph->image包含位置信息 pen_x += face->glyph->advance.x; // 以1/64像素点为单位 glyph++; } num_glyphs= glyph- glyphs; //获取转换成功的文字个数
3)通过glyphs[]存的一行字形图像,计算出边界框
FT_BBox bbox; bbox.xMin = bbox.yMin = ;
bbox.xMax = bbox.yMax = -; /*判断一行文字的边界框范围*/
for ( n = ; n < num_glyphs; n++ )
{
FT_BBox glyph_bbox;
FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox );
// FT_GLYPH_BBOX_TRUNCATE:获取的坐标信息以像素坐标为单位 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;
}
4)通过边界框,找到居中显示的坐标信息
int line_box_width;
int line_box_height; line_box_width = bbox.xMax - bbox.xMin; //一行文字的宽度
line_box_height = bbox.yMax - bbox.yMin; //一行文字的高度 pen.x = (var.xres - line_box_width)/ * ; // var.xres:LCD总宽度
pen.y = (var.yres - line_box_height)/ * ;
5)通过坐标信息,将glyphs[]存的一行字形图像显示出来
for (n = ; n < num_glyphs; n++)
{
//再次使用FT_Glyph_Transform(),更新glyphs[n].image里的坐标值
FT_Glyph_Transform(glyphs[n].image, , &pen); error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, ,);
//转化为位图,1:转换后并摧毁glyphs[n].image的内容
if( !error )
{
FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image;
draw_bitmap(&glyphs[n].image->bitmap, bit->left, var.yres - bit->top); //打印位图
FT_Done_Glyph(glyphs[n].image ); //注销一个Glyph
}
}
4.数码相框-freetype多行显示,居中显示的更多相关文章
- extjs中grid中行内文本或图片居中显示
我是看了网上写的方法调试自己的代码来实现的,实现的方式是当加载store数据时改变grid的行样式,源码如下: html代码: <div id="weatherP_grid-body& ...
- CSS基础之居中显示
这些天忙完了一些项目后,终于有时间来总结一下了.自己就把做项目过程中的体会和理解到的一些东西和大家分享一下.有错请指正!! 在css中,元素居中显示,是基础也是一个小难点.我们经常不知为何总是不能把元 ...
- Wtl之奇技淫巧篇:一、SDI如何居中显示视图
Wtl的sdi应用,视图默认铺满框架的客户区.视图通常用modeless对话框,所有的界面元素都拥挤在左上角,这明显很丑陋.我们尝试让视图居中显示,保持原始大小,这是个很典型的问题,看似简单,诸多细节 ...
- line-height让文本在块级元素中居中显示总结
一.总结: line-height不仅可以用在段落文本中控制行与行之间的间距,还可以用来控制文本在li这种块级元素中的位置. 文本行间距的大小由字体的大小决定,行间距的大小的设置方法有5种方式:
- java中关于窗体居中显示问题
最近在学着用java写qq聊天程序,首先是登录和聊天界面,书上没有给出居中显示,通过上网查找知道有两种方案 先说第一种方法,也是以前用的方法 /获得屏幕大小Dimension screenSize = ...
- css实现一行居中显示,两行靠左显示,超过两行以引号省略
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- NPOI 图片在单元格等比缩放且居中显示
NPOI导出的图片默认是在单元格左上方,这使得图片在单元格显示得很难看.居中,且等比缩放,才是图片在单元格上的完美展示. /// <summary> /// 图片在单元格等比缩放居中显示 ...
- (原创)关于viewpager嵌套listview居中显示的问题
今天折腾了半天自定义控件的问题,如下图所示,我们UI设计了一种可以左右滑动的列表,而列表中又包含了listview.而且要居中显示listview 我一看UI,心想简单,不就是根据datas的数目进行 ...
- 接下来将介绍C#如何设置子窗体在主窗体中居中显示,本文提供详细的操作步骤,需要的朋友可以参考下
接下来将介绍C#如何设置子窗体在主窗体中居中显示,本文提供详细的操作步骤,需要的朋友可以参考下 其实表面上看是很简单的 开始吧,现在有两个窗体Form1主窗体,Form2子窗体 而且我相信大部分人都会 ...
随机推荐
- 【对比分析四】position的absolute与fixed共同点与不同点
共同点: (1) 改变行内元素的呈现方式,display被置为block: (2) 让元素脱离普通流,不占据空间: (3) 默认会覆盖到非定位元素上 不同点: absolute的”根元素“是可以设置的 ...
- iostat 命令详解
前言 话说搞运维的人没有两把"刷子",都不好意思上服务器操作.还好,我还不是搞运维的,我一直都自诩是开发人员,奈何现在的东家运维人员"水"的一比,还要我这个自诩 ...
- 9.7 翻译系列:EF数据注解特性之--InverseProperty【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/inverseproperty-dataannotations-attribute-in ...
- HTML中的文本标签
<span></span> 请使用 <span> 来组合行内元素,以便通过样式来格式化它们. 注释:span 没有固定的格式表现.当对它应用样式时,它才会产生视觉上 ...
- Servlet案例4:用户注册
数据库准备: CREATE DATABASE web; USE web; CREATE TABLE `user` ( `uid` ) NOT NULL, `username` ) DEFAULT NU ...
- location匹配
=/ 表示精确匹配 www.sensetime.com/ ~ :表示做正则表达式匹配,区分字符大小写 ~* : 表示做正则表达式匹配,不区分大小写 ^~: URI的左半部分匹配,不区分大小写 匹配优 ...
- 机器学习基石笔记:05 Training versus Testing
train:A根据给定训练集D在H中选出g,使得Ein(g)约等于0: test:g在整个输入空间X上的表现要约等于在训练集D上的表现,使得Eout(g)约等于Ein(g). 如果|H|小,更易保证t ...
- jvm加载类的7个步骤
- MySQL 中的数字类型
MySQL 中数据类型常用的就三大类: 数字类型/numeric types 日期和时间/date and time types 字符类型/string (character and byte) ty ...
- 11.10 vue
https://vuejs.org/js/vue.js ide typora v-pre 指令 vuex text script . 语法 BCF 终端输入 node -v npm -v 包管理 ...