├── Makefile ├── hello-harfbuzz-opentype.c └── hello-harfbuzz-freetype.c /Makefile: -------------------------------------------------------------------------------- 1 | HB_PKGS = harfbuzz 2 | FT_PKGS = harfbuzz cairo-ft freetype2 3 | 4 | HB_CFLAGS = `pkg-config --cflags $(HB_PKGS)` 5 | HB_LDFLAGS = `pkg-config --libs $(HB_PKGS)` -lm 6 | 7 | FT_CFLAGS = `pkg-config --cflags $(FT_PKGS)` 8 | FT_LDFLAGS = `pkg-config --libs $(FT_PKGS)` -lm 9 | 10 | all: hello-harfbuzz-freetype hello-harfbuzz-opentype 11 | 12 | hello-harfbuzz-opentype: hello-harfbuzz-opentype.c 13 | $(CC) -std=c99 -o $@ $^ $(HB_CFLAGS) $(HB_LDFLAGS) 14 | 15 | hello-harfbuzz-freetype: hello-harfbuzz-freetype.c 16 | $(CC) -std=c99 -o $@ $^ $(FT_CFLAGS) $(FT_LDFLAGS) -------------------------------------------------------------------------------- /hello-harfbuzz-opentype.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define FONT_SIZE 36 8 | #define MARGIN (FONT_SIZE * .5) 9 | 10 | int 11 | main(int argc, char **argv) 12 | { 13 | const char *fontfile; 14 | const char *text; 15 | 16 | if (argc < 3) 17 | { 18 | fprintf (stderr, "usage: hello-harfbuzz font-file.ttf text\n"); 19 | exit (1); 20 | } 21 | 22 | fontfile = argv[1]; 23 | text = argv[2]; 24 | 25 | /* Create a font. */ 26 | hb_blob_t* blob = hb_blob_create_from_file(argv[1]); 27 | hb_face_t* hb_face = hb_face_create(blob, 0); 28 | hb_blob_destroy(blob); /* face will keep a reference to it */ 29 | hb_font_t* hb_font = hb_font_create(hb_face); 30 | 31 | hb_ot_font_set_funcs(hb_font); 32 | hb_font_set_scale(hb_font, FONT_SIZE*64, FONT_SIZE*64); 33 | 34 | /* Create hb-buffer and populate. */ 35 | hb_buffer_t *hb_buffer; 36 | hb_buffer = hb_buffer_create (); 37 | hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1); 38 | hb_buffer_guess_segment_properties (hb_buffer); 39 | 40 | /* Shape it! */ 41 | hb_shape (hb_font, hb_buffer, NULL, 0); 42 | 43 | /* Get glyph information and positions out of the buffer. */ 44 | unsigned int len = hb_buffer_get_length (hb_buffer); 45 | hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL); 46 | hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL); 47 | 48 | /* Print them out as is. */ 49 | printf ("Raw buffer contents:\n"); 50 | for (unsigned int i = 0; i < len; i++) 51 | { 52 | hb_codepoint_t gid = info[i].codepoint; 53 | unsigned int cluster = info[i].cluster; 54 | double x_advance = pos[i].x_advance / 64.; 55 | double y_advance = pos[i].y_advance / 64.; 56 | double x_offset = pos[i].x_offset / 64.; 57 | double y_offset = pos[i].y_offset / 64.; 58 | 59 | char glyphname[32]; 60 | hb_font_get_glyph_name (hb_font, gid, glyphname, sizeof (glyphname)); 61 | 62 | printf ("glyph='%s' cluster=%d advance=(%g,%g) offset=(%g,%g)\n", 63 | glyphname, cluster, x_advance, y_advance, x_offset, y_offset); 64 | } 65 | 66 | printf ("Converted to absolute positions:\n"); 67 | /* And converted to absolute positions. */ 68 | { 69 | double current_x = 0; 70 | double current_y = 0; 71 | for (unsigned int i = 0; i < len; i++) 72 | { 73 | hb_codepoint_t gid = info[i].codepoint; 74 | unsigned int cluster = info[i].cluster; 75 | double x_position = current_x + pos[i].x_offset / 64.; 76 | double y_position = current_y + pos[i].y_offset / 64.; 77 | 78 | 79 | char glyphname[32]; 80 | hb_font_get_glyph_name (hb_font, gid, glyphname, sizeof (glyphname)); 81 | 82 | printf ("glyph='%s' cluster=%d position=(%g,%g)\n", 83 | glyphname, cluster, x_position, y_position); 84 | 85 | current_x += pos[i].x_advance / 64.; 86 | current_y += pos[i].y_advance / 64.; 87 | } 88 | } 89 | 90 | hb_buffer_destroy (hb_buffer); 91 | hb_font_destroy (hb_font); 92 | hb_face_destroy (hb_face); 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /hello-harfbuzz-freetype.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define FONT_SIZE 36 10 | #define MARGIN (FONT_SIZE * .5) 11 | 12 | int 13 | main(int argc, char **argv) 14 | { 15 | const char *fontfile; 16 | const char *text; 17 | 18 | if (argc < 3) 19 | { 20 | fprintf (stderr, "usage: hello-harfbuzz font-file.ttf text\n"); 21 | exit (1); 22 | } 23 | 24 | fontfile = argv[1]; 25 | text = argv[2]; 26 | 27 | /* Initialize FreeType and create FreeType font face. */ 28 | FT_Library ft_library; 29 | FT_Face ft_face; 30 | FT_Error ft_error; 31 | 32 | if ((ft_error = FT_Init_FreeType (&ft_library))) 33 | abort(); 34 | if ((ft_error = FT_New_Face (ft_library, fontfile, 0, &ft_face))) 35 | abort(); 36 | if ((ft_error = FT_Set_Char_Size (ft_face, FONT_SIZE*64, FONT_SIZE*64, 0, 0))) 37 | abort(); 38 | 39 | /* Create hb-ft font. */ 40 | hb_font_t *hb_font; 41 | hb_font = hb_ft_font_create (ft_face, NULL); 42 | 43 | /* Create hb-buffer and populate. */ 44 | hb_buffer_t *hb_buffer; 45 | hb_buffer = hb_buffer_create (); 46 | hb_buffer_add_utf8 (hb_buffer, text, -1, 0, -1); 47 | hb_buffer_guess_segment_properties (hb_buffer); 48 | 49 | /* Shape it! */ 50 | hb_shape (hb_font, hb_buffer, NULL, 0); 51 | 52 | /* Get glyph information and positions out of the buffer. */ 53 | unsigned int len = hb_buffer_get_length (hb_buffer); 54 | hb_glyph_info_t *info = hb_buffer_get_glyph_infos (hb_buffer, NULL); 55 | hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (hb_buffer, NULL); 56 | 57 | /* Print them out as is. */ 58 | printf ("Raw buffer contents:\n"); 59 | for (unsigned int i = 0; i < len; i++) 60 | { 61 | hb_codepoint_t gid = info[i].codepoint; 62 | unsigned int cluster = info[i].cluster; 63 | double x_advance = pos[i].x_advance / 64.; 64 | double y_advance = pos[i].y_advance / 64.; 65 | double x_offset = pos[i].x_offset / 64.; 66 | double y_offset = pos[i].y_offset / 64.; 67 | 68 | char glyphname[32]; 69 | hb_font_get_glyph_name (hb_font, gid, glyphname, sizeof (glyphname)); 70 | 71 | printf ("glyph='%s' cluster=%d advance=(%g,%g) offset=(%g,%g)\n", 72 | glyphname, cluster, x_advance, y_advance, x_offset, y_offset); 73 | } 74 | 75 | printf ("Converted to absolute positions:\n"); 76 | /* And converted to absolute positions. */ 77 | { 78 | double current_x = 0; 79 | double current_y = 0; 80 | for (unsigned int i = 0; i < len; i++) 81 | { 82 | hb_codepoint_t gid = info[i].codepoint; 83 | unsigned int cluster = info[i].cluster; 84 | double x_position = current_x + pos[i].x_offset / 64.; 85 | double y_position = current_y + pos[i].y_offset / 64.; 86 | 87 | 88 | char glyphname[32]; 89 | hb_font_get_glyph_name (hb_font, gid, glyphname, sizeof (glyphname)); 90 | 91 | printf ("glyph='%s' cluster=%d position=(%g,%g)\n", 92 | glyphname, cluster, x_position, y_position); 93 | 94 | current_x += pos[i].x_advance / 64.; 95 | current_y += pos[i].y_advance / 64.; 96 | } 97 | } 98 | 99 | /* Draw, using cairo. */ 100 | double width = 2 * MARGIN; 101 | double height = 2 * MARGIN; 102 | for (unsigned int i = 0; i < len; i++) 103 | { 104 | width += pos[i].x_advance / 64.; 105 | height -= pos[i].y_advance / 64.; 106 | } 107 | if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer))) 108 | height += FONT_SIZE; 109 | else 110 | width += FONT_SIZE; 111 | 112 | /* Set up cairo surface. */ 113 | cairo_surface_t *cairo_surface; 114 | cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 115 | ceil(width), 116 | ceil(height)); 117 | cairo_t *cr; 118 | cr = cairo_create (cairo_surface); 119 | cairo_set_source_rgba (cr, 1., 1., 1., 1.); 120 | cairo_paint (cr); 121 | cairo_set_source_rgba (cr, 0., 0., 0., 1.); 122 | cairo_translate (cr, MARGIN, MARGIN); 123 | 124 | /* Set up cairo font face. */ 125 | cairo_font_face_t *cairo_face; 126 | cairo_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); 127 | cairo_set_font_face (cr, cairo_face); 128 | cairo_set_font_size (cr, FONT_SIZE); 129 | 130 | /* Set up baseline. */ 131 | if (HB_DIRECTION_IS_HORIZONTAL (hb_buffer_get_direction(hb_buffer))) 132 | { 133 | cairo_font_extents_t font_extents; 134 | cairo_font_extents (cr, &font_extents); 135 | double baseline = (FONT_SIZE - font_extents.height) * .5 + font_extents.ascent; 136 | cairo_translate (cr, 0, baseline); 137 | } 138 | else 139 | { 140 | cairo_translate (cr, FONT_SIZE * .5, 0); 141 | } 142 | 143 | cairo_glyph_t *cairo_glyphs = cairo_glyph_allocate (len); 144 | double current_x = 0; 145 | double current_y = 0; 146 | for (unsigned int i = 0; i < len; i++) 147 | { 148 | cairo_glyphs[i].index = info[i].codepoint; 149 | cairo_glyphs[i].x = current_x + pos[i].x_offset / 64.; 150 | cairo_glyphs[i].y = -(current_y + pos[i].y_offset / 64.); 151 | current_x += pos[i].x_advance / 64.; 152 | current_y += pos[i].y_advance / 64.; 153 | } 154 | cairo_show_glyphs (cr, cairo_glyphs, len); 155 | cairo_glyph_free (cairo_glyphs); 156 | 157 | cairo_surface_write_to_png (cairo_surface, "out.png"); 158 | 159 | cairo_font_face_destroy (cairo_face); 160 | cairo_destroy (cr); 161 | cairo_surface_destroy (cairo_surface); 162 | 163 | hb_buffer_destroy (hb_buffer); 164 | hb_font_destroy (hb_font); 165 | 166 | FT_Done_Face (ft_face); 167 | FT_Done_FreeType (ft_library); 168 | 169 | return 0; 170 | } 171 | --------------------------------------------------------------------------------