[embedded Linux] Framebuffer application programming and character display of basic knowledge of embedded Linux application development

preface

Weidongshan embedded Linux application development basic knowledge learning notes

Video tutorial address: https://www.bilibili.com/video/BV1kk4y117Tu

1. Framebuffer application programming

  in Linux system, LCD is controlled by Framebuffer driver. Frame means frame and buffer means buffer, which means that Framebuffer is a piece of memory in which a frame of image is stored. The Framebuffer stores the color value of each pixel of a frame of image. Assuming that the resolution of LCD is 1024x768 and the color of each pixel is represented by 32 bits, the size of Framebuffer is: 1024x768x32/8=3145728 bytes.
   briefly introduce the operation principle of LCD:
① Set LCD controller by driver:
   set the timing and signal polarity of LCD controller according to the parameters of LCD;
  allocate Framebuffer according to LCD resolution and BPP.
② APP uses ioctl to obtain LCD resolution and BPP
③ APP maps the Framebuffer through mmap and writes data in the Framebuffer

1.1 calculation of starting address of pixel color value in Framebuffer

▲ LCD and Framebuffer

▲ (x,y) pixel address calculation

(x,y)_offset = (y * x_res + x) * bpp / 8
(x,y) start address = fb_base + (y * x_res + x) * bpp / 8

1.2. How are pixel colors represented in binary?

▲RGB888 RGB565 RGB555

   for 32BPP, generally only the lower 24 bits are set, and the higher 8 bits indicate transparency, which is not supported by general LCD.
   for 24BPP, in order to facilitate processing in hardware, it is also represented by 32 bits in Framebuffer, and the effect is the same as that of 32BPP.
  for 16BPP, RGB565 is commonly used; RGB555 is rarely used, which can determine which format to use by ioctl reading the RGB bit offset in the driver.

   (x,y) pixel address calculation can also be expressed as follows: fb_base + y * line_width + x * pixel_width is represented in the following program
Where line_width = xres * bpp / 8 , pixel_width = bpp / 8

▲ (x,y) pixel address calculation

1.3 program analysis

▲ screen variable parameter structure

main.c

static int fd_fb;//Device node
static struct fb_var_screeninfo var;	/* Current var */   //Store screen variable parameters
static int screen_size;//Screen memory size byte
static unsigned char *fb_base;//Pixel base address 
static unsigned int line_width;//Row width byte
static unsigned int pixel_width;//Pixel width byte

int main(int argc, char **argv)
{
	int i,j;
	
	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))//FrameBufferIOGET_ValueSCREENINFOmation
	{
		printf("can't get var\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;
	fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}

	/* Clear screen: set all to white */
	memset(fb_base, 0xff, screen_size);

	/* Randomly set 100 * 100 as red */
	for (j = 0; j < 100; j++)
	{
		for (i = 0; i < 100; i++)
			lcd_put_pixel(var.xres/2+i, var.yres/2+j, 0xFF0000);//The incoming color format is RGB888
	}
	
	munmap(fb_base , screen_size);//Cancel FB_ Memory address mapping of base
	close(fd_fb);
	
	return 0;	
}

void lcd_put_pixel(int x, int y, unsigned int color)

//RGB888 -> RGB565
void lcd_put_pixel(int x, int y, unsigned int color)
{
	unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;//The address algorithm mentioned above
	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://bpp = 16, i.e. RGB565
		{
			/* 565 */
			//Store the high 5 bits, high 6 bits and high 5 bits of 888 data into 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;
		}
	}
}

2. Text and character display

2.1 character coding method

▲ coding method of characters

▲ UTF-8 variable length code "medium"

2.2. Realize the display of string on LCD

2.1 implementation principle

   to display an ASCII character in LCD, that is, English letters, these characters, the first thing is to find the dot matrix corresponding to the character. There is this file in the Linux kernel source code: lib\fonts\font_8x16.c. The dot matrix of each character is saved in the form of array

▲ dot matrix data of characters

  how do the numbers in the array represent the lattice? Take character A as an example, as shown in the following figure:

▲ how do the numbers in the array represent the lattice

2.2.2 program analysis

/*Omit fontdata_8x16 character array, containing dot matrix data corresponding to ASCII characters*/
...
int fd_fb;
struct fb_var_screeninfo var;	/* Current var */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;
/**********************************************************************
 * Function name: lcd_put_pixel
 * Function Description: output the specified color (tracing point) at the specified position of LCD
 * Input parameters: x coordinate, y coordinate, color
 * Output parameters: None
 * Return value: Yes
 * Modification date version number modified by 	       Modification content
 * -----------------------------------------------
 * 2020/05/12	     V1.0	  zh(angenao)	      establish
 ***********************************************************************/ 
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;
		}
	}
}
/**********************************************************************
 * Function name: lcd_put_ascii
 * Function Description: display an 8 * 16 character at the designated position of LCD
 * Input parameters: x coordinate, y coordinate, ascii code, RGB888 color value
 * Output parameters: None
 * Return value: None
 * Modification date version number modified by 	       Modification content
 * -----------------------------------------------
 * 2022/02/15		V1.1	Joseph	Add RGB888 color value and color logic to the entry parameters
 ***********************************************************************/ 
void lcd_put_ascii(int x, int y, unsigned char c, int color)
{
	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, color); /* white */
			}
			else
			{
				/* hide */
				lcd_put_pixel(x+7-b, y+i, 0); /* black */
			}
		}
	}
}
/**********************************************************************
 * Function name: lcd_show_string
 * Function Description: display string at the specified position of LCD
 * Input parameters: x coordinate, y coordinate, ascii code, RGB888 color value
 * Output parameters: None
 * Return value: None
 * Modification date version number modified by 	       Modification content
 * -----------------------------------------------
 * 2022/02/15	     V1.0	  Joseph	      establish
 ***********************************************************************/ 
void lcd_show_string(int x, int y, unsigned char *string, int color)
{
	int string_len = strlen(string);
	int string_x = x;
	int string_y = y;


	for(int i = 0; i < string_len; i++)
	{
		if(string[i] == '\n')
		{
			string_y += 18;
			string_x = 0;
			if(string_y > var.yres)
			{
				return ;
			}
		}
		else
		{
			lcd_put_ascii(string_x, string_y, string[i], color);
			string_x += 8;
			if(string_x > var.xres)
			{
				string_x = 0;
				string_y += 18;
				if(string_y > var.yres)
				{
					return ;
				}
			}
		}
		
	}

}


int main(int argc, char **argv)
{
	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;
	}

	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;
	}

	/* Clear screen: set all to black */
	memset(fbmem, 0, screen_size);

	lcd_show_string(var.xres/2, var.yres/2, "Hello world!\nHello Linux!\n", 0xff0000);

	munmap(fbmem , screen_size);
	close(fd_fb);
	
	return 0;	
}

2.3 dot matrix display of Chinese characters

2.3.1 display principle

   like the principle of displaying ASCII characters, displaying Chinese characters is to find the dot matrix data from the dot matrix database of Chinese characters through the coded value of characters, and then display it on the screen
   a HZK16 file is used here. This file is the 16 * 16 dot matrix font library of common Chinese characters. Each Chinese character in HZK16 is described by 32 bytes, as shown in the following figure:

▲ data display mode of Chinese character library

   it should be noted here that this font library can only match the characters in GB2312 character set format under ANSI coding format, which means that when we write the source code, we need to use the same format to input Chinese characters in order to find dot matrix data in the font library. We can directly use this format to write the source code, You can also add - fexec charset = GB2312 to convert the source file into GB2312 before compiling. For example, use arm builderoot Linux gnueabihf GCC - fexec charset = GB2312 - o show_ chinese show_ chinese. C to compile the program

2.3.2 program analysis

main() function

int main(int argc, char **argv)
{
	unsigned char str[] = "in";
	
	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;
	}

	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;
	}
	//Will fd_hzk16 maps to memory and returns the starting address to hzkmem
	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;
	}

	/* Clear screen: set all to black */
	memset(fbmem, 0, screen_size);

    lcd_put_ascii(var.xres/2, var.yres/2, 'A', 0xff0000); /*The letter A of 8 * 16 is displayed in the middle of the screen*/
	
	printf("chinese code: %02x %02x\n", str[0], str[1]);
	//Display Chinese characters
	lcd_put_chinese(var.xres/2 + 8,  var.yres/2, str, 0xff0000);

	munmap(fbmem , screen_size);
	close(fd_fb);
	
	return 0;	
}

lcd_put_chinese() function

void lcd_put_chinese(int x, int y, unsigned char *str, unsigned int color)
{
	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, color); /* white */
				}
				else
				{
					/* hide */
					lcd_put_pixel(x+j*8+7-b, y+i, 0); /* black */
				}	
			}
		}
}

2.4 problems encountered in compiling freetype / displaying Chinese characters

See the complete manual of embedded Linux application development V4.0 weidongshan full series video documents - STM32MP157 development board for the principle and detailed tutorial of freetype

solve the problem:

libtool: warning: library '/home/book/100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/.../arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libharfbuzz.la' was moved.

/bin/grep: /home/book/stm32mp157/ST-Buildroot/output/host/bin/.../arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libfreetype.la: No such file or directory

/bin/sed: can't read /home/book/stm32mp157/ST-Buildroot/output/host/bin/.../arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libfreetype.la: No such file or directory

libtool: error: '/home/book/stm32mp157/ST-Buildroot/output/host/bin/.../arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libfreetype.la' is not a valid libtool archive

config.mk:55: recipe for target '/home/book/free/freetype-2.10.2/objs/libfreetype.la' failed

make: *** [/home/book/free/freetype-2.10.2/objs/libfreetype.la] Error 1

The path / home / book / stm32mp157 / St builderoot searched during make execution does not exist

Modify the file of the path:
.../100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libfreetype.la
.../100ask_stm32mp157_pro-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/arm-buildroot-linux-gnueabihf/sysroot/usr/lib/libharfbuzz.la

If there is any error, please handle it at your own discretion

▲ documents to be modified

Partial program analysis

main() function

int main(int argc, char **argv)
{
	wchar_t *chinese_str = L"Multiply";

	FT_Library	  library;
	FT_Face 	  face;
	int error;
    FT_Vector     pen;
	FT_GlyphSlot  slot;
	int font_size = 24;

	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);
		
	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;
	}

	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;
	}

	/* Clear screen: set all to black */
	memset(fbmem, 0, screen_size);

	/* Display vector font */
	//Initialize bitmap
	error = FT_Init_FreeType( &library );			   /* initialize library */
	/* error handling omitted */
	
	//Load the font file and save it in & face
	error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
	/* error handling omitted */	
	//Get ft from face_ Glyphslot, text bitmap is saved in Ft_ In glyphslot
	slot = face->glyph;

	//Set font size
	FT_Set_Pixel_Sizes(face, font_size, 0);


    /* load glyph image into the slot (erase previous one) */
	//Get bitmap according to encoded value
	/*
		FT_Load_Char It can realize the following three functions
		a. Get glyph based on encoded value_ index: FT_Get_Char_Index
		b. According to glyph_idex take out glyph: FT_Load_Glyph
		c. Rendered bitmap: FT_Render_Glyph
	*/
    error = FT_Load_Char( face, chinese_str[0], FT_LOAD_RENDER );
	//Execute ft_ Load_ After char, the character bitmap is stored in slot - > bitmap, that is, face - > glyph - > bitmap
	
	if (error)
	{
		printf("FT_Load_Char error\n");
		return -1;
	}
	
    draw_bitmap( &slot->bitmap,
                 var.xres/2,
                 var.yres/2);

	return 0;	
}

▲ data format in bitmap

draw_bitmap() function

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]);
		}
	}
}

2.7 rotation of Chinese characters

Partial program analysis

int main(int argc, char **argv)
{
	wchar_t *chinese_str = L"Multiply";

	FT_Library	  library;
	FT_Face 	  face;					//The appearance object of vector font is used to save relevant data such as the number of font appearance, the current appearance index, the number of font files contained in the current appearance, etc,
										//The appearance can be simply understood as regular, italic, bold and other font styles
	int error;
    FT_Vector     pen;					//Origin of character			
	FT_GlyphSlot  slot;					//Glyph slot: only one glyph image can be stored at a time. Each face object has a glyph slot located in face - > glyph
	int font_size = 24;
	FT_Matrix	  matrix;				  /* transformation matrix */
	double		  angle;			

	if (argc < 3)
	{
		printf("Usage : %s <font_file> <angle> [font_size]\n", argv[0]);
		return -1;
	}
	//Radian rotation angle
	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;
	}

	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;
	}

	/* Clear screen: set all to black */
	memset(fbmem, 0, screen_size);

	/* Display vector font */
	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);

	/* Determine coordinates:
	 */
	pen.x = 0;
	pen.y = 0;
	
	/* set up matrix */
	//Set 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 */
	//deformation
    FT_Set_Transform( face, &matrix, &pen);

    /* load glyph image into the slot (erase previous one) */
	//Get bitmap
    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;	
}

2.8 line of Chinese characters

Several important concepts involved

▲ relationship between midpoint coordinates of LCD coordinate system and Cartesian coordinate system

▲ glyph index

Baseline: baseline. The text can be implemented on the same line, mainly because its origin is on the baseline
Origin: origin. The origin of characters in the same line is located on the same baseline, which determines its y coordinate. Its x coordinate is obtained from the x+advance of the previous origin. The origin of the first character needs to be specified
Advance: advance, connecting the difference between the x coordinates of two origin points
xMin, xMax, yMin, yMax, width, height: (xMin, yMin) - > (xMax, yMax) indicates that the display character needs the smallest coordinate range, where width = xMax - xMin, height = yMax - yMin
brearingX,bearingY:brearingX = xMin - orgin_x,bearingY = yMax - orgin_y

How to get xMin, xMax, yMin, yMax?
  ft can be used_ Glyph_ Get_ The Cbox function obtains these parameters of a font and will be saved in an ft_ In the bbox structure, you need to use this information when you want to calculate the outer frame of a line of text in the future:

▲FT_BBox_ structural morphology

With the above basic knowledge, how to display a line of text in the specified position now?
  first, how to determine the outline of this line of text: each character has its own Outline: xMin, xMax, yMin, yMax. Take the minimum value of xMin and yMin of these characters and the maximum value of xMax and yMax of these characters to determine the outline of this line of text.
   then you can display a line of text in the specified position (x,y):

   ① first specify the origin pen coordinate of the first character as (0, 0), and calculate its outer frame
   ② calculate the origin of the right character and its outer frame
   after all the characters are processed, the overall outline of a line of text can be obtained by using the method mentioned above: suppose the coordinates of the upper left corner of the outline are (x ', y').
   ③ if you want to display this line of text at (x, y), you can adjust the pen coordinate, because we have only filled in one coordinate in this series of operations, which is the pen coordinate of the origin of the starting text
  so how to adjust it?
   when pen is (0, 0), it corresponds to the upper left corner of the frame (x ', y');
   then when the upper left corner is (x, y), pen can be calculated as (x-x ', y-y').

Several important data structures involved

FT_Library: corresponding to freetype library, using ft_ Init_ The freetype() function initializes a variable of this type
FT_Face: corresponds to a vector font text, such as simsong TTC file, using ft_ New_ The face () function is used to initialize the font file. The function requires the variable corresponding to the freetype library file as a member
FT_GlyphSlot: a glyph slot used to store the results of character processing, such as converted glyphs, bitmaps, etc. What is glyph? Chinese is saved in glyph - > glyph - > bitmap_ Variable of type glyphslot

▲FT_ Schematic diagram of face containing member variables

FT_Glyph: the original key point information of the character is saved in the font file. Using the freetype function, you can zoom in, zoom out and rotate to obtain new key points. These new key points are saved in the slot (Note: the bitmap is also saved in the slot)
  use ft for new key points_ Glyph. You can use this code to get glyph: error = ft from slot_ Get_ Glyph(slot , &glyph);
FT_BBox: the structure is defined as follows. It represents the outer frame of a character, that is, the outer frame of the new glyph:

▲FT_BBox_ structural morphology

  ft can be used_ Glyph_ Get_ CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox ); Get ft from glyph_ Bbox information

  the following example code uses the data structures and functions mentioned above

▲ example code

Partial program analysis

Display string: first set pen as (0,0) to push back the origin (x ', y'), and then calculate pen with (pen_x, pen_y) = (x, y) - (x ', y')
int display_string(FT_Face face, wchar_t *wstr, int lcd_x, int lcd_y)

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

    /* Convert LCD coordinates to Cartesian coordinates */
    int x = lcd_x;
    int y = var.yres - lcd_y;

    /* Calculation frame */
    compute_string_bbox(face, wstr, &bbox);

    /* Backstepping origin */
    //Why * 64? FT_ Set_ The transform function requires the input coordinate unit to be 1 / 64 pixel
    pen.x = (x - bbox.xMin) * 64; /* Unit: 1 / 64 pixel */
    pen.y = (y - bbox.yMax) * 64; /* Unit: 1 / 64 pixel */

    /* Process each character */
    for (i = 0; i < wcslen(wstr); i++)
    {
        /* transformation: transformation */
        //Integrate the information in pen into face
        FT_Set_Transform(face, 0, &pen);

        /* Load bitmap: 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;
        }

        /* Draw on LCD: use LCD coordinates */
        draw_bitmap( &slot->bitmap,
                        slot->bitmap_left,
                        var.yres - slot->bitmap_top);

        /* Calculate the origin of the next character: increment pen position */
        pen.x += slot->advance.x;
        pen.y += slot->advance.y;
    }

    return 0;
}

Calculate the outline of a line of text:
int compute_ string_ Bbox (ft_face, wchar_t * wstr, ft_bbox * abbox) function

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;

    /* initialization */
    bbox.xMin = bbox.yMin = 32000;
    bbox.xMax = bbox.yMax = -32000;

    /* Specify the origin as (0, 0) */
    pen.x = 0;
    pen.y = 0;

    /* Calculate the bounding box for each character */
    /* translate first and then load char to get its outer frame */
    for (i = 0; i < wcslen(wstr); i++)
    {
        /* transformation: transformation */
        FT_Set_Transform(face, 0, &pen);

        /* Load bitmap: 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;
        }

        /* Remove the glyph */
        error = FT_Get_Glyph(face->glyph, &glyph);
        if (error)
        {
            printf("FT_Get_Glyph error!\n");
            return -1;
        }
        
        /* Get the outline from glyph: bbox */
        FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);

        /* Update outline */
        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;
        
        /* Calculate the origin of the next character: increment pen position */
        pen.x += slot->advance.x;
        pen.y += slot->advance.y;
    }

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

Add rotation angle (the displayed words will be slightly incomplete at a specific angle, and the reason is unknown for the time being)

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;
    FT_GlyphSlot slot = face->glyph;
    FT_Matrix	  matrix;				  /* transformation matrix */



    /* Convert LCD coordinates to Cartesian coordinates */
    int x = lcd_x;
    int y = var.yres - lcd_y;

    /* Calculation frame */
    compute_string_bbox(face, wstr, &bbox);

    /* Backstepping origin */
    //Why * 64? FT_ Set_ The transform function requires the input coordinate unit to be 1 / 64 pixel
    pen.x = (x - bbox.xMin) * 64; /* Unit: 1 / 64 pixel */
    pen.y = (y - bbox.yMax) * 64; /* Unit: 1 / 64 pixel */

    /* Process each character */
    for (i = 0; i < wcslen(wstr); i++)
    {
        
        /* set up matrix */
        //Set 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 );

        /* transformation: transformation */
        //Integrate the information in pen into face
        FT_Set_Transform( face, &matrix, &pen);
        /* Load bitmap: 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;
        }

        /* Draw on LCD: use LCD coordinates */
        draw_bitmap( &slot->bitmap,
                        slot->bitmap_left,
                        var.yres - slot->bitmap_top);

        /* Calculate the origin of the next character: increment pen position */
        pen.x += slot->advance.x;
        pen.y += slot->advance.y;
    }

    return 0;
}

reference material

When cross compiling freetype in 6.4.4 under MP157, you will be prompted that libfreetype is not found la
FreeTpye library learning notes: parsing vector fonts into bitmaps

Keywords: Linux

Added by MatthewJ on Fri, 18 Feb 2022 19:26:23 +0200