4 freetyp2.c - font support via the FreeType library version 2.
8 if (!i_ft2_init()) { error }
10 font = i_ft2_new(name, index);
11 if (!i_ft2_setdpi(font, xdpi, ydpi)) { error }
12 if (!i_ft2_getdpi(font, &xdpi, &ydpi)) { error }
14 if (!i_ft2_settransform(font, matrix)) { error }
15 i_img_dim bbox[BOUNDING_BOX_COUNT];
16 if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox, utf8)) { error }
19 if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align,
21 if (!i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, length,
27 Implements Imager font support using the FreeType2 library.
29 The FreeType2 library understands several font file types, including
30 Truetype, Type1 and Windows FNT.
42 #include FT_FREETYPE_H
43 #ifdef FT_MULTIPLE_MASTERS_H
44 #ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
46 #include FT_MULTIPLE_MASTERS_H
50 static void ft2_push_message(int code);
52 static void ft2_final(void *);
54 static im_slot_t slot = -1;
62 static i_img_dim i_min(i_img_dim a, i_img_dim b);
63 static i_img_dim i_max(i_img_dim a, i_img_dim b);
68 slot = im_context_slot_new(ft2_final);
72 =item i_ft2_init(void)
74 Initializes the Freetype 2 library.
76 Returns ft2_state * on success or NULL on failure.
84 im_context_t ctx = im_get_context();
85 ft2_state *ft2 = im_context_slot_get(ctx, slot);
88 ft2 = mymalloc(sizeof(ft2_state));
92 im_context_slot_set(ctx, slot, ft2);
93 mm_log((1, "created FT2 state %p for context %p\n", ft2, ctx));
97 if (!ft2->initialized) {
98 error = FT_Init_FreeType(&ft2->library);
100 ft2_push_message(error);
101 i_push_error(0, "Initializing Freetype2");
104 mm_log((1, "initialized FT2 state %p\n", ft2));
106 ft2->initialized = 1;
113 ft2_final(void *state) {
114 ft2_state *ft2 = state;
116 if (ft2->initialized) {
117 mm_log((1, "finalizing FT2 state %p\n", state));
118 FT_Done_FreeType(ft2->library);
120 ft2->initialized = 0;
123 mm_log((1, "freeing FT2 state %p\n", state));
127 struct FT2_Fonthandle {
132 FT_Encoding encoding;
134 /* used to adjust so we can align the draw point to the top-left */
138 /* Multiple master data if any */
144 /* the following is used to select a "best" encoding */
145 static struct enc_score {
146 FT_Encoding encoding;
150 /* the selections here are fairly arbitrary
151 ideally we need to give the user a list of encodings available
152 and a mechanism to choose one */
153 { ft_encoding_unicode, 10 },
154 { ft_encoding_sjis, 8 },
155 { ft_encoding_gb2312, 8 },
156 { ft_encoding_big5, 8 },
157 { ft_encoding_wansung, 8 },
158 { ft_encoding_johab, 8 },
159 { ft_encoding_latin_2, 6 },
160 { ft_encoding_apple_roman, 6 },
161 { ft_encoding_adobe_standard, 6 },
162 { ft_encoding_adobe_expert, 6 },
166 =item i_ft2_new(char *name, int index)
168 Creates a new font object, from the file given by I<name>. I<index>
169 is the index of the font in a file with multiple fonts, where 0 is the
172 Return NULL on failure.
178 i_ft2_new(const char *name, int index) {
180 FT2_Fonthandle *result;
183 FT_Encoding encoding;
187 mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
189 if ((ft2 = i_ft2_init()) == NULL)
193 error = FT_New_Face(ft2->library, name, index, &face);
195 ft2_push_message(error);
196 i_push_error(error, "Opening face");
197 mm_log((2, "error opening face '%s': %d\n", name, error));
201 encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode;
203 for (i = 0; i < face->num_charmaps; ++i) {
204 FT_Encoding enc_entry = face->charmaps[i]->encoding;
205 mm_log((2, "i_ft2_new, encoding %lX platform %u encoding %u\n",
206 enc_entry, face->charmaps[i]->platform_id,
207 face->charmaps[i]->encoding_id));
208 for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) {
209 if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) {
210 encoding = enc_entry;
211 score = enc_scores[j].score;
216 FT_Select_Charmap(face, encoding);
217 mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
219 result = mymalloc(sizeof(FT2_Fonthandle));
222 result->xdpi = result->ydpi = 72;
223 result->encoding = encoding;
225 /* by default we disable hinting on a call to i_ft2_settransform()
226 if we don't do this, then the hinting can the untransformed text
227 to be a different size to the transformed text.
228 Obviously we have it initially enabled.
232 /* I originally forgot this: :/ */
233 /*i_ft2_settransform(result, matrix); */
234 result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0;
235 result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0;
239 FT_Multi_Master *mm = &result->mm;
242 if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0
243 && (error = FT_Get_Multi_Master(face, mm)) == 0) {
244 mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs));
245 for (i = 0; i < mm->num_axis; ++i) {
246 mm_log((2, " axis %d name %s range %ld - %ld\n", i, mm->axis[i].name,
247 (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum)));
252 mm_log((2, "No multiple masters\n"));
262 =item i_ft2_destroy(FT2_Fonthandle *handle)
264 Destroys a font object, which must have been the return value of
270 i_ft2_destroy(FT2_Fonthandle *handle) {
271 FT_Done_Face(handle->face);
276 =item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
278 Sets the resolution in dots per inch at which point sizes scaled, by
279 default xdpi and ydpi are 72, so that 1 point maps to 1 pixel.
281 Both xdpi and ydpi should be positive.
283 Return true on success.
288 i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
290 if (xdpi > 0 && ydpi > 0) {
296 i_push_error(0, "resolutions must be positive");
302 =item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
304 Retrieves the current horizontal and vertical resolutions at which
305 point sizes are scaled.
310 i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
311 *xdpi = handle->xdpi;
312 *ydpi = handle->ydpi;
318 =item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
320 Sets a transormation matrix for output.
322 This should be a 2 x 3 matrix like:
324 matrix[0] matrix[1] matrix[2]
325 matrix[3] matrix[4] matrix[5]
330 i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) {
335 m.xx = matrix[0] * 65536;
336 m.xy = matrix[1] * 65536;
337 v.x = matrix[2]; /* this could be pels of 26.6 fixed - not sure */
338 m.yx = matrix[3] * 65536;
339 m.yy = matrix[4] * 65536;
340 v.y = matrix[5]; /* see just above */
342 FT_Set_Transform(handle->face, &m, &v);
344 for (i = 0; i < 6; ++i)
345 handle->matrix[i] = matrix[i];
352 =item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
354 If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
356 i_ft2_settransform() disables hinting to prevent distortions in
357 gradual text transformations.
361 int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
362 handle->hint = hinting;
367 =item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, i_img_dim *bbox)
369 Retrieves bounding box information for the font at the given
370 character width and height. This ignores the transformation matrix.
372 Returns non-zero on success.
377 i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth,
378 char const *text, size_t len, i_img_dim *bbox, int utf8) {
383 int ascent = 0, descent = 0;
384 int glyph_ascent, glyph_descent;
385 FT_Glyph_Metrics *gm;
387 int loadFlags = FT_LOAD_DEFAULT;
390 mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n",
391 handle, cheight, cwidth, text, len, bbox));
393 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
394 handle->xdpi, handle->ydpi);
396 ft2_push_message(error);
397 i_push_error(0, "setting size");
401 loadFlags |= FT_LOAD_NO_HINTING;
408 c = i_utf8_advance(&text, &len);
410 i_push_error(0, "invalid UTF8 character");
415 c = (unsigned char)*text++;
419 index = FT_Get_Char_Index(handle->face, c);
420 error = FT_Load_Glyph(handle->face, index, loadFlags);
422 ft2_push_message(error);
423 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
427 gm = &handle->face->glyph->metrics;
428 glyph_ascent = gm->horiBearingY / 64;
429 glyph_descent = glyph_ascent - gm->height/64;
431 start = gm->horiBearingX / 64;
432 /* handles -ve values properly */
433 ascent = glyph_ascent;
434 descent = glyph_descent;
438 if (glyph_ascent > ascent)
439 ascent = glyph_ascent;
440 if (glyph_descent < descent)
441 descent = glyph_descent;
443 width += gm->horiAdvance / 64;
447 handle the case where the right the of the character overlaps the
449 rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64;
455 bbox[BBOX_NEG_WIDTH] = start;
456 bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64;
457 bbox[BBOX_POS_WIDTH] = width;
459 bbox[BBOX_POS_WIDTH] -= rightb;
460 bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64;
461 bbox[BBOX_DESCENT] = descent;
462 bbox[BBOX_ASCENT] = ascent;
463 bbox[BBOX_ADVANCE_WIDTH] = width;
464 bbox[BBOX_RIGHT_BEARING] = rightb;
465 mm_log((1, " bbox=> negw=%d glob_desc=%d pos_wid=%d glob_asc=%d desc=%d asc=%d adv_width=%d rightb=%d\n", bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5], bbox[6], bbox[7]));
467 return BBOX_RIGHT_BEARING + 1;
471 =item transform_box(FT2_FontHandle *handle, int bbox[4])
473 bbox contains coorinates of a the top-left and bottom-right of a bounding
474 box relative to a point.
476 This is then transformed and the values in bbox[4] are the top-left
477 and bottom-right of the new bounding box.
479 This is meant to provide the bounding box of a transformed character
480 box. The problem is that if the character was round and is rotated,
481 the real bounding box isn't going to be much different from the
482 original, but this function will return a _bigger_ bounding box. I
483 suppose I could work my way through the glyph outline, but that's
488 void ft2_transform_box(FT2_Fonthandle *handle, i_img_dim bbox[4]) {
490 double *matrix = handle->matrix;
492 work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
493 work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
494 work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
495 work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
496 work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
497 work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
498 work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
499 work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
501 bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6])));
502 bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7])));
503 bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6])));
504 bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7])));
508 =item expand_bounds(int bbox[4], int bbox2[4])
510 Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
511 bounding box in bbox[] that encloses both.
515 static void expand_bounds(i_img_dim bbox[4], i_img_dim bbox2[4]) {
516 bbox[0] = i_min(bbox[0], bbox2[0]);
517 bbox[1] = i_min(bbox[1], bbox2[1]);
518 bbox[2] = i_max(bbox[2], bbox2[2]);
519 bbox[3] = i_max(bbox[3], bbox2[3]);
523 =item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int vlayout, int utf8, i_img_dim *bbox)
525 Retrieves bounding box information for the font at the given
526 character width and height.
528 This version finds the rectangular bounding box of the glyphs, with
529 the text as transformed by the transformation matrix. As with
530 i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
531 the topline to the top-left of the bounding box. Unlike i_ft2_bbox()
532 this could be near the bottom left corner of the box.
534 (bbox[4], bbox[5]) is the offset to the start of the baseline.
535 (bbox[6], bbox[7]) is the offset from the start of the baseline to the
538 Returns non-zero on success.
543 i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth,
544 char const *text, size_t len, int vlayout, int utf8, i_img_dim *bbox) {
549 i_img_dim ascent = 0, descent = 0;
550 int glyph_ascent, glyph_descent;
551 FT_Glyph_Metrics *gm;
557 int loadFlags = FT_LOAD_DEFAULT;
560 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
562 loadFlags |= FT_LOAD_NO_HINTING;
564 error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64,
565 handle->xdpi, handle->ydpi);
567 ft2_push_message(error);
568 i_push_error(0, "setting size");
576 c = i_utf8_advance(&text, &len);
578 i_push_error(0, "invalid UTF8 character");
583 c = (unsigned char)*text++;
587 index = FT_Get_Char_Index(handle->face, c);
588 error = FT_Load_Glyph(handle->face, index, loadFlags);
590 ft2_push_message(error);
591 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
595 slot = handle->face->glyph;
598 /* these probably don't mean much for vertical layouts */
599 glyph_ascent = gm->horiBearingY / 64;
600 glyph_descent = glyph_ascent - gm->height/64;
602 work[0] = gm->vertBearingX;
603 work[1] = gm->vertBearingY;
606 work[0] = gm->horiBearingX;
607 work[1] = gm->horiBearingY;
609 work[2] = gm->width + work[0];
610 work[3] = work[1] - gm->height;
612 bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
613 bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
614 bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
617 ft2_transform_box(handle, work);
618 for (i = 0; i < 4; ++i)
625 for (i = 0; i < 4; ++i)
627 ascent = glyph_ascent;
628 descent = glyph_descent;
632 expand_bounds(bounds, work);
634 x += slot->advance.x / 64;
635 y += slot->advance.y / 64;
637 if (glyph_ascent > ascent)
638 ascent = glyph_ascent;
639 if (glyph_descent > descent)
640 descent = glyph_descent;
644 handle the case where the right the of the character overlaps the
646 /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
648 width -= rightb / 64;*/
652 /* at this point bounds contains the bounds relative to the CP,
653 and x, y hold the final position relative to the CP */
660 bbox[1] = -bounds[3];
662 bbox[3] = -bounds[1];
670 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
673 =item i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, double cheight, double cwidth, char *text, size_t len, int align, int aa)
675 Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given
676 I<cheight> and I<cwidth>.
678 If align is 0, then the text is rendered with the top-left of the
679 first character at (I<tx>, I<ty>). If align is non-zero then the text
680 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
683 If aa is non-zero then the text is anti-aliased.
685 Returns non-zero on success.
690 i_ft2_text(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, const i_color *cl,
691 double cheight, double cwidth, char const *text, size_t len,
692 int align, int aa, int vlayout, int utf8) {
695 FT_Glyph_Metrics *gm;
696 i_img_dim bbox[BOUNDING_BOX_COUNT];
700 unsigned char map[256];
701 char last_mode = ft_pixel_mode_none;
703 int loadFlags = FT_LOAD_DEFAULT;
706 mm_log((1, "i_ft2_text(handle %p, im %p, tx %d, ty %d, cl %p, cheight %f, cwidth %f, text %p, len %d, align %d, aa %d)\n",
707 handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
710 if (!FT_HAS_VERTICAL(handle->face)) {
711 i_push_error(0, "face has no vertical metrics");
714 loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
717 loadFlags |= FT_LOAD_NO_HINTING;
719 /* set the base-line based on the string ascent */
720 if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
724 render = i_render_new(im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
727 /* this may need adjustment */
728 tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
729 ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
734 c = i_utf8_advance(&text, &len);
736 i_push_error(0, "invalid UTF8 character");
741 c = (unsigned char)*text++;
745 index = FT_Get_Char_Index(handle->face, c);
746 error = FT_Load_Glyph(handle->face, index, loadFlags);
748 ft2_push_message(error);
749 i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)",
752 i_render_delete(render);
755 slot = handle->face->glyph;
759 error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
761 ft2_push_message(error);
762 i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
764 i_render_delete(render);
767 if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
768 bmp = slot->bitmap.buffer;
769 for (y = 0; y < slot->bitmap.rows; ++y) {
772 for (x = 0; x < slot->bitmap.width; ++x) {
774 i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
782 bmp += slot->bitmap.pitch;
786 /* grey scale or something we can treat as greyscale */
787 /* we create a map to convert from the bitmap values to 0-255 */
788 if (last_mode != slot->bitmap.pixel_mode
789 || last_grays != slot->bitmap.num_grays) {
790 if (!make_bmp_map(&slot->bitmap, map))
792 last_mode = slot->bitmap.pixel_mode;
793 last_grays = slot->bitmap.num_grays;
796 bmp = slot->bitmap.buffer;
797 for (y = 0; y < slot->bitmap.rows; ++y) {
798 if (last_mode == ft_pixel_mode_grays &&
800 for (x = 0; x < slot->bitmap.width; ++x)
801 bmp[x] = map[bmp[x]];
803 i_render_color(render, tx + slot->bitmap_left, ty-slot->bitmap_top+y,
804 slot->bitmap.width, bmp, cl);
805 bmp += slot->bitmap.pitch;
810 tx += slot->advance.x / 64;
811 ty -= slot->advance.y / 64;
815 i_render_delete(render);
821 =item i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel, double cheight, double cwidth, char *text, size_t len, int align, int aa)
823 Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given
824 I<cheight> and I<cwidth>.
826 If align is 0, then the text is rendered with the top-left of the
827 first character at (I<tx>, I<ty>). If align is non-zero then the text
828 is rendered with (I<tx>, I<ty>) aligned with the base-line of the
831 If aa is non-zero then the text is anti-aliased.
833 Returns non-zero on success.
839 i_ft2_cp(FT2_Fonthandle *handle, i_img *im, i_img_dim tx, i_img_dim ty, int channel,
840 double cheight, double cwidth, char const *text, size_t len, int align,
841 int aa, int vlayout, int utf8) {
847 mm_log((1, "i_ft2_cp(handle %p, im %p, tx %d, ty %d, channel %d, cheight %f, cwidth %f, text %p, len %d, ...)\n",
848 handle, im, tx, ty, channel, cheight, cwidth, text, len));
850 if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
851 i_push_error(0, "face has no vertical metrics");
855 if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
858 work = i_img_8_new(bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
860 if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth,
861 text, len, 1, aa, vlayout, utf8))
869 /* render to the specified channel */
870 /* this will be sped up ... */
871 for (y = 0; y < work->ysize; ++y) {
872 for (x = 0; x < work->xsize; ++x) {
873 i_gpix(work, x, y, &cl);
874 i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
875 cl2.channel[channel] = cl.channel[0];
876 i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
884 =item i_ft2_has_chars(handle, char *text, size_t len, int utf8, char *out)
886 Check if the given characters are defined by the font.
888 Returns the number of characters that were checked.
893 i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len,
894 int utf8, char *out) {
896 mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
897 handle, text, len, utf8));
903 c = i_utf8_advance(&text, &len);
905 i_push_error(0, "invalid UTF8 character");
910 c = (unsigned char)*text++;
914 index = FT_Get_Char_Index(handle->face, c);
922 /* uses a method described in fterrors.h to build an error translation
925 #undef __FTERRORS_H__
926 #define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
927 #define FT_ERROR_START_LIST
928 #define FT_ERROR_END_LIST
933 =head2 Internal Functions
935 These functions are used in the implementation of freetyp2.c and should not
936 (usually cannot) be called from outside it.
940 =item ft2_push_message(int code)
942 Pushes an error message corresponding to code onto the error stack.
947 #define UNKNOWN_ERROR_FORMAT "Unknown Freetype2 error code 0x%04X"
950 ft2_push_message(int code) {
957 #ifdef IMAGER_SNPRINTF
958 snprintf(unknown, sizeof(unknown), UNKNOWN_ERROR_FORMAT, code);
960 sprintf(unknown, UNKNOWN_ERROR_FORMAT, code);
962 i_push_error(code, unknown);
966 =item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
968 Creates a map to convert grey levels from the glyphs bitmap into
969 values scaled 0..255.
974 make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
978 switch (bitmap->pixel_mode) {
979 case ft_pixel_mode_grays:
980 scale = bitmap->num_grays;
984 i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
988 /* build the table */
989 for (i = 0; i < scale; ++i)
990 map[i] = i * 255 / (bitmap->num_grays - 1);
995 /* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false
996 positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
997 #ifndef FREETYPE_PATCH
998 #define FREETYPE_PATCH 4
1001 /* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
1002 #define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
1003 /* #define IM_HAS_FACE_NAME 0 */
1006 =item i_ft2_face_name(handle, name_buf, name_buf_size)
1008 Fills the given buffer with the Postscript Face name of the font,
1011 Returns the number of bytes copied, including the terminating NUL.
1017 i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
1018 #if IM_HAS_FACE_NAME
1019 char const *name = FT_Get_Postscript_Name(handle->face);
1024 strncpy(name_buf, name, name_buf_size);
1025 name_buf[name_buf_size-1] = '\0';
1027 return strlen(name) + 1;
1030 i_push_error(0, "no face name available");
1037 i_push_error(0, "Freetype 2.0.6 or later required");
1045 i_ft2_can_face_name(void) {
1046 return IM_HAS_FACE_NAME;
1049 /* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
1050 /* well, I assume FREETYPE_MAJOR is 2, since we're here */
1051 #if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
1052 #define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
1056 i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf,
1057 size_t name_buf_size, int reliable_only) {
1058 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1061 i_push_error(0, "FT2 configured without glyph name support");
1069 if (!FT_HAS_GLYPH_NAMES(handle->face)) {
1070 i_push_error(0, "no glyph names in font");
1074 if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
1075 i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
1080 index = FT_Get_Char_Index(handle->face, ch);
1083 FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf,
1086 ft2_push_message(error);
1091 return strlen(name_buf) + 1;
1098 i_push_error(0, "no glyph for that character");
1106 i_ft2_can_do_glyph_names(void) {
1107 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1115 i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
1116 #ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
1119 return FT_Has_PS_Glyph_Names(handle->face);
1124 i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
1127 return handle->has_mm;
1134 i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
1137 FT_Multi_Master *mms = &handle->mm;
1140 if (!handle->has_mm) {
1141 i_push_error(0, "Font has no multiple masters");
1144 mm->num_axis = mms->num_axis;
1145 mm->num_designs = mms->num_designs;
1146 for (i = 0; i < mms->num_axis; ++i) {
1147 mm->axis[i].name = mms->axis[i].name;
1148 mm->axis[i].minimum = mms->axis[i].minimum;
1149 mm->axis[i].maximum = mms->axis[i].maximum;
1155 i_push_error(0, "Multiple master functions unavailable");
1161 i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
1164 FT_Long ftcoords[T1_MAX_MM_AXIS];
1168 if (!handle->has_mm) {
1169 i_push_error(0, "Font has no multiple masters");
1172 if (coord_count != handle->mm.num_axis) {
1173 i_push_error(0, "Number of MM coords doesn't match MM axis count");
1176 for (i = 0; i < coord_count; ++i)
1177 ftcoords[i] = coords[i];
1179 error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
1181 ft2_push_message(error);
1188 i_push_error(0, "Multiple master functions unavailable");
1195 i_min(i_img_dim a, i_img_dim b) {
1196 return a < b ? a : b;
1200 i_max(i_img_dim a, i_img_dim b) {
1201 return a > b ? a : b;
1209 Tony Cook <tony@develop-help.com>, with a fair amount of help from
1210 reading the code in font.c.
1214 font.c, Imager::Font(3), Imager(3)
1216 http://www.freetype.org/