freetype简介与测试

article/2025/8/30 14:15:00

目录

一、简要

二、文字显示过程

三、freetype中的step1

四、在PC上测试freetype

4.1 分析main函数

4.2 修改main函数

4.3 在PC上测试

4.4 得到CBox


一、简要

点阵文件中把字母或者汉字的字模取出来在LCD上显示这个方式有个缺点,这个文字的大小就固定了不能够缩放,我们浏览器就可以放大缩小字体,这些字体就成为矢量字体,比如字母A,在矢量字体文件中存放的是若干条闭合曲线的关键点,显示的时候使用数学曲线描绘并连接关键点,然后填充曲线内部空间,这样来实现缩放字体,关键点之间的相互位置是知晓的,而这种数学曲线就称为贝塞尔曲线,贝塞尔曲线在高等数学中有讲到,但不代表我们需要复习贝塞尔曲线,我们可以通过freetype库来处理这些矢量字体,在网上可以搜索到freetype的官网:https://www.freetype.org/,在里面可以下载到源码以及相当文档

在docs/reference目录有解释说明,不过都是英文的,但是有中国牛人的翻译:https://wenku.baidu.com/view/2d24be10cc7931b765ce155b.html

字体文件怎么构造的,构造字体前,需要先描绘出来,例如在1000*1000的细格子以点阵的方式描绘,由做美工的描绘,然后具备数字功底的程序员将关键点取出来及相对位置,例如我们PC上C:\Windows\Fonts存放这各种字库文件,例如文件simsun.ttc字体,存放着很多中文还兼容ASCII,存放着每个字符的关键点和关键点之间的相对位置,这些数据在术语上称为glyph(字形)


二、文字显示过程

字符编码参考:字符编码方式

  • 给定一个文字'A':0x41,"中":可能有GBK、unicode 等编码,可以确定它的编码值
  • 根据编码值从字体文件中找到"glyph" ,(由于字体文件可以是GBK、unicode等,在字库文件前还存有字符映射表charmaps,支持多种编码)
  • 设置字体大小
  • 用某些函数把glyph里的点缩放设置的大小
  • 转换为位图点阵
  • 在LCD等显示器中显示出来

三、freetype中的step1

在docs\tutorial\step1.html介绍了怎么使用相关函数,这里只截图小部分

  • 首先包含头文件里面定义了一些宏例如FT_FREETYPE_H这个宏就在ft2build.h这个头文件中定义了

 

  • 1、初始化:FT_Init_FreeType函数

 

  • 2、初始化库:FT_Init_FreeType函数,加载字体Face,可以认为是一种平面,只可意会,a.可以从文件中加载,b也可以读到内存再从内存中加载,c其他方式加载,我们主要想从文件里面做,FT_New_Face(可以认为打开字体文件),术语上是构造了一个face,face是一个结构体

 

  • 加载face之后会得到所谓的face结构体,从结构体可以确定字体文件的信息,比如num_glyphs(字形数)、units_per_EM(比如1000*1000的方框,这个框就是EM)

  • 3、设置字体大小:有FT_Set_Char_Size和FT_Set_Pixel_Sizes两个函数

  • 4、根据字母或者汉字的ASCLL或者其他编码,去文件中找到glyph,根据编码值加载glyph,在loading之前可以选择charmap,比如给定一个中字可能有 GBK、unicode、BIG5码,charmaps支持多种编码方式,可以根据FT_Select_CharMap选择字符编码方式,如果不选择的话默认是unicode码
  • glyph_index = FT_Get_Char_Index( face, charcode ); 参数是face和字符编码,得到glyph的索引

  • 根据索引取出glyph:FT_Load_Glyph(face, glyph_index, load_flags );  转为位图:FT_Render_Glyph函数

  • 5、变换:移动、旋转,FT_Set_Transform:matrix旋转的角度,delta 偏移位置


四、在PC上测试freetype

看再多的文档也比不上写代码或者看代码来得快,写代码的过程理解会更加深刻,在docs\tutorial里面有3个例子是C++,还有C语言的例子example1.c,各个函数可以参考文档中docs\reference\ft2-base_interface.html

 

4.1 分析main函数

main函数如下

int
main( int     argc,char**  argv )
{FT_Library    library;FT_Face       face;FT_GlyphSlot  slot;FT_Matrix     matrix;                 /* transformation matrix */FT_Vector     pen;                    /* untransformed origin  */FT_Error      error;char*         filename;char*         text;double        angle;int           target_height;int           n, num_chars;if ( argc != 3 ){fprintf ( stderr, "usage: %s font sample-text\n", argv[0] );exit( 1 );}filename      = argv[1];                           /* first argument     */text          = argv[2];                           /* second argument    */num_chars     = strlen( text );angle         = ( 25.0 / 360 ) * 3.14159 * 2;      /* use 25 degrees     */target_height = HEIGHT;error = FT_Init_FreeType( &library );              /* initialize library *//* error handling omitted */error = FT_New_Face( library, filename, 0, &face );/* create face object *//* error handling omitted *//* use 50pt at 100dpi */error = FT_Set_Char_Size( face, 50 * 64, 0,100, 0 );                /* set character size *//* error handling omitted *//* cmap selection omitted;                                        *//* for simplicity we assume that the font contains a Unicode cmap */slot = face->glyph;/* 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 );/* the pen position in 26.6 cartesian space coordinates; *//* start at (300,200) relative to the upper left corner  */pen.x = 300 * 64;pen.y = ( target_height - 200 ) * 64;for ( n = 0; n < num_chars; n++ ){/* set transformation */FT_Set_Transform( face, &matrix, &pen );/* load glyph image into the slot (erase previous one) */error = FT_Load_Char( face, text[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;}show_image();FT_Done_Face    ( face );FT_Done_FreeType( library );return 0;
}
  • 一开始FT_Init_FreeType、FT_New_Face、FT_Set_Char_Size,后面出现以下语句,FT_Load_Glyph函数会把图像存在face->glyph中,而slot称为插槽
slot = face->glyph; 
  •  对于FT_Set_Char_Size函数其中char_width、char_height:单位是1/64point,point相等于物理上的尺寸,等于1/72inch(英寸),如果char_width是100的话就是100 * 1/64 * 1/72 ,horz_resolution:单位是dpi,(dpi:dots像素,per每一个,inch英寸)即每英寸里面有多少个像素,因此字符像素为 100 * 1/64 * 1/72,假设horz_resolution为200,就是100 * 1/64 * 1/72 * 200,即每个字符的像素
  • 对于lcd来说只需要关注像素的大小,因此我们用FT_Set_Pixel_Sizes

  •  旋转角度方面的计算
  /* 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 );
  • pen指示的是笛卡尔坐标,原点是在左下角,在lcd原点一般在左上角,在字体文件或者字体函数中用的都是笛卡尔坐标,这里需要进行转换为lcd的坐标,笛卡尔与lcd的x同向,因此x' = x(lcd),y坐标下,笛卡尔与lcd的y坐标相加等于lcd宽度,其中target_height相当于宽度,单位是1/64point,因此乘上64
  /* the pen position in 26.6 cartesian space coordinates; *//* start at (300,200) relative to the upper left corner  */pen.x = 300 * 64;pen.y = ( target_height - 200 ) * 64;
  •  这个函数旋转角度的时候用
FT_Set_Transform( face, &matrix, &pen );
  •  这里只用了FT_Load_Char,在文档step1有解释,这个函数在这里替代了FT_Get_Char_Index、FT_Load_Glyph、FT_Render_Glyph三个函数,FT_LOAD_RENDER标志位可以立刻得到点阵,就不用FT_Render_Glyph函数来转换为点阵
error = FT_Load_Char( face, text[n], FT_LOAD_RENDER );
  •  最后把点阵由buffer存在了image中,并打印出出来
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 >= WIDTH || j >= HEIGHT )continue;image[j][i] |= bitmap->buffer[q * bitmap->width + p];}}
}void
show_image( void )
{int  i, j;for ( i = 0; i < HEIGHT; i++ ){for ( j = 0; j < WIDTH; j++ )putchar( image[i][j] == 0 ? ' ': image[i][j] < 128 ? '+': '*' );putchar( '\n' );}
}

 

4.2 修改main函数

包含相关注释

...
#define WIDTH   80 //分辨率,在打印的时候体现
#define HEIGHT  80...
int
main( int     argc,char**  argv )
{FT_Library    library;FT_Face       face;FT_GlyphSlot  slot;FT_Matrix     matrix;                 /* transformation matrix */FT_Vector     pen;                    /* untransformed origin  */FT_Error      error;char*         filename;char*         text;double        angle;int           target_height;int           n, num_chars;if ( argc != 3 ){fprintf ( stderr, "usage: %s font sample-text\n", argv[0] );exit( 1 );}filename      = argv[1];                           /* first argument     */text          = argv[2];                           /* second argument    */num_chars     = strlen( text );angle         = ( 0.0 / 360 ) * 3.14159 * 2;      /* use 25 degrees     */  //角度设置为0不旋转target_height = HEIGHT;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 */#if 0/* use 50pt at 100dpi */error = FT_Set_Char_Size( face, 50 * 64, 0,100, 0 );                /* set character size *//* pixels = 50 /72 * 100 = 69  */
#elseFT_Set_Pixel_Sizes(face, 24, 0); //设置为24*24的点阵大小
#endif/* error handling omitted */slot = face->glyph;/* 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 );/* the pen position in 26.6 cartesian space coordinates; *//* start at (0,40) relative to the upper left corner  */ // 这里表示在0,40的地方显示pen.x = 0 * 64;//单位是1/64像素 所以乘上64pen.y = ( target_height - 40 ) * 64;for ( n = 0; n < num_chars; n++ ){/* set transformation */FT_Set_Transform( face, &matrix, &pen );/* load glyph image into the slot (erase previous one) */error = FT_Load_Char( face, text[n], FT_LOAD_RENDER ); //load_char之后就可以得到字符的点阵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;}show_image();FT_Done_Face    ( face );FT_Done_FreeType( library );return 0;
}

draw_bitmap中参数的相关解释

    draw_bitmap( &slot->bitmap,     //得到点阵,笛卡尔左上角的坐标slot->bitmap_left, //转换为点阵lcd的x坐标,两者坐标相等target_height - slot->bitmap_top );//lcd的高度减去笛卡尔高度就是点阵的y坐标

 


4.3 在PC上测试

  • 先安装freetype环境
tar xjf freetype-2.4.10.tar.bz2 
./configure
make
sudo make install
gcc -o example1 example1.c  -I /usr/local/include/freetype2 -lfreetype -lm
  • 显示字母的效果,参数二为字库,参数三只能输入字符,不能是中文,因为FT_Load_Char函数会把中文当成一个字节,需要后面引入宽字符

  • 想显示中文怎么做,继续修改main函数,可以直接指定unicode码,然后FT_Load_Char得到位图,如果是这种写法:char *str = "小马";这样写需要分辨中文两个字节,字母一个字节,因此我们引入宽字符,每一个字/字母都用四个字节来表示,需要包含wchar.h头文件
#include <wchar.h>...double        angle;int           target_height;int           n, num_chars;//int chinese_str[] = {0x97e6, 0x4e1c, 0x5c71, 0x0067}; //这样写表示一个字/字母,需要我们手动去查找unicode码//char *str = "小马"; 这样写需要分辨中文两个字节,字母一个字节wchar_t *chinese_str = L"韦gif";  //每一个字/字母都用四个字节来表示unsigned int *p = (wchar_t *)chinese_str; int i;printf("Uniocde: \n");for (i = 0; i < wcslen(chinese_str); i++){printf("0x%x ", p[i]);}printf("\n");//return 0;if ( argc != 2 ){fprintf ( stderr, "usage: %s font\n", argv[0] );exit( 1 );}
...for ( n = 0; n < wcslen(chinese_str); n++ ) //宽字符长度{/* set transformation */FT_Set_Transform( face, &matrix, &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;}
  • 测试如下,指定输入字符集DBK,输出字符集为unicode,因此打印出来的为unicode码,FT_Load_Char根据unicode码就可以得到位图,然后打印显示

  • 在打印函数中修改代码打印一下行数
void
show_image( void )
{int  i, j;for ( i = 0; i < HEIGHT; i++ ){printf("%02d", i);for ( j = 0; j < WIDTH; j++ )putchar( image[i][j] == 0 ? ' ': image[i][j] < 128 ? '+': '*' );putchar( '\n' );}
}
...  
/* the pen position in 26.6 cartesian space coordinates; *//* start at (0,40) relative to the upper left corner  */pen.x = 0 * 64;pen.y = ( target_height - 40 ) * 64;
  •  执行之后,发现"韦"字不在(0,40)的位置,反而超过了

 

4.4 得到CBox

  • 去描绘一个字符的时候,有可能超过基线,参考文档中step2

  • 因此在main函数最后,每次循环会重新指定pen的位置
    /* increment pen position */pen.x += slot->advance.x;pen.y += slot->advance.y;
  • 在文档中介绍了通过FT_Glyph_Get_CBox函数,可以得到xMax,xMin,yMax,yMin

  • 修改代码,FT_Get_Glyph把插槽slot提取出来,因为每一次循环solt都不一样,FT_Glyph_Get_CBox根据glyph找到bbox,bbox就含有相关的参数
#include FT_GLYPH_H
....
int
main( int     argc,char**  argv )
{
...FT_BBox bbox;FT_Glyph  glyph;
...for ( n = 0; n < wcslen(chinese_str); n++ ){/* set transformation */FT_Set_Transform( face, &matrix, &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 */error = FT_Get_Glyph( face->glyph, &glyph ); //把插槽放在glyph中if (error){printf("FT_Get_Glyph error!\n");return -1;}FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox );//根据glyph找到bbox/* now, draw to our target surface (convert position) */draw_bitmap( &slot->bitmap,slot->bitmap_left,target_height - slot->bitmap_top );printf("Unicode: 0x%x\n", chinese_str[n]);printf("origin.x/64 = %d, origin.y/64 = %d\n", pen.x/64, pen.y/64); //原点的位置,单位为1/64printf("xMin = %d, xMax = %d, yMin = %d, yMax = %d\n", bbox.xMin, bbox.xMax, bbox.yMin, bbox.yMax);//可以描述方框printf("slot->advance.x/64 = %d, slot->advance.y/64 = %d\n", slot->advance.x/64, slot->advance.y/64);/* increment pen position */pen.x += slot->advance.x;pen.y += slot->advance.y;}

编译之后得到相关的参数 

  • 根据打印把字符描绘出来,字/字母可能越过基线,根据CBox可以算出整个文本中的宽度和长度,如下图绿色的方框

 


http://chatgpt.dhexx.cn/article/38eu2wam.shtml

相关文章

Freetype 的安装与使用

4 交叉编译程序 4.1 程序运行的一些基础知识 编译程序时去哪找头文件&#xff1f; 系统目录&#xff1a;就是交叉编译工具链里的某个 include 目录&#xff1b; 也可以自己指定&#xff1a;编译时用 “ -I dir ” 选项指定。 链接时去哪找库文件&#xff1f; 系统目录&#x…

java和web哪个难_web前端和java哪个难学?哪个简单?

说到java很多都人都熟知&#xff0c;但是说到web前端可能是很多人并不知道&#xff0c;随着最近几年的发展&#xff0c;web前端开发人越来越吃香&#xff0c;无论是薪资待遇还是岗位的招聘数量比java差不了多少&#xff0c;最近有同学在咨询web前端和java哪个难学这个问题&…

js和java那个难_javascript与java哪个难?

javascript与java哪个难&#xff1f;答案是&#xff1a;JavaScript比Java更难。那么这是为什么&#xff1f;下面本篇文章就来给大家介绍一下&#xff0c;希望对大家有所帮助。 原因&#xff1a; JavaScript有太多东西需要你自己去理解&#xff0c;这些东西里有很多要么Java已经…

没学历学java很难找工作吗

说实话不是学Java很难找工作&#xff0c;是以后找工作基本都会看学历&#xff0c;学历这个东西说重要也重要&#xff0c;因为它决定了你的简历能不能呈现到面试官面前&#xff0c;如果你的学历不够的话很有可能在第一轮简历就被刷下去了&#xff0c;它根本就不会呈现在面试官面…

java最难的部分_java最难学的是那一块?

原标题&#xff1a;java最难学的是那一块&#xff1f; 对于那些打算通过学习java来找到一份工作的同学来说&#xff0c;可以分为三个学习阶段&#xff0c;初级&#xff0c;中级&#xff0c;高级。不同的学习阶段有不同的难点&#xff0c;下来我就简单的和大家仔细的聊聊&#x…

学习Java开发难不难?好学吗?

学习Java难不难&#xff1f;这是很多希望学习Java的人比较纠结的问题。实际上&#xff0c;Java语言是非常易学的&#xff0c;Java语言机遇&#xff23;语言&#xff0c;却又高于&#xff23;语言。Java语言简单易学的特性使得大多数程序员很容易学习和使用Java。 Java是个简单…

零基础Java难学吗?自学怎么样?

在零基础上学习Java难吗?自学呢?要回答这个问题,我们应该从多方面来回答。首先,谁更适合学习Java?   如果仅仅从兴趣上说那么人人都可以胜任,那就像姜子牙70多年的探险生涯。47岁的刘邦在沛县召集民众响应陈胜武广起义。古代的年龄相当于我们现在的六十岁。齐白石,一位…

java学习路线,一个初中生学java要多久,java难学吗

一门永不过时的编程语言——Java 软件开发 java难学吗 java不难&#xff0c;你可以做如下学习 一、到相应的培训机构付费学习 别在这说培训机构没用什么的&#xff0c;不过一定要找正规的培训机构&#xff0c;不然容易被坑。培训机构里面的课程都是现在工作中需要用到的&am…

学Java难吗

Java这门语言你要是单独拎出来&#xff0c;那还是挺复杂的&#xff0c;但你要是把它放到编程里面&#xff0c;那算不上难&#xff0c;因为编程这门行业本来就难&#xff0c;而且&#xff0c;现在大学计算机专业的学生&#xff0c;大学期间&#xff0c;会设置Java这门课程&#…

c语言难还是java难_C语言真的比Java难学吗?

原标题&#xff1a; C语言真的比Java难学吗&#xff1f; 千锋小编觉得C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。C语言语法比较简单便捷&#xff0c;而且性能快速&#xff0c;只比汇编语言…

学习Java很难吗

没有简单的语言,编程语言各有各的优势,同时也各有各的难点,不过这些难点也可以是他们的特点。就像C++难的是语言的细节,Java难的是各种库,各种函数的调用,它的基本语法很简单,但只靠基础是做不出什么东西的,必须去熟悉各种轮子才能进行开发。 第一、 Java入门很简单…

Java难学吗

学习Java说难其实也不难&#xff01; 毕竟世上无难事&#xff0c;只怕有心人。 Java是编程语言中比较难学的一门语言&#xff0c;它的难度并不低&#xff0c;相对比于C语言来说&#xff0c;Java的学习难度要小一些。 Java的学习中最难得就是&#xff0c;各种各样的框架&#x…

java学起来难不难?

同学们问的最多的一个关于Java的问题就是java学起来到底难不难&#xff1f;java好不好学&#xff1f;小千综合过去毕业学员给大家介绍一下学Java到底难不难。 java语言 单单来说学Java这件事的话&#xff0c;小千认为是不难的&#xff0c;实际上Java经常会用到的代码结构无非就…

关于 高内聚 和 低耦合 的理解

随着一个程序逻辑越来越多&#xff0c;就难免需要微服务来保证程序的高可用性。一个服务宕机或者出问题了&#xff0c;不影响其他的服务。 只要有微服务的存在&#xff0c;两个服务之间有许多代码需要共用。 高内聚低耦合是一种程序设计的思想&#xff0c;高内聚的本质也就抽…

【架构基础】高内聚低耦合

软件设计目标&#xff1a;实现需求、易于重用、易于理解、没有冗余。 Dont reinvent the wheel, just realign it. --Anthony J D’ Angelo 高内聚低耦合&#xff0c;是软件工程中判断软件设计好坏的标准。主要评判模块或类的内聚性是否高&#xff0c;耦合度是否低。目的是使…

神秘的高内聚与低耦合举例

内聚类型&#xff1a; 1.巧合内聚 / 偶然内聚 模块的各成分之间没有关联&#xff0c;只是把分散的功能合并在一起。 例&#xff1a;A模块中有三条语句&#xff08;一条赋值&#xff0c;一条求和&#xff0c;一条传参&#xff09;&#xff0c;表面上看不出任何联系&#xff0c;但…

高内聚,低耦合的实现方式

高内聚低耦合&#xff0c;是软件工程中的概念&#xff0c;是判断软件设计好坏的标准&#xff0c;主要用于程序的面向对象的设计&#xff0c;主要看类的内聚性是否高&#xff0c;耦合度是否低。 目的是使程序模块的可重用性、移植性大大增强。通常程序结构中各模块的内聚程度越…

什么是高内聚,低耦合?

高内聚&#xff0c;低耦合是一个老生常谈的话题&#xff0c;所以拿出来说一下 我们在看Linux的一些资料&#xff0c;或者是在面试&#xff0c;又或者跟一个比较牛的大佬讨论技术的时候&#xff0c;可能会听到这个概念。 所以&#xff0c;什么是高内聚&#xff0c;低耦合呢&…

浅谈高内聚低耦合

前言 高内聚低耦合&#xff0c;是软件工程中的概念&#xff0c;是判断设计好坏的标准&#xff0c;主要是面向对象的设计&#xff0c;看类的内聚性是否高&#xff0c;耦合度是否低。 概念 内聚关注模块内部的元素结合程度&#xff0c;耦合关注模块之间的依赖程度。 内聚性&a…

什么是高内聚低耦合

总是提到高内聚低耦合&#xff0c;往往同学们在学习过程中&#xff0c;对这个概念都不是很清楚&#xff0c;下面我们就这个问题&#xff0c;简单描述&#xff0c;彻底搞懂什么是高内聚低耦合 搞清楚模块是什么 模块就是从系统层次去分成不同的部分&#xff0c;每个部分就是一…