2009-04-17 Pavel Roskin <proski@gnu.org>
[grub2/bean.git] / util / grub-mkfont.c
blobcfd6f9df37278c6c1f67206109bb822fa93dfe3c
1 /*
2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2009 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
19 #include <config.h>
20 #include <grub/types.h>
21 #include <grub/util/misc.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <getopt.h>
28 #include <ft2build.h>
29 #include FT_FREETYPE_H
30 #include <freetype/ftsynth.h>
32 #define GRUB_FONT_DEFAULT_SIZE 16
34 #define GRUB_FONT_RANGE_BLOCK 1024
36 struct grub_glyph_info
38 struct grub_glyph_info *next;
39 grub_uint32_t char_code;
40 int width;
41 int height;
42 int x_ofs;
43 int y_ofs;
44 int device_width;
45 int bitmap_size;
46 grub_uint8_t bitmap[0];
49 #define GRUB_FONT_FLAG_BOLD 1
50 #define GRUB_FONT_FLAG_NOBITMAP 2
51 #define GRUB_FONT_FLAG_NOHINTING 4
52 #define GRUB_FONT_FLAG_FORCEHINT 8
54 struct grub_font_info
56 char* name;
57 int style;
58 int desc;
59 int size;
60 int max_width;
61 int max_height;
62 int min_y;
63 int flags;
64 int num_range;
65 grub_uint32_t *ranges;
66 struct grub_glyph_info *glyph;
69 static struct option options[] =
71 {"output", required_argument, 0, 'o'},
72 {"name", required_argument, 0, 'n'},
73 {"index", required_argument, 0, 'i'},
74 {"range", required_argument, 0, 'r'},
75 {"size", required_argument, 0, 's'},
76 {"desc", required_argument, 0, 'd'},
77 {"bold", no_argument, 0, 'b'},
78 {"no-bitmap", no_argument, 0, 0x100},
79 {"no-hinting", no_argument, 0, 0x101},
80 {"force-autohint", no_argument, 0, 'a'},
81 {"help", no_argument, 0, 'h'},
82 {"version", no_argument, 0, 'V'},
83 {"verbose", no_argument, 0, 'v'},
84 {0, 0, 0, 0}
87 int font_verbosity;
89 static void
90 usage (int status)
92 if (status)
93 fprintf (stderr, "Try ``grub-mkfont --help'' for more information.\n");
94 else
95 printf ("\
96 Usage: grub-mkfont [OPTIONS] FONT_FILES\n\
97 \nOptions:\n\
98 -o, --output=FILE_NAME set output file name\n\
99 -i, --index=N set face index\n\
100 -r, --range=A-B[,C-D] set font range\n\
101 -n, --name=S set font family name\n\
102 -s, --size=N set font size\n\
103 -d, --desc=N set font descent\n\
104 -b, --bold convert to bold font\n\
105 -a, --force-autohint force autohint\n\
106 --no-hinting disable hinting\n\
107 --no-bitmap ignore bitmap strikes when loading\n\
108 -h, --help display this message and exit\n\
109 -V, --version print version information and exit\n\
110 -v, --verbose print verbose messages\n\
112 Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
114 exit (status);
117 void
118 add_pixel (grub_uint8_t **data, int *mask, int not_blank)
120 if (*mask == 0)
122 (*data)++;
123 **data = 0;
124 *mask = 128;
127 if (not_blank)
128 **data |= *mask;
130 *mask >>= 1;
133 void
134 add_char (struct grub_font_info *font_info, FT_Face face,
135 grub_uint32_t char_code)
137 struct grub_glyph_info *glyph_info, **p_glyph;
138 int width, height;
139 grub_uint8_t *data;
140 int mask, i, j, bitmap_size;
141 FT_GlyphSlot glyph;
142 int flag = FT_LOAD_RENDER | FT_LOAD_MONOCHROME;
144 if (font_info->flags & GRUB_FONT_FLAG_NOBITMAP)
145 flag |= FT_LOAD_NO_BITMAP;
147 if (font_info->flags & GRUB_FONT_FLAG_NOHINTING)
148 flag |= FT_LOAD_NO_HINTING;
149 else if (font_info->flags & GRUB_FONT_FLAG_FORCEHINT)
150 flag |= FT_LOAD_FORCE_AUTOHINT;
152 if (FT_Load_Char (face, char_code, flag))
153 return;
155 glyph = face->glyph;
157 if (font_info->flags & GRUB_FONT_FLAG_BOLD)
158 FT_GlyphSlot_Embolden (glyph);
160 p_glyph = &font_info->glyph;
161 while ((*p_glyph) && ((*p_glyph)->char_code > char_code))
163 p_glyph = &(*p_glyph)->next;
166 /* Ignore duplicated glyph. */
167 if ((*p_glyph) && ((*p_glyph)->char_code == char_code))
168 return;
170 width = glyph->bitmap.width;
171 height = glyph->bitmap.rows;
173 bitmap_size = ((width * height + 7) / 8);
174 glyph_info = xmalloc (sizeof (struct grub_glyph_info) + bitmap_size);
175 glyph_info->bitmap_size = bitmap_size;
177 glyph_info->next = *p_glyph;
178 *p_glyph = glyph_info;
180 glyph_info->char_code = char_code;
181 glyph_info->width = width;
182 glyph_info->height = height;
183 glyph_info->x_ofs = glyph->bitmap_left;
184 glyph_info->y_ofs = glyph->bitmap_top - height;
185 glyph_info->device_width = glyph->metrics.horiAdvance / 64;
187 if (width > font_info->max_width)
188 font_info->max_width = width;
190 if (height > font_info->max_height)
191 font_info->max_height = height;
193 if (glyph_info->y_ofs < font_info->min_y)
194 font_info->min_y = glyph_info->y_ofs;
196 mask = 0;
197 data = &glyph_info->bitmap[0] - 1;
198 for (j = 0; j < height; j++)
199 for (i = 0; i < width; i++)
200 add_pixel (&data, &mask,
201 glyph->bitmap.buffer[i / 8 + j * glyph->bitmap.pitch] &
202 (1 << (7 - (i & 7))));
205 void
206 add_font (struct grub_font_info *font_info, FT_Face face)
208 if (font_info->num_range)
210 int i;
211 grub_uint32_t j;
213 for (i = 0; i < font_info->num_range; i++)
214 for (j = font_info->ranges[i * 2]; j <= font_info->ranges[i * 2 + 1];
215 j++)
216 add_char (font_info, face, j);
218 else
220 grub_uint32_t char_code, glyph_index;
222 for (char_code = FT_Get_First_Char (face, &glyph_index);
223 glyph_index;
224 char_code = FT_Get_Next_Char (face, char_code, &glyph_index))
225 add_char (font_info, face, char_code);
229 void
230 write_string_section (char *name, char *str, int* offset, FILE* file)
232 grub_uint32_t leng, leng_be32;
234 leng = strlen (str) + 1;
235 leng_be32 = grub_cpu_to_be32 (leng);
237 grub_util_write_image (name, 4, file);
238 grub_util_write_image ((char *) &leng_be32, 4, file);
239 grub_util_write_image (str, leng, file);
241 *offset += 8 + leng;
244 void
245 write_be16_section (char *name, grub_uint16_t data, int* offset, FILE* file)
247 grub_uint32_t leng;
249 leng = grub_cpu_to_be32 (2);
250 data = grub_cpu_to_be16 (data);
251 grub_util_write_image (name, 4, file);
252 grub_util_write_image ((char *) &leng, 4, file);
253 grub_util_write_image ((char *) &data, 2, file);
255 *offset += 10;
258 void
259 print_glyphs (struct grub_font_info *font_info)
261 int num;
262 struct grub_glyph_info *glyph;
263 char line[512];
265 for (glyph = font_info->glyph, num = 0; glyph; glyph = glyph->next, num++)
267 int x, y, xmax, xmin, ymax, ymin;
268 grub_uint8_t *bitmap, mask;
270 printf ("\nGlyph #%d, U+%04x\n", num, glyph->char_code);
271 printf ("Width %d, Height %d, X offset %d, Y offset %d, Device width %d\n",
272 glyph->width, glyph->height, glyph->x_ofs, glyph->y_ofs,
273 glyph->device_width);
275 xmax = glyph->x_ofs + glyph->width;
276 if (xmax < glyph->device_width)
277 xmax = glyph->device_width;
279 xmin = glyph->x_ofs;
280 if (xmin > 0)
281 xmin = 0;
283 ymax = glyph->y_ofs + glyph->height;
284 if (ymax < font_info->size - font_info->desc)
285 ymax = font_info->size - font_info->desc;
287 ymin = glyph->y_ofs;
288 if (ymin > - font_info->desc)
289 ymin = - font_info->desc;
291 bitmap = glyph->bitmap;
292 mask = 0x80;
293 for (y = ymax - 1; y >= ymin; y--)
295 int line_pos;
297 line_pos = 0;
298 for (x = xmin; x < xmax; x++)
300 if ((x >= glyph->x_ofs) &&
301 (x < glyph->x_ofs + glyph->width) &&
302 (y >= glyph->y_ofs) &&
303 (y < glyph->y_ofs + glyph->height))
305 line[line_pos++] = (*bitmap & mask) ? '#' : '_';
306 mask >>= 1;
307 if (mask == 0)
309 mask = 0x80;
310 bitmap++;
313 else if ((x >= 0) &&
314 (x < glyph->device_width) &&
315 (y >= - font_info->desc) &&
316 (y < font_info->size - font_info->desc))
318 line[line_pos++] = ((x == 0) || (y == 0)) ? '+' : '.';
320 else
321 line[line_pos++] = '*';
323 line[line_pos] = 0;
324 printf ("%s\n", line);
329 void
330 write_font (struct grub_font_info *font_info, char *output_file)
332 FILE *file;
333 grub_uint32_t leng, data;
334 char style_name[20], *font_name;
335 struct grub_glyph_info *cur, *pre;
336 int num, offset;
338 file = fopen (output_file, "wb");
339 if (! file)
340 grub_util_error ("Can\'t write to file %s.", output_file);
342 offset = 0;
344 leng = grub_cpu_to_be32 (4);
345 grub_util_write_image ("FILE", 4, file);
346 grub_util_write_image ((char *) &leng, 4, file);
347 grub_util_write_image ("PFF2", 4, file);
348 offset += 12;
350 if (! font_info->name)
351 font_info->name = "Unknown";
353 if (font_info->flags & GRUB_FONT_FLAG_BOLD)
354 font_info->style |= FT_STYLE_FLAG_BOLD;
356 style_name[0] = 0;
357 if (font_info->style & FT_STYLE_FLAG_BOLD)
358 strcpy (style_name, " Bold");
360 if (font_info->style & FT_STYLE_FLAG_ITALIC)
361 strcat (style_name, " Italic");
363 if (! style_name[0])
364 strcpy (style_name, " Regular");
366 asprintf (&font_name, "%s %s %d", font_info->name, &style_name[1],
367 font_info->size);
369 write_string_section ("NAME", font_name, &offset, file);
370 write_string_section ("FAMI", font_info->name, &offset, file);
371 write_string_section ("WEIG",
372 (font_info->style & FT_STYLE_FLAG_BOLD) ?
373 "bold" : "normal",
374 &offset, file);
375 write_string_section ("SLAN",
376 (font_info->style & FT_STYLE_FLAG_ITALIC) ?
377 "italic" : "normal",
378 &offset, file);
380 write_be16_section ("PTSZ", font_info->size, &offset, file);
381 write_be16_section ("MAXW", font_info->max_width, &offset, file);
382 write_be16_section ("MAXH", font_info->max_height, &offset, file);
384 if (! font_info->desc)
386 if (font_info->min_y >= 0)
387 font_info->desc = 1;
388 else
389 font_info->desc = - font_info->min_y;
392 write_be16_section ("ASCE", font_info->size - font_info->desc, &offset, file);
393 write_be16_section ("DESC", font_info->desc, &offset, file);
395 if (font_verbosity > 0)
397 printf ("Font name: %s\n", font_name);
398 printf ("Max width: %d\n", font_info->max_width);
399 printf ("Max height: %d\n", font_info->max_height);
400 printf ("Font ascent: %d\n", font_info->size - font_info->desc);
401 printf ("Font descent: %d\n", font_info->desc);
404 num = 0;
405 pre = 0;
406 cur = font_info->glyph;
407 while (cur)
409 struct grub_glyph_info *nxt;
411 nxt = cur->next;
412 cur->next = pre;
413 pre = cur;
414 cur = nxt;
415 num++;
418 font_info->glyph = pre;
420 if (font_verbosity > 0)
421 printf ("Number of glyph: %d\n", num);
423 leng = grub_cpu_to_be32 (num * 9);
424 grub_util_write_image ("CHIX", 4, file);
425 grub_util_write_image ((char *) &leng, 4, file);
426 offset += 8 + num * 9 + 8;
428 for (cur = font_info->glyph; cur; cur = cur->next)
430 data = grub_cpu_to_be32 (cur->char_code);
431 grub_util_write_image ((char *) &data, 4, file);
432 data = 0;
433 grub_util_write_image ((char *) &data, 1, file);
434 data = grub_cpu_to_be32 (offset);
435 grub_util_write_image ((char *) &data, 4, file);
436 offset += 10 + cur->bitmap_size;
439 leng = 0xffffffff;
440 grub_util_write_image ("DATA", 4, file);
441 grub_util_write_image ((char *) &leng, 4, file);
443 for (cur = font_info->glyph; cur; cur = cur->next)
445 data = grub_cpu_to_be16 (cur->width);
446 grub_util_write_image ((char *) &data, 2, file);
447 data = grub_cpu_to_be16 (cur->height);
448 grub_util_write_image ((char *) &data, 2, file);
449 data = grub_cpu_to_be16 (cur->x_ofs);
450 grub_util_write_image ((char *) &data, 2, file);
451 data = grub_cpu_to_be16 (cur->y_ofs);
452 grub_util_write_image ((char *) &data, 2, file);
453 data = grub_cpu_to_be16 (cur->device_width);
454 grub_util_write_image ((char *) &data, 2, file);
455 grub_util_write_image ((char *) &cur->bitmap[0], cur->bitmap_size, file);
458 if (font_verbosity > 1)
459 print_glyphs (font_info);
461 fclose (file);
465 main (int argc, char *argv[])
467 struct grub_font_info font_info;
468 FT_Library ft_lib;
469 int font_index = 0;
470 int font_size = 0;
471 char *output_file = NULL;
473 memset (&font_info, 0, sizeof (font_info));
475 progname = "grub-mkfont";
477 /* Check for options. */
478 while (1)
480 int c = getopt_long (argc, argv, "bao:n:i:s:d:r:hVv", options, 0);
482 if (c == -1)
483 break;
484 else
485 switch (c)
487 case 'b':
488 font_info.flags |= GRUB_FONT_FLAG_BOLD;
489 break;
491 case 0x100:
492 font_info.flags |= GRUB_FONT_FLAG_NOBITMAP;
493 break;
495 case 0x101:
496 font_info.flags |= GRUB_FONT_FLAG_NOHINTING;
497 break;
499 case 'a':
500 font_info.flags |= GRUB_FONT_FLAG_FORCEHINT;
501 break;
503 case 'o':
504 output_file = optarg;
505 break;
507 case 'n':
508 font_info.name = optarg;
509 break;
511 case 'i':
512 font_index = strtoul (optarg, NULL, 0);
513 break;
515 case 's':
516 font_size = strtoul (optarg, NULL, 0);
517 break;
519 case 'r':
521 char *p = optarg;
523 while (1)
525 grub_uint32_t a, b;
527 a = strtoul (p, &p, 0);
528 if (*p != '-')
529 grub_util_error ("Invalid font range");
530 b = strtoul (p + 1, &p, 0);
531 if ((font_info.num_range & (GRUB_FONT_RANGE_BLOCK - 1)) == 0)
532 font_info.ranges = xrealloc (font_info.ranges,
533 (font_info.num_range +
534 GRUB_FONT_RANGE_BLOCK) *
535 sizeof (int) * 2);
537 font_info.ranges[font_info.num_range * 2] = a;
538 font_info.ranges[font_info.num_range * 2 + 1] = b;
539 font_info.num_range++;
541 if (*p)
543 if (*p != ',')
544 grub_util_error ("Invalid font range");
545 else
546 p++;
548 else
549 break;
551 break;
554 case 'd':
555 font_info.desc = strtoul (optarg, NULL, 0);
556 break;
558 case 'h':
559 usage (0);
560 break;
562 case 'V':
563 printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
564 return 0;
566 case 'v':
567 font_verbosity++;
568 break;
570 default:
571 usage (1);
572 break;
576 if (! output_file)
577 grub_util_error ("No output file is specified.");
579 if (FT_Init_FreeType (&ft_lib))
580 grub_util_error ("FT_Init_FreeType fails");
582 for (; optind < argc; optind++)
584 FT_Face ft_face;
585 int size;
587 if (FT_New_Face (ft_lib, argv[optind], font_index, &ft_face))
589 grub_util_info ("Can't open file %s, index %d\n", argv[optind],
590 font_index);
591 continue;
594 if ((! font_info.name) && (ft_face->family_name))
595 font_info.name = xstrdup (ft_face->family_name);
597 size = font_size;
598 if (! size)
600 if ((ft_face->face_flags & FT_FACE_FLAG_SCALABLE) ||
601 (! ft_face->num_fixed_sizes))
602 size = GRUB_FONT_DEFAULT_SIZE;
603 else
604 size = ft_face->available_sizes[0].height;
607 font_info.style = ft_face->style_flags;
608 font_info.size = size;
610 FT_Set_Pixel_Sizes (ft_face, size, size);
611 add_font (&font_info, ft_face);
612 FT_Done_Face (ft_face);
615 FT_Done_FreeType (ft_lib);
617 write_font (&font_info, output_file);
619 return 0;