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
1.3 program analysis
▲ screen variable parameter structuremain.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
how do the numbers in the array represent the lattice? Take character A as an example, as shown in the following figure:
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:
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
Partial program analysis
main() function
▲ data format in bitmapint 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; }
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 indexBaseline: 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:
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_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 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
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