[Linux] Wishing with LCD text (Framebuffer+Freetype)

Table of contents

foreword

1. LCD operation principle

(1) LCD and Framebuffer.

(2) LCD operation:

(3) Core functions (will be used frequently in the future)

①open function

②ioctl function

③ mmap function

2. Dot matrix display of characters

(1) Character encoding method

①Standard of characters

② Implementation of UNICODE encoding

(2) Dot matrix display of characters

①Dot matrix display of ASCII characters

② Dot matrix display of Chinese characters

(3) Disadvantages of dot matrix display

3. Manual cross compilation of Freetype

(1) Basic knowledge and solutions

①Universal commands for cross-compilers

(2) imx6ull cross compile freetype

① Determine the location of header files and library files in the tool chain

②Cross compile and install libpng

③Cross compile and install freetype

4. Use Freetype to display a single text

(1) Realize the process steps

①The process of displaying a text:

②The specific function realization process:

(2) Specific implementation

①Describe point function (lcd_put_pixel)

② Display bitmap function (draw_bitmap)

③ main function (main)

(3) Realize the effect

 5. Use Freetype to display multi-line text (support tilt angle)

(1) Method principle

①Character size indication

 ②Display a line of text at the specified position

(2) Specific implementation

① specific implementation process

② core function

(3) Realize the effect


foreword

After a certain understanding of the principle of LCD display text, realize the display of multi-line text, in this process, familiarize yourself with the library compilation and common functions under the Linux system.

1. LCD display is realized based on Framebuffer, and the main body uses open, ioctl and mmap to realize.

2. Compared with the character dot matrix display, the use of vector fonts can well realize the display of different sizes of fonts.

3. The size of characters in a line of text is different, and the effect is not good if it is displayed in a uniform size. Based on the Cartesian coordinates and the frame structure of the character size, define the character frame and adjust to the origin of the next character, and use freetype to display a line of text.

1. LCD operation principle

(1) LCD and Framebuffer.

Use the Framebuffer driver to control the LCD  in Linux .

  • Here Framebuffer is a piece of memory, which holds a frame of image.
  • Take the current LCD screen (1024*768) as an example, the color of each pixel is represented by 32, and the size of the Framebuffer: →1024*768*32/8= 3MB
  • Writing to the Framebuffer will also be mapped to the LCD screen accordingly.

(2) LCD operation:

  • The driver sets up the LCD program,
    • Set the timing and signal polarity of the LCD controller according to the parameters of the LCD;
    • Allocate Framebuffer according to LCD resolution and BPP .
  • APP uses ioctl function to get LCD resolution, BPP
  • APP maps Framebuffer through mmap , and writes data in Framebuffer.

(3) Core functions (will be used frequently in the future)

①open function

The open function is used to open the corresponding device node, here is to open the LCD device node.

//头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

//函数原型
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

//核心参数
pathname:文件的路径
flags:表示打开文件的方式
mode:表示创建文件的权限,一般不起效,当flags为O_CREAT时有效
返回值:打开成功返回文件描述符,失败则返回-1

②ioctl function

The ioctl function is generally used to interact with the driver, read and pass some parameters (such as resolution, BPP).

//头文件
#include <sys/ioctl.h>

//函数原型
int ioctl(int fd, unsigned long request, ...);

//核心参数
fd:文件描述符---接open返回值
request:表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据。
返回值:打开成功返回文件描述符,失败返回-1.

③ mmap function

The mmap function is used to map device files to memory and build connections.

//头文件
#include <sys/mman.h>

//函数原型
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

//核心参数
addr:表示指定映射的内存起始地址。设为NULL表示系统自动选定地址,在成功映射后返回该地址。
length:表示将文件中多大的内容映射到内存中。
prot:表示映射区域的保护方式
    PROT_EXEC 映射区域可被执行
    PROT_READ 映射区域可被读出
    PROT_WRITE 映射区域可被写入
    PROT_NONE 映射区域不能存取
flags:表示影响映射区域的不同特性,通常有两种:
    MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。
    MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回原来的文件内容中。
返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1。

2. Dot matrix display of characters

The core of a character --- its encoding value and what shape the character corresponds to is determined by the character file.

Two analysis software: Hex Editor Neno and Notepad . Use Hex Editor Neno to analyze the specific encoding value of input characters in detail, and use Notepad to analyze the difference between different encoding methods.

(1) Character encoding method

①Standard of characters

  • Character standards are ASCII , ANSI (an extension of ASCII) and UNICODE
    • " American Standard Code for Information Interchange", American Standard Code for Information Interchange
    • ANSI is not fixed, usually closely related to "localization", GB2312 is used in mainland China, and BIG5 is used in Hong Kong, Macao and Taiwan.
    • UNICODE is to solve the problem that a value corresponds to different characters in different encoding standards. Any character on the earth has only one unique value.

② Implementation of UNICODE encoding

  • Encoding implementation of UNICODE --- When encountering different encodings, how to correctly implement numerical representation.
    • The first method: use 3 bytes to represent a UNICODE, which is very convenient but a waste of space.
    • The second method: UTF-16 LE ; only two bytes are used, little endian , and the byte with the lowest weight in the value is placed first. UTF-16 BE ; Big endian , the low weight byte in the value is placed at the end. Characters commonly used throughout the world can be represented.
      • But the disadvantages are also obvious: ①The number of characters represented is limited ②There is a waste of space for ASCII characters ③If a certain byte in the file is missing, this will make all subsequent characters unable to be displayed due to misplacement
    • The third method: UTF8 can solve the above problems; the specific schematic diagram is as follows:

(2) Dot matrix display of characters

The display of characters is realized by turning on and off each pixel, and the common one is the dot matrix display of ASCII characters and Chinese characters.

①Dot matrix display of ASCII characters

  • There is this file in the Linux kernel source code: lib\fonts\font_8x16.c , which stores the dot matrix of each character in the form of an array.
  • To display a certain character, find its dot matrix in the fontdata_8x16 array according to its ASCII code, and then take out these 16 bytes to draw 16 rows of pixels.

② Dot matrix display of Chinese characters

  • Use the HZK16 font, which is a 16*16 dot matrix font of commonly used Chinese characters. Each Chinese character in HZK16 uses 32 bytes to describe.
  • In HZK16, the dot matrix is ​​searched by the GB2312 coded value. So pay attention to converting the file encoding format to GB2312. details as follows:

(3) Disadvantages of dot matrix display

  •  When using dot matrix fonts to display English letters and Chinese characters, the size is fixed.
  • If the text is enlarged or reduced, it will be blurred or even jagged.

3. Manual cross compilation of Freetype

For the shortcomings of dot matrix display, here is the vector font solution.

Freetype is an open source font engine library, which provides a unified interface to access multiple font format files, so as to realize vector font display.

(1) Basic knowledge and solutions

①Universal commands for cross-compilers

The specific time to use it is reflected in the specific process below.
//The installed library can be used when the configure command is available, and the library files are installed in the tmp folder of the current directory
./configure --host=arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp
make
make install

(2) imx6ull cross compile freetype

Here the freetype library depends on libpng , and libpng depends on zlib , so we should: first compile and install zlib , then compile and install libpng , and finally compile and install freetype . For imx6ull, there is no need to compile and install zlib, and there is zlib in its tool chain.

① Determine the location of header files and library files in the tool chain

//Set up the cross-compilation toolchain
export ARCH=arm
export CROSS_COMPILE=arm-buildroot-linux-gnueabihf-
export PATH=$PATH:/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueab ihf_sdk-buildroot/bin
//When compiling main{}, list the system directory
echo 'main(){}'| arm-buildroot-linux-gnueabihf-gcc -E -v -
//determine header file directory
/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/include
//Determine the library file directory
/home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/ bin/../lib/gcc/arm-buildroot-linux-gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/lib

Header file path: 

 Compile path, library path:

②Cross compile and install libpng

//copy the file to the current directory
cp /home/book/01_all_series_quickstart/04_Basic knowledge of embedded Linux application development/source/10_freetype/libpng-1.6.37.tar.xz ./

//unzip

tar xJf libpng-1.6.37.tar.xz

//Cross compiler command

cd libpng-1.6.37
./configure --host=arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp
make
make install

// move to tmp

cd tmp

//Copy the include and lib files to the previously specified system header and library file directories

cp include/* -rf /home/book/100ask_imx6ull-sdk/To olChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-lin ux-gnueabihf/7.5.0/include
cp lib/* -rfd /home/book/100ask_imx6ull-sdk/Tool Chain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux -gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/lib

③Cross compile and install freetype

//copy the file to the current directory
cp /home/book/01_all_series_quickstart/04_Basic knowledge of embedded Linux application development/source/10_freetype/freetype-2.10.2.tar.xz ./

//unzip

tar xJf freetype-2.10.2.tar.xz

//Cross compiler command

cd freetype-2.10.2

./configure --host=arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp
make
make install

// move to tmp

cd tmp

//Copy the include and lib files to the previously specified system header and library file directories

cp include/* -rf /home/book/100ask_imx6ull-sdk/To olChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-lin ux-gnueabihf/7.5.0/include
cp lib/* -rfd /home/book/100ask_imx6ull-sdk/Tool Chain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/../lib/gcc/arm-buildroot-linux -gnueabihf/7.5.0/../../../../arm-buildroot-linux-gnueabihf/lib

4. Use Freetype to display a single text

We transplant the Freetype font engine, call the corresponding API interface, and provide font files, so that the freetype library can help us extract key points , realize closed curves , fill colors , and achieve the purpose of displaying vector fonts.

(1) Realize the process steps

①The process of displaying a text :

  • Given a character, its encoding value can be determined (ASCII, UNICODE, GB2312)
  • set font size
  • According to the encoding value, find the corresponding key point (glyph) from the file header through the charmap ( character mapping table ) , and it will adjust the key point according to the font size;
  • Convert keypoints to bitmap lattice
  • displayed on the LCD

②The specific function realization process:

  • Initialization: FT_InitFreetype
  • Load ( open ) font Face : FT_New_Face
  • Set font size: FT_Set_Char_Sizes or FT_Set_Pixel_Sizes
  • Select charmap : FT_Select_Charmap
  • Find the glyph_index based on the encoded value charcode : glyph_index = FT_Get_Char_Index( face , charcode )
  • Take out glyph according to glyph_index : FT_Load_Glyph ( face , glyph_index )
  • Convert to bitmap: FT_Render_Glyph
  • Move or rotate : FT_Set_Transform
  • last shown

(2) Specific implementation

①Describe point function (lcd_put_pixel)

It can output the specified color on the specified position of the LCD. Here our bpp is the corresponding 565.
//输入参数: x坐标,y坐标,颜色
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;
		}
	}

② Display bitmap function (draw_bitmap)

According to the bitmap bitmap, call the lcd_put_pixel drawing function to display Chinese characters at the specified position on the LCD.

//输入参数: x坐标,y坐标,位图指针
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 ( j = y, q = 0; j < y_max; j++, q++ )
	{
		for ( i = x, p = 0; i < x_max; i++, p++ )
		{
			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]);
		}
	}
}

③ main function (main)

The specific implementation process:

  • Step 1: Open the LCD device node and obtain LCD parameters
  • Step 2: Mapping the framebuffer
  • Step 3: Use wchar_t to get the UNICODE value of the character
  • Step 4: Initialize the screen and font library, and build the font file object
  • Step 5: Use freetype to obtain bitmap (tilt angle can be set)
  • Finally: call the draw_bitmap function to display the bitmap
#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 <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

int fd_fb;
struct fb_var_screeninfo var;	/* Current var */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;

int main(int argc, char **argv)
{
    FT_Library	  library;
	FT_Face 	  face;
	int error;
    FT_Vector     pen;
	FT_GlyphSlot  slot;
    int font_size = 24;
	FT_Matrix	  matrix;				  /* transformation matrix */
	double		  angle;

    //第一步:打开LCD的设备节点以及获取LCD参数
	if (argc < 2)
	{
		printf("Usage : %s <font_file> [font_size]\n", argv[0]);
		return -1;
	}

	if (argc == 3)
		font_size = strtoul(argv[2], NULL, 0);
	
	angle  = ( 1.0* strtoul(argv[2], NULL, 0) / 360 ) * 3.14159 * 2;	   /* use 25 degrees	 */

	if (argc == 4)
		font_size = strtoul(argv[3], NULL, 0);
		
	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;
	}

    //第二步:映射framebuffer
    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;
	}

    //第三步:使用 wchar_t 获得字符的 UNICODE 值
	wchar_t *chinese_str = L"希";


    //第四步:屏幕、字体库初始化,构建字体文件对象
	/* 清屏: 全部设为黑色 */
	memset(fbmem, 0, screen_size);
	
	/* 显示矢量字体 */
	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, font_size, 0);


    //第五步:使用freetype得到位图
	/* 确定座标:
	 */
	pen.x = 0;
	pen.y = 0;

	/* 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 );
	
    /* set transformation */
    FT_Set_Transform( face, &matrix, &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,
                 var.xres/2,
                 var.yres/2);

	return 0;	
}

(3) Realize the effect

 ​​After cross-compiling, copy the file to the board and run it to realize the LCD display of the text.

// When cross-compiling .c files, an error will be reported , first perform the following operations

//ft2build.h is located in the freetype2 directory, which does not correspond to the toolchain header file, and needs to be moved to the parent directory

cd /home/book/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/include

mv freetype2/* ./

//Compile and copy the file to the directory mounted on NFS

arm-buildroot-linux-gnueabihf-gcc -o freetype_show_font freetype_show_font.c -lfreetype -lm

cp freetype_show_font simsun.ttc ~/nfs_rootfs

//on-machine test

./freetype_show_font ./simsun.ttc 45 200

 5. Use Freetype to display multi-line text (support tilt angle)

Only use the above function to display a line of text, there will be some problems, such as the size of each character may be different, if the set font size is the same, the display effect will not be good. For this problem, there is a corresponding solution in the freetype library .

After an in-depth understanding of Teacher Wei's sample code, it is further implemented to support the display of multi-line text at an oblique angle. In this process, the code ideas are further organized.

(1) Method principle

①Character size indication

The definition of a character size is shown in the figure below, and xMin, xMax, yMin, and yMax need to be considered specifically. We can get these parameters through the FT_Glyph_Get_CBox function.

 ②Display a line of text at the specified position

If a line of text is displayed at the specified position (x, y), the steps are as shown in the figure:

The specific steps are:

  1. First specify the origin pen coordinates of the first character as (0, 0) , and calculate its outer frame
  2. Then calculate the origin of the character on the right, and also calculate its outer frame
  3. When displaying this line of text at (x, y) , adjust the pen coordinates.

(2) Specific implementation

① specific implementation process

  • Step 1: Open the LCD device node and obtain LCD parameters
  • Step 2: Obtain the setting parameters x_label, y_label, font size and tilt angle
  • Step 3: Map the framebuffer
  • Step 4: Use wchar_t to get the UNICODE value of the string
  • Step 5: Initialize the screen and font library, and build the font file object
  • Step 6: Draw a multi-line string ( calculate the outer frame and adjust the origin )

② core function

Based on the point function ( lcd_put_pixel ) and the display bitmap function ( draw_bitmap ) in freetype displaying a single character .

a. Calculate the outer frame of a line of text (compute_string_bbox)

int compute_string_bbox(FT_Face       face, wchar_t *wstr, FT_BBox  *abbox)
{
    int i;
    int error;
    FT_BBox bbox;
    FT_BBox glyph_bbox;
    FT_Vector pen;
    FT_Glyph  glyph;
    FT_GlyphSlot slot = face->glyph;

    /* 初始化 */
    bbox.xMin = bbox.yMin = 32000;
    bbox.xMax = bbox.yMax = -32000;

    /* 指定原点为(0, 0) */
    pen.x = 0;
    pen.y = 0;

    /* 计算每个字符的bounding box */
    /* 先translate, 再load char, 就可以得到它的外框了 */
    for (i = 0; i < wcslen(wstr); i++)
    {
        /* 转换:transformation */
        FT_Set_Transform(face, 0, &pen);

        /* 加载位图: load glyph image into the slot (erase previous one) */
        error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
        if (error)
        {
            printf("FT_Load_Char error\n");
            return -1;
        }

        /* 取出glyph */
        error = FT_Get_Glyph(face->glyph, &glyph);
        if (error)
        {
            printf("FT_Get_Glyph error!\n");
            return -1;
        }
        
        /* 从glyph得到外框: bbox */
        FT_Glyph_Get_CBox(glyph, 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;
        
        /* 计算下一个字符的原点: increment pen position */
        pen.x += slot->advance.x;
        pen.y += slot->advance.y;
    }

    /* return string bbox */
    *abbox = bbox;
}

b. Adjust the origin and draw  (support tilt angle)

int display_string(FT_Face     face, wchar_t *wstr, int lcd_x, int lcd_y, double angle)
{
    int i;
    int error;
    FT_BBox bbox;
    FT_Vector pen;							/*字符原点*/
    FT_Glyph  glyph;						/*对应字符的处理结果,含glyph和位图*/
	FT_Matrix	  matrix;				  	/* transformation matrix */
    FT_GlyphSlot slot = face->glyph;

    /* 把LCD坐标转换为笛卡尔坐标 */
    int x = lcd_x;
    int y = var.yres - lcd_y;

    /* 计算外框 */
    compute_string_bbox(face, wstr, &bbox);

    /* 反推原点 */
    pen.x = (x - bbox.xMin) * 64; /* 单位: 1/64像素 */
    pen.y = (y - bbox.yMax) * 64; /* 单位: 1/64像素 */

	/*设置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 );

    /* 处理每个字符 */
    for (i = 0; i < wcslen(wstr); i++)
    {
        /* 转换:transformation */
        FT_Set_Transform(face, &matrix, &pen);

        /* 加载位图: load glyph image into the slot (erase previous one) */
        error = FT_Load_Char(face, wstr[i], FT_LOAD_RENDER);
        if (error)
        {
            printf("FT_Load_Char error\n");
            return -1;
        }

        /* 在LCD上绘制: 使用LCD坐标 */
        draw_bitmap( &slot->bitmap,
                        slot->bitmap_left,
                        var.yres - slot->bitmap_top);

        /* 计算下一个字符的原点: increment pen position */
        pen.x += slot->advance.x;
        pen.y += slot->advance.y;
    }

    return 0;
}

c.main()

#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 <math.h>
#include <wchar.h>
#include <sys/ioctl.h>
#include <ft2build.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;


int main(int argc, char **argv)
{
    FT_Library	  library;					/*freetype库*/
	FT_Face 	  face;						/*对应字体文件*/
	FT_BBox bbox;
	int lcd_x, lcd_y, lcd_y2, lcd_y3;						/*初始坐标*/
	int error;
    int font_size = 24;
	FT_Matrix	  matrix;				  	/* transformation matrix */
	double		  angle;

    //第一步:打开LCD的设备节点以及获取LCD参数
    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;
	}
	
	//第二步,设置的参数x_label、y_label、字体大小以及倾斜角度
	if (argc < 5)
	{
        printf("Usage : %s <font_file> <lcd_x> <lcd_y> [font_size]\n", argv[0]);
        return -1;
	}
	lcd_x = strtoul(argv[2], NULL, 0);
	lcd_y = strtoul(argv[3], NULL, 0);
	font_size = strtoul(argv[4], NULL, 0);
	
	if (argc == 6)
		angle  = ( 1.0* strtoul(argv[5], NULL, 0) / 360 ) * 3.14159 * 2;	   /* use 25 degrees	 */

    //第三步:映射framebuffer
    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;
	}

    //第四步:使用 wchar_t 获得字符串的 UNICODE 值
	wchar_t *wline1 = L"希希雾里";
	wchar_t *wline2 = L"对自己越坦然,自己就越轻松!";
	wchar_t *wline3 = L"加油呀,争取换个地方继续搬砖,嘿嘿";

    //第五步:屏幕、字体库初始化,构建字体文件对象

	/* 清屏: 全部设为黑色 */
	memset(fbmem, 0, screen_size);
	
	/* 显示矢量字体 */
	error = FT_Init_FreeType( &library );			   /* initialize library */
	/* error handling omitted */
	
	error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
	
	FT_Set_Pixel_Sizes(face, font_size, 0);

	//第六步,绘制多行字符串(计算外框以及调整原点)
    display_string(face, wline1, lcd_x, lcd_y, angle);
	lcd_y2 = lcd_y + 80;
	display_string(face, wline2, lcd_x, lcd_y2, angle);
	lcd_y3 = lcd_y2 + 80;
	display_string(face, wline3, lcd_x, lcd_y3, angle);


	return 0;	
}

(3) Realize the effect

//Display multi-line text, best wishes 

./freetype_show_font ./simsun.ttc  100 0 40 0

 Reference video:

5_Framebuffer application programming_哔哩哔哩_bilibili

6.1_Character encoding method_哔哩哔哩_bilibili         6.2_Dot matrix display of ASCII characters_哔哩哔哩_bilibili 

6.3_Dot matrix display of Chinese characters_哔哩哔哩_bilibili     6-4. Cross compiler program_Take freetype as an example_哔哩哔哩_bilibili

6.5_Using freetype to display a single text_哔哩哔哩_bilibili  6.6_Using freetype to display a line of text_哔哩哔哩_bilibili

Guess you like

Origin blog.csdn.net/weixin_42373086/article/details/130033912