Created
April 25, 2025 22:23
-
-
Save RJ-Infinity/19a17dd915e60e90419e9aba07de9c3d to your computer and use it in GitHub Desktop.
based of the example in the docs (https://freetype.org/freetype2/docs/tutorial/step1.html)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <string.h> | |
| #include <math.h> | |
| #include <assert.h> | |
| #include <Windows.h> | |
| #include <ft2build.h> | |
| #include FT_FREETYPE_H | |
| #define STB_IMAGE_WRITE_IMPLEMENTATION | |
| #include "stb_image_write.h" | |
| void show_image(unsigned char* image, int width, int height) { | |
| unsigned char* img = calloc(width*height*4, 1); | |
| // memset(img, 0xff, width*height*4); | |
| int i, j; | |
| for ( i = 0; i < height; i++ ) | |
| { | |
| for ( j = 0; j < width; j++ ){ | |
| img[width*i*4 + j*4 + 0] = 0;//image[i * width + j]; | |
| img[width*i*4 + j*4 + 1] = 0;//image[i * width + j]; | |
| img[width*i*4 + j*4 + 2] = 0;//image[i * width + j]; | |
| img[width*i*4 + j*4 + 3] = image[i * width + j]; | |
| } | |
| } | |
| stbi_write_png("test.png", width, height, 4, img, width*4); | |
| free(img); | |
| } | |
| // FT_Error error; | |
| // unsigned char* text; | |
| // double angle; | |
| // int n, num_chars; | |
| typedef struct{ | |
| int width; | |
| int height; | |
| int baseline; | |
| } TextSize; | |
| TextSize render_text(FT_Face face, unsigned char* text, unsigned char* image, TextSize size){ | |
| FT_GlyphSlot slot = face->glyph; | |
| /* set up matrix */ | |
| FT_Matrix matrix; | |
| matrix.xx = 0x10000L; | |
| matrix.xy = 0; | |
| matrix.yx = 0; | |
| matrix.yy = 0x10000L; | |
| FT_Vector pen = {0}; | |
| if (image){ | |
| pen.x = 0; | |
| pen.y = size.baseline; | |
| } | |
| int min_pos = 0; | |
| int max_pos = 0; | |
| for (int n = 0; n < strlen(text); n++) { | |
| /* set transformation */ | |
| FT_Set_Transform( face, &matrix, &pen ); | |
| FT_ULong utf8char; | |
| if (text[n] >> 3 == 0b11110){ | |
| FT_ULong b1 = text[n]; | |
| n++; | |
| FT_ULong b2 = text[n]; | |
| n++; | |
| FT_ULong b3 = text[n]; | |
| n++; | |
| FT_ULong b4 = text[n]; | |
| utf8char = (b1&0b111)<<18 | (b2&0b111111)<<12 | (b3&0b111111)<<6 | (b4&0b111111); | |
| }else if (text[n] >> 4 == 0b1110){ | |
| FT_ULong b1 = text[n]; | |
| n++; | |
| FT_ULong b2 = text[n]; | |
| n++; | |
| FT_ULong b3 = text[n]; | |
| utf8char = (b1&0b1111)<<12 | (b2&0b111111)<<6 | (b3&0b111111); | |
| }else if (text[n] >> 5 == 0b110){ | |
| FT_ULong b1 = text[n]; | |
| n++; | |
| FT_ULong b2 = text[n]; | |
| utf8char = (b1&0b11111)<<6 | (b2&0b111111); | |
| }else{ | |
| utf8char = text[n]; | |
| } | |
| /* load glyph image into the slot (erase previous one) */ | |
| FT_Error error = FT_Load_Char(face, utf8char, image?FT_LOAD_RENDER:FT_LOAD_NO_BITMAP); | |
| if ( error ) | |
| continue; /* ignore errors */ | |
| /* now, draw to our target surface (convert position) */ | |
| if (image){ | |
| FT_Bitmap* bitmap = &slot->bitmap; | |
| FT_Int x = slot->bitmap_left; | |
| FT_Int y = size.height - slot->bitmap_top; | |
| FT_Int i, j, p, q; | |
| FT_Int x_max = x + bitmap->width; | |
| FT_Int y_max = y + bitmap->rows; | |
| /* for simplicity, we assume that `bitmap->pixel_mode' */ | |
| /* is `FT_PIXEL_MODE_GRAY' (i.e., not a bitmap font) */ | |
| assert(bitmap->pixel_mode == FT_PIXEL_MODE_GRAY); | |
| 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 >= size.width || j >= size.height){ continue; } | |
| image[size.width * j + i] = ( | |
| image[size.width * j + i] + bitmap->buffer[q * bitmap->width + p] | |
| ) - ( | |
| image[size.width * j + i] * bitmap->buffer[q * bitmap->width + p] | |
| ); | |
| // image[j][i] |= bitmap->buffer[q * bitmap->width + p]; | |
| // image[WIDTH*j*4 + i*4 + 0] |=bitmap->buffer[q * bitmap->width + p]; | |
| // image[WIDTH*j*4 + i*4 + 1] |=bitmap->buffer[q * bitmap->width + p]; | |
| // image[WIDTH*j*4 + i*4 + 2] |=bitmap->buffer[q * bitmap->width + p]; | |
| // image[WIDTH*j*4 + i*4 + 3] = 0xFF; | |
| } | |
| } | |
| } | |
| if (slot->metrics.horiBearingY > max_pos){max_pos = slot->metrics.horiBearingY;} | |
| if (slot->metrics.horiBearingY-slot->metrics.height < min_pos){min_pos = slot->metrics.horiBearingY-slot->metrics.height;} | |
| /* increment pen position */ | |
| pen.x += slot->advance.x; | |
| pen.y += slot->advance.y; | |
| } | |
| return (TextSize){ | |
| pen.x/64, | |
| (max_pos - min_pos)/64, | |
| -min_pos | |
| }; | |
| } | |
| int main(int _argc, unsigned char** _argv) { | |
| int argc; | |
| LPWSTR* argvW = CommandLineToArgvW(GetCommandLineW(), &argc); | |
| unsigned char** argv = malloc(argc * sizeof(*argv)); | |
| for (size_t i = 0; i < argc; i++) { | |
| int len = WideCharToMultiByte(CP_UTF8, 0, argvW[i], -1, NULL, 0, NULL, NULL); | |
| argv[i] = malloc((len+1) * sizeof(*argv[i])); | |
| argv[i][len] = 0; // assure its null terminated | |
| WideCharToMultiByte(CP_UTF8, 0, argvW[i], -1, argv[i], len, NULL, NULL); | |
| } | |
| // leaking memory above. dosent matter as short run time | |
| if (argc != 3) { | |
| fprintf ( stderr, "usage: %s font sample-text\n", argv[0] ); | |
| exit( 1 ); | |
| } | |
| unsigned char* filename = argv[1]; | |
| unsigned char* text = argv[2]; | |
| FT_Library library; | |
| FT_Error error = FT_Init_FreeType( &library ); /* initialize library */ | |
| /* error handling omitted */ | |
| FT_Face face; | |
| 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 = FT_Set_Pixel_Sizes(face, 51, 51); | |
| /* error handling omitted */ | |
| /* cmap selection omitted; */ | |
| /* for simplicity we assume that the font contains a Unicode cmap */ | |
| TextSize size = render_text(face, text, NULL, (TextSize){}); | |
| unsigned char* image = calloc(size.width*size.height, 1); | |
| render_text(face, text, image, size); | |
| show_image(image, size.width, size.height); | |
| FT_Done_Face(face); | |
| FT_Done_FreeType(library); | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment