#include "freetype/fttypes.h" #include #include #include #include #include FT_FREETYPE_H #include #include #include #include #include #include "utf_8.h" static int canvas_width = 0; static int canvas_height = 0; #define COLOR 3 double now_sec(void) { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec + ts.tv_nsec * 1e-9; } typedef struct { int rows; int width; int advance_x; int advance_y; int bitmap_top; int bitmap_left; unsigned char *buffer; }CachedGlyph; static CachedGlyph ascii_cache[256] = {0}; CachedGlyph *get_glyph(FT_Face face, uint32_t codepoint) { if (codepoint < 256) { return &ascii_cache[codepoint]; } else { printf("Ohno."); return 0; } } int load_font(FT_Library library, char *path, FT_Face *face) { int error; error = FT_New_Face(library, path, 0, face); if (error) { printf("Error while loading font"); return 1; } error = FT_Set_Char_Size(*face, 0, 48*64, 300, 300); if (error) { printf("Error during setting char size %d", error); return 1; } for (int i = 0; i < 255; i++) { int error; int glyph_index = 0; glyph_index = FT_Get_Char_Index(*face, i); error = FT_Load_Glyph(*face, glyph_index, FT_LOAD_RENDER); if (error) { printf("Error during LoadGlyph %d", error); continue; } FT_GlyphSlot slot = (*face)->glyph; CachedGlyph val = { .rows = slot->bitmap.rows, .width = slot->bitmap.width, .advance_x = slot->advance.x, .advance_y = slot->advance.y, .bitmap_top = slot->bitmap_top, .bitmap_left = slot->bitmap_left, }; size_t bytes = slot->bitmap.rows * abs(slot->bitmap.pitch) * COLOR; val.buffer = malloc(bytes); for (int r = 0; r < val.rows; r++) { unsigned char *src = slot->bitmap.buffer + r * abs(slot->bitmap.pitch); unsigned char *target = val.buffer + r * abs(slot->bitmap.pitch) * COLOR; for (int c = 0; c < val.width; c++) { unsigned char alpha = src[c]; target[c * COLOR + 0] = alpha; target[c * COLOR + 1] = alpha; target[c * COLOR + 2] = alpha; } } ascii_cache[i] = val; } return 0; } int dumbRenderer(FT_Face face, unsigned int codepoint, unsigned char *canvas, int pen_x, int pen_y) { int x = 0; int y = 0; CachedGlyph *glyph = get_glyph(face, codepoint); int dst_x = pen_x + glyph->bitmap_left; int dst_y = pen_y - glyph->bitmap_top; for (y = 0; y < glyph->rows; y++) { int target_y = dst_y + y; int dst_idx = (target_y * canvas_width + dst_x) * COLOR; unsigned char *row = glyph->buffer + y * abs(glyph->width * COLOR); memcpy(&canvas[dst_idx], row, glyph->width * COLOR); // stupe loop // for (x = 0; x < bitmap.width; x++) // { // int target_x = dst_x + x; // int idx = (target_y * width + target_x) * COLOR; // unsigned char alpha = row[x]; // canvas[idx + 0] |= alpha; // canvas[idx + 1] |= alpha; // canvas[idx + 2] |= alpha; // } } return (glyph->advance_x >> 6); } int main(int argc, char **argv) { double t0 = now_sec(); FT_Library library; FT_Face face; int error = FT_Init_FreeType(&library); if (error) return 1; // shut up gemini this is where my fonts live error = load_font(library, "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf", &face); printf("sucees\n"); if (error) return 1; double t1 = now_sec(); // ARGV[1] to Glyph Index Array uint32_t state = 0; uint32_t codep = 0; int glyph_count = 0; int string_len = strlen(argv[1]); FT_UInt target_string[string_len + 1]; for (int i = 0; i < string_len; i++) { utf8_decode(&state, &codep, (uint8_t)argv[1][i]); if (state == UTF8_REJECT) printf("Invalid utf8 char: %u\n", (uint8_t)argv[1][i]); else if (state == UTF8_ACCEPT) { target_string[glyph_count] = codep; glyph_count += 1; } } target_string[glyph_count] = 0; double t2 = now_sec(); unsigned int *cp = &target_string[0]; char *fname = "out2.ppm"; CachedGlyph *test = get_glyph(face, 65); int padding = 80; canvas_width = ((test->advance_x >> 6) * glyph_count) + padding; printf("width set!"); canvas_height = 360; unsigned char *canvas = calloc(canvas_width * canvas_height * COLOR, sizeof(unsigned char)); int pen_x = 20; int pen_y = canvas_height / 2; printf("Malloc succees"); for (int i = 0; i < 200; i++) { // benchmaxxing unsigned int *cp = &target_string[0]; pen_x = 20; double t2 = now_sec(); for (; *cp; cp++) { pen_x += dumbRenderer(face, *cp, canvas, pen_x, pen_y); } double t3 = now_sec(); printf("Render: %.6f ms\n", (t3 - t2) * 1000.0); } //for (; *cp; cp++) //{ // pen_x += dumbRenderer(face, *cp, canvas, pen_x, pen_y); //} double t3 = now_sec(); int fd = open(fname, O_CREAT | O_RDWR | O_TRUNC); dprintf(fd, "P6\n%d %d\n255\n", canvas_width, canvas_height); write(fd, canvas, canvas_width * canvas_height * COLOR); double t4 = now_sec(); printf("Font Load: %.6f ms\n", (t1 - t0) * 1000.0); printf("UTF-8 parse: %.6f ms\n", (t2 - t1) * 1000.0); printf("Render: %.6f ms\n", (t3 - t2) * 1000.0); printf("Write to file: %.6f ms\n", (t4 - t3) * 1000.0); close(fd); free(canvas); }