A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007 Jonas Hurrelmann
11 *
12 * A command-line tool to convert ttf file to bitmap fonts
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <ft2build.h>
22#include FT_FREETYPE_H
23#include FT_GLYPH_H
24
25#include <stdio.h>
26#ifdef WIN32
27#ifdef _MSC_VER
28#define snprintf _snprintf
29#endif
30#else
31#include <stdlib.h>
32#include <unistd.h>
33#endif
34#include FT_SFNT_NAMES_H
35#include FT_TRUETYPE_TABLES_H
36
37#include <string.h>
38#include <stdint.h>
39/*
40 * Set the default values used to generate a BDF font.
41 */
42#ifndef DEFAULT_PLATFORM_ID
43#define DEFAULT_PLATFORM_ID 3
44#endif
45
46#ifndef DEFAULT_ENCODING_ID
47#define DEFAULT_ENCODING_ID 1
48#endif
49
50#define ABS(x) (((x) < 0) ? -(x) : (x))
51
52#define VERSION "RB12"
53/*
54 * nameID macros for getting strings from the OT font.
55 */
56enum {
57 BDFOTF_COPYRIGHT_STRING = 0,
58 BDFOTF_FAMILY_STRING,
59 BDFOTF_SUBFAMILY_STRING,
60 BDFOTF_UNIQUEID_STRING,
61 BDFOTF_FULLNAME_STRING,
62 BDFOTF_VENDOR_STRING,
63 BDFOTF_POSTSCRIPT_STRING,
64 BDFOTF_TRADEMARK_STRING,
65};
66/*
67 * String names for the string indexes. Used for error messages.
68 */
69static char *string_names[] = {
70 "\"Copyright\"",
71 "\"Family\"",
72 "\"SubFamily\"",
73 "\"Unique ID\"",
74 "\"Full Name\"",
75 "\"Vendor\"",
76 "\"Postscript Name\"",
77 "\"Trademark\""
78};
79
80
81/*
82 * The default platform and encoding ID's.
83 */
84static int pid = DEFAULT_PLATFORM_ID;
85static int eid = DEFAULT_ENCODING_ID;
86
87
88/*
89 * A flag indicating if a CMap was found or not.
90 */
91static FT_UShort nocmap;
92
93int pct = 0; /* display ttc table if it is not zero. */
94FT_Long max_char = 0x10FFFF;
95int pixel_size = 15;
96FT_Long start_char = 0;
97FT_Long limit_char;
98FT_Long firstchar = 0;
99FT_Long lastchar;
100FT_Long ttc_index = -1;
101int flg_all_ttc = 0;
102short antialias = 1; /* smooth fonts with gray levels */
103int oflag = 0;
104char outfile[1024];
105float between_chr = 0.0f;
106float between_row = 0.0f;
107int hv_resolution = 60;
108int dump_glyphs = 0;
109int digits_equally_wide = 1; /* Try to make digits equally wide */
110int trimming = 0;
111int trim_dp = 0; /* trim descent percent */
112int trim_da = 0; /* trim descnet actual */
113int trim_ap = 0; /* trim ascent precent */
114int trim_aa = 0; /* trim ascent actual */
115int ft_load_opts = FT_LOAD_RENDER | FT_LOAD_NO_BITMAP;
116
117struct font_header_struct {
118 uint8_t header[4]; /* magic number and version bytes */
119 uint16_t maxwidth; /* max width in pixels */
120 uint16_t height; /* height in pixels */
121 uint16_t ascent; /* ascent (baseline) height */
122 uint16_t depth; /* depth 0=1-bit, 1=4-bit */
123 uint32_t firstchar; /* first character in font */
124 uint32_t defaultchar; /* default character in font */
125 uint32_t size; /* # characters in font */
126 uint32_t nbits; /* # bytes imagebits data in file */ /* = bits_size */
127
128 uint32_t noffset; /* # longs offset data in file */
129 uint32_t nwidth; /* # bytes width data in file */
130};
131
132struct font_struct {
133 struct font_header_struct header;
134 uint8_t *chars_data;
135 uint16_t *offset;
136 uint32_t *offset_long;
137 uint8_t *width;
138};
139
140struct ttc_table{
141 FT_Long ttc_count;
142 char **ttf_name;
143};
144
145/* exit the program with given message */
146static void
147panic( const char* message)
148{
149 fprintf( stderr, "%s\n", message );
150 exit( 1 );
151}
152
153static void
154arg_panic( const char* message, const char* arg )
155{
156 fprintf( stderr, "%s: %s\n", message, arg );
157 exit( 1 );
158}
159
160static int writebyte(FILE *fp, unsigned char c)
161{
162 return putc(c, fp) != EOF;
163}
164
165static int writeshort(FILE *fp, unsigned short s)
166{
167 putc(s, fp);
168 return putc(s>>8, fp) != EOF;
169}
170
171static int writeint(FILE *fp, unsigned int l)
172{
173 putc(l, fp);
174 putc(l>>8, fp);
175 putc(l>>16, fp);
176 return putc(l>>24, fp) != EOF;
177}
178
179static int writestr(FILE *fp, char *str, int count)
180{
181 return (int)fwrite(str, 1, count, fp) == count;
182}
183
184/* print usage information */
185void usage(void)
186{
187 char help[] = {
188 "Usage: convttf [options] [input-files]\n"
189 " convttf [options] [-o output-file] [single-input-file]\n\n"
190 " Default output-file : <font-size>-<basename>.fnt.\n"
191 " When '-ta' or '-tc' is specified in command line,\n "
192 " default output-file is: \n"
193 " <font-size>-<internal postscript-name of input-file>.fnt.\n"
194 "Options:\n"
195 " -s N Start output at character encodings >= N\n"
196 " -l N Limit output to character encodings <= N\n"
197 " -p N Font size N in pixel (default N=15)\n"
198 " -c N Character separation in pixel.Insert space between lines.\n"
199 " -x Trim glyphs horizontally of nearly empty space\n"
200 " (to improve spacing on V's W's, etc.)\n"
201 " -X Set the horizontal and vertical resolution (default: 60)\n"
202 " -TA N Trim vertical ascent (N percent)\n"
203 " -TD N Trim vertical descent (N percent)\n"
204 " -Ta N Trim vertical ascent (N pixels)\n"
205 " -Td N Trim vertical descent (N pixels)\n"
206 " -r N Row separation in pixel.Insert space between characters\n"
207 " -d Debug: print converted glyph images\n"
208 " -tt Display the True Type Collection tables available in the font\n"
209 " -t N Index of true type collection. It must be start from 0.(default N=0).\n"
210 " -ta Convert all fonts in ttc (ignores outfile option)\n"
211 " -w Don't try to make digits (0-9) equally wide\n"
212 " -L Use lighter hinting algorithm\n"
213 };
214 fprintf(stderr, "%s", help);
215 exit( 1 );
216}
217
218/* remove directory prefix and file suffix from full path*/
219char *basename(char *path)
220{
221 char *p, *b;
222 static char base[256];
223
224 /* remove prepended path and extension*/
225 b = path;
226 for (p=path; *p; ++p) {
227#ifdef WIN32
228 if (*p == '/' || *p == '\\')
229#else
230 if (*p == '/')
231#endif
232 b = p + 1;
233 }
234 strcpy(base, b);
235 for (p=base; *p; ++p) {
236 if (*p == '.') {
237 *p = 0;
238 break;
239 }
240 }
241 return base;
242}
243
244
245void setcharmap(FT_Face face)
246{
247 FT_Long i;
248
249 /*
250 * Get the requested cmap.
251 */
252 for (i = 0; i < face->num_charmaps; i++) {
253 if (face->charmaps[i]->platform_id == pid &&
254 face->charmaps[i]->encoding_id == eid)
255 break;
256 }
257
258 if (i == face->num_charmaps && pid == 3 && eid == 1) {
259 /*
260 * Make a special case when this fails with pid == 3 and eid == 1.
261 * Change to eid == 0 and try again. This captures the two possible
262 * cases for MS fonts. Some other method should be used to cycle
263 * through all the alternatives later.
264 */
265 for (i = 0; i < face->num_charmaps; i++) {
266 if (face->charmaps[i]->platform_id == pid &&
267 face->charmaps[i]->encoding_id == 0)
268 break;
269 }
270 if (i < face->num_charmaps) {
271 pid = 3;
272 eid = 1;
273 FT_Set_Charmap(face, face->charmaps[i]);
274 } else {
275 /*
276 * No CMAP was found.
277 */
278 nocmap = 1;
279 pid = eid = -1;
280 }
281 } else {
282 FT_Set_Charmap(face, face->charmaps[i]);
283 nocmap = 0;
284 }
285
286}
287
288/*
289 * quote in otf2bdf.
290 * A generic routine to get a name from the OT name table. This routine
291 * always looks for English language names and checks three possibilities:
292 * 1. English names with the MS Unicode encoding ID.
293 * 2. English names with the MS unknown encoding ID.
294 * 3. English names with the Apple Unicode encoding ID.
295 *
296 * The particular name ID mut be provided (e.g. nameID = 0 for copyright
297 * string, nameID = 6 for Postscript name, nameID = 1 for typeface name.
298 *
299 * If the `dash_to_space' flag is non-zero, all dashes (-) in the name will be
300 * replaced with the character passed.
301 *
302 * Returns the number of bytes added.
303 */
304static int
305otf_get_english_string(FT_Face face, int nameID, int dash_to_space,
306 char *name, int name_size)
307{
308
309 int j, encid;
310 FT_UInt i, nrec;
311 FT_SfntName sfntName;
312 unsigned char *s = NULL;
313 unsigned short slen = 0;
314
315 nrec = FT_Get_Sfnt_Name_Count(face);
316
317 for (encid = 1, j = 0; j < 2; j++, encid--) {
318 /*
319 * Locate one of the MS English font names.
320 */
321 for (i = 0; i < nrec; i++) {
322 FT_Get_Sfnt_Name(face, i, &sfntName);
323 if (sfntName.platform_id == 3 &&
324 sfntName.encoding_id == encid &&
325 sfntName.name_id == nameID &&
326 (sfntName.language_id == 0x0409 ||
327 sfntName.language_id == 0x0809 ||
328 sfntName.language_id == 0x0c09 ||
329 sfntName.language_id == 0x1009 ||
330 sfntName.language_id == 0x1409 ||
331 sfntName.language_id == 0x1809)) {
332 s = sfntName.string;
333 slen = sfntName.string_len;
334 break;
335 }
336 }
337
338 if (i < nrec) {
339 if (slen >> 1 >= name_size) {
340 fprintf(stderr, "warning: %s string longer than buffer."
341 "Truncating to %d bytes.\n", string_names[nameID], name_size);
342 slen = name_size << 1;
343 }
344
345 /*
346 * Found one of the MS English font names. The name is by
347 * definition encoded in Unicode, so copy every second byte into
348 * the `name' parameter, assuming there is enough space.
349 */
350 for (i = 1; i < slen; i += 2) {
351 if (dash_to_space)
352 *name++ = (s[i] != '-') ? s[i] : ' ';
353 else if (s[i] == '\r' || s[i] == '\n') {
354 if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n')
355 i += 2;
356 *name++ = ' ';
357 *name++ = ' ';
358 } else
359 *name++ = s[i];
360 }
361 *name = 0;
362 return (slen >> 1);
363 }
364 }
365
366 /*
367 * No MS English name found, attempt to find an Apple Unicode English
368 * name.
369 */
370 for (i = 0; i < nrec; i++) {
371 FT_Get_Sfnt_Name(face, i, &sfntName);
372 if (sfntName.platform_id == 0 && sfntName.language_id == 0 &&
373 sfntName.name_id == nameID) {
374 s = sfntName.string;
375 slen = sfntName.string_len;
376 break;
377 }
378 }
379
380 if (i < nrec) {
381 if (slen >> 1 >= name_size) {
382 fprintf(stderr, "warning: %s string longer than buffer."
383 "Truncating to %d bytes.\n", string_names[nameID], name_size);
384 slen = name_size << 1;
385 }
386
387 /*
388 * Found the Apple Unicode English name. The name is by definition
389 * encoded in Unicode, so copy every second byte into the `name'
390 * parameter, assuming there is enough space.
391 */
392 for (i = 1; i < slen; i += 2) {
393 if (dash_to_space)
394 *name++ = (s[i] != '-') ? s[i] : ' ';
395 else if (s[i] == '\r' || s[i] == '\n') {
396 if (s[i] == '\r' && i + 2 < slen && s[i + 2] == '\n')
397 i += 2;
398 *name++ = ' ';
399 *name++ = ' ';
400 } else
401 *name++ = s[i];
402 }
403 *name = 0;
404 return (slen >> 1);
405 }
406
407 return 0;
408}
409
410
411int get_ttc_table(char *path, struct ttc_table *ttcname )
412{
413
414
415 FT_Error err;
416 FT_Library library;
417 FT_Face face;
418 FT_Long i;
419 char xlfd[BUFSIZ];
420
421 /* init number of ttf in ttc */
422 ttcname->ttc_count = 0;
423
424 /* Initialize engine */
425 if ( ( err = FT_Init_FreeType( &library ) ) != 0 )
426 {
427 panic( "Error while initializing engine" );
428 return err;
429 }
430
431
432 /* Load face */
433 err = FT_New_Face( library, path, (FT_Long) 0, &face );
434 if ( err )
435 {
436 arg_panic( "Could not find/open font", path );
437 return err;
438 }
439
440 ttcname->ttc_count = face->num_faces;
441 ttcname->ttf_name = malloc( sizeof(char*) * ttcname->ttc_count);
442
443 for(i = 0; i < ttcname->ttc_count; i++)
444 {
445 err = FT_New_Face( library, path, i, &face );
446 if ( err == FT_Err_Cannot_Open_Stream )
447 arg_panic( "Could not find/open font", path );
448 otf_get_english_string(face, BDFOTF_POSTSCRIPT_STRING, 0, xlfd,
449 sizeof(xlfd));
450 ttcname->ttf_name[i] = malloc(sizeof(char) * (strlen(xlfd) + 1 ));
451 strcpy(ttcname->ttf_name[i], xlfd);
452 }
453 return 0;
454}
455
456void print_ttc_table(char* path)
457{
458 struct ttc_table ttcname;
459 FT_Long i;
460
461 get_ttc_table(path, &ttcname);
462 printf("ttc header count = %ld \n\n", ttcname.ttc_count);
463 printf("Encoding tables available in the true type collection\n\n");
464 printf("INDEX\tPOSTSCRIPT NAME\n");
465 printf("-----------------------------------------------------\n");
466 for(i = 0; i < ttcname.ttc_count; i++)
467 {
468 printf("%ld\t%s\n", i, ttcname.ttf_name[i]);
469 }
470 for(i = 0; i < ttcname.ttc_count; i++)
471 {
472 free(ttcname.ttf_name[i]);
473 }
474 printf("\n\n");
475 free(ttcname.ttf_name);
476
477 return;
478}
479
480FT_Long getcharindex(FT_Face face, FT_Long code)
481{
482 FT_Long idx;
483 if (nocmap) {
484 if (code >= face->num_glyphs)
485 idx = 0;
486 else
487 idx = code;
488 } else
489 idx = FT_Get_Char_Index( face, code);
490
491 if ( idx <= 0 || idx > face->num_glyphs)
492 return 0;
493 else
494 return idx;
495}
496
497void print_raw_glyph( FT_Face face)
498{
499 int pixel,row,col,width;
500 width = face->glyph->metrics.width >> 6;
501
502 printf("\n---Raw-Glyph---\n");
503 for(row=0; row < face->glyph->metrics.height >> 6; row++)
504 {
505 printf("_");
506 for(col=0; col < width; col++)
507 {
508 pixel = *(face->glyph->bitmap.buffer+width*row+col)/26;
509 if ( pixel ) printf("%d",pixel); else printf(" ");
510 }
511 printf("_\n");
512 }
513 printf("----End-----\n");
514}
515
516int glyph_width( FT_Face face, FT_Long code, FT_Long digit_width )
517{
518 int width;
519
520 if (code >= '0' && code <= '9' && digit_width)
521 {
522 width = digit_width;
523 }
524 else
525 {
526 int pitch, h_adv;
527 unsigned spacing = (unsigned)(between_chr * (1<<6));/* convert to fixed point */
528
529 pitch = ABS(face->glyph->bitmap.pitch);
530 h_adv = face->glyph->metrics.horiAdvance >> 6;
531 width = (face->glyph->metrics.width + spacing) >> 6;
532
533 if(pitch == 0) pitch = h_adv;
534 if(width < pitch) width = pitch;
535 }
536
537 return width;
538}
539
540FT_Long check_digit_width( FT_Face face )
541{
542 FT_Long code;
543 FT_Long last_advance = -1;
544
545 for (code='0'; code <= '9'; ++code)
546 {
547 FT_Glyph_Metrics* metrics;
548
549 FT_Load_Char(face, code, ft_load_opts);
550 metrics = &face->glyph->metrics;
551
552 if ((last_advance != -1 && last_advance != metrics->horiAdvance) ||
553 metrics->horiBearingX < 0)
554 {
555 last_advance = 0;
556 break;
557 }
558
559 last_advance = metrics->horiAdvance;
560 }
561
562 return last_advance >> 6;
563}
564
565void trim_glyph( FT_GlyphSlot glyph, int *empty_first_col,
566 int *empty_last_col, int *width )
567{
568 int row;
569 int stride = glyph->bitmap.pitch;
570 int end = stride-1;
571 int trim_left = 2, trim_right = 2;
572
573 const unsigned char limit = 64u;
574 const unsigned char *image = glyph->bitmap.buffer;
575
576 if (*width < 2)
577 return; /* nothing to do? */
578
579 for(row=0; row< glyph->metrics.height >> 6; row++)
580 {
581 const unsigned char *column = image+row*stride;
582 if (*column++ < limit && trim_left)
583 {
584 if (*column >= limit/2)
585 trim_left = 1;
586 }
587 else
588 trim_left = 0;
589
590 column = image+row*stride+end;
591 if (*column-- < limit && trim_right)
592 {
593 if (*column >= limit/2)
594 trim_right = 1;
595 }
596 else
597 trim_right = 0;
598 }
599
600
601 (*width) -= trim_left + trim_right;
602 if (*width < 0) *width = 0;
603
604 *empty_first_col = trim_left;
605 *empty_last_col = trim_right;
606}
607
608void convttf(char* path, char* destfile, FT_Long face_index)
609{
610 FT_Error err;
611 FT_Library library;
612 FT_Face face;
613 int w,h;
614 int row,col;
615 int empty_first_col, empty_last_col;
616 FT_Long charindex;
617 FT_Long idx = 0;
618 FT_Long code;
619 FT_Long digit_width = 0;
620 float extra_space;
621 FT_Long char_count;
622 char use_long_offset;
623 int done = 0;
624 char char_name[1024];
625 int converted_char_count = 0;
626 int failed_char_count = 0;
627
628 int depth = 2;
629 unsigned char bit_shift = 1u << depth;
630 unsigned char pixel_per_byte = CHAR_BIT / bit_shift;
631 struct font_struct export_font;
632 char pad[] = {0,0,0,0};
633 unsigned int skip,i;
634 FILE *file;
635
636 /* Initialize engine */
637 if ( ( err = FT_Init_FreeType( &library ) ) != 0 )
638 panic( "Error while initializing engine" );
639
640 /* Load face */
641 err = FT_New_Face( library, path, (FT_Long) face_index, &face );
642 if ( err == FT_Err_Cannot_Open_Stream )
643 arg_panic( "Could not find/open font\n", path );
644 else if ( err )
645 arg_panic( "Error while opening font\n", path );
646
647
648 setcharmap( face );
649 /* Set font header data */
650
651 export_font.header.header[0] = 'R';
652 export_font.header.header[1] = 'B';
653 export_font.header.header[2] = '1';
654 export_font.header.header[3] = '2';
655#if 0
656 export_font.header.height = 0;
657 export_font.header.ascent = 0;
658#endif
659
660 extra_space = (float)(between_row-trim_aa-trim_da);
661 FT_Set_Char_Size( face, 0, pixel_size << 6, hv_resolution, hv_resolution );
662 export_font.header.ascent =
663 ((face->size->metrics.ascender*(100-trim_ap)/100) >> 6) - trim_aa;
664
665 export_font.header.height =
666 (((face->size->metrics.ascender*(100-trim_ap)/100) -
667 (face->size->metrics.descender*(100-trim_dp)/100)) >> 6) + extra_space;
668
669 printf("\n");
670 printf("Please wait, converting %s:\n", path);
671
672 /* "face->num_glyphs" is NG.; */
673 if ( limit_char == 0 ) limit_char = max_char;
674 if ( limit_char > max_char ) limit_char = max_char;
675
676 char_count = 0;
677
678
679
680 export_font.header.maxwidth = 1;
681 export_font.header.depth = 1;
682 firstchar = limit_char;
683 lastchar = start_char;
684
685 if (digits_equally_wide)
686 digit_width = check_digit_width(face);
687
688 /* calculate memory usage */
689 for(code = start_char; code <= limit_char ; code++ )
690 {
691 charindex = getcharindex( face, code);
692 if ( !(charindex) ) continue;
693 err = FT_Load_Glyph(face, charindex, ft_load_opts);
694 if ( err ) continue;
695
696 w = glyph_width( face, code, digit_width );
697 if (w == 0) continue;
698 empty_first_col = empty_last_col = 0;
699 if(trimming)
700 trim_glyph( face->glyph, &empty_first_col, &empty_last_col, &w);
701
702 if (export_font.header.maxwidth < w)
703 export_font.header.maxwidth = w;
704
705
706 char_count++;
707 idx += (w*export_font.header.height + pixel_per_byte - 1)/pixel_per_byte;
708
709 if (code >= lastchar)
710 lastchar = code;
711
712 if (code <= firstchar)
713 firstchar = code;
714 }
715 export_font.header.defaultchar = firstchar;
716 export_font.header.firstchar = firstchar;
717 export_font.header.size = lastchar - firstchar + 1;
718 export_font.header.nbits = idx;
719 export_font.header.noffset = export_font.header.size;
720 export_font.header.nwidth = export_font.header.size;
721
722 /* check if we need to use long offsets */
723 use_long_offset = (export_font.header.nbits >= 0xFFDB );
724
725 /* allocate memory */
726 export_font.offset = NULL;
727 export_font.offset_long = NULL;
728 if (use_long_offset)
729 export_font.offset_long =
730 malloc( sizeof(FT_Long)* export_font.header.noffset );
731 else
732 export_font.offset =
733 malloc( sizeof(unsigned short)* export_font.header.noffset );
734
735 export_font.width =
736 malloc( sizeof(unsigned char) * export_font.header.nwidth );
737 export_font.chars_data =
738 malloc( sizeof(unsigned char) * export_font.header.nbits );
739
740 /* for now we use the full height for each character */
741 h = export_font.header.height;
742
743 idx = 0;
744
745 for( code = firstchar; code <= lastchar; code++ )
746 {
747 FT_GlyphSlot slot;
748 FT_Bitmap* source;
749 unsigned char* src;
750 unsigned char* tmpbuf;
751 int start_y;
752
753 int glyph_height;
754 int stride;
755 unsigned char* buf;
756 unsigned char* endbuf;
757
758 /* insert empty pixels on the left */
759 int col_off;
760 int numbits;
761 unsigned int field;
762
763 /* Get gylph index from the char and render it */
764 charindex = getcharindex( face, code);
765 if ( !charindex )
766 {
767 if ( use_long_offset )
768 export_font.offset_long[code - firstchar] = export_font.offset_long[0];
769 else
770 export_font.offset[code - firstchar] = export_font.offset[0];
771 export_font.width[code - firstchar] = export_font.width[0];
772 continue;
773 }
774
775 err = FT_Load_Glyph(face, charindex, ft_load_opts);
776 if ( err ) {
777 continue;
778 }
779 if FT_HAS_GLYPH_NAMES( face )
780 FT_Get_Glyph_Name( face, charindex, char_name, 16);
781 else
782 char_name[0] = '\0';
783
784 slot = face->glyph;
785 source = &slot->bitmap;
786#if 0
787 print_raw_glyph( face );
788#endif
789 w = glyph_width( face, code, digit_width );
790 if (w == 0) continue;
791 empty_first_col = empty_last_col = 0;
792
793 if(trimming)
794 trim_glyph( face->glyph, &empty_first_col, &empty_last_col, &w );
795
796 if ( use_long_offset )
797 export_font.offset_long[code - firstchar] = idx;
798 else
799 export_font.offset[code - firstchar] = idx;
800
801 export_font.width[code - firstchar] = w;
802
803 /* copy the glyph bitmap to a full sized glyph bitmap */
804 src = source->buffer;
805 tmpbuf = malloc(sizeof(unsigned char) * w * h);
806 memset(tmpbuf, 0xff, w*h);
807 start_y = export_font.header.ascent - slot->bitmap_top;
808
809 glyph_height = source->rows;
810 stride = source->pitch;
811 buf = tmpbuf;
812 endbuf = tmpbuf + w*h;
813
814 err = 0;
815 /* insert empty pixels on the left */
816 col_off = w - stride;
817 if (col_off > 1) col_off /= 2;
818 if (col_off < 0) col_off = 0;
819
820 for(row=0; row < glyph_height; row++)
821 {
822 if(row+start_y < 0 || row+start_y >= h)
823 continue;
824 for(col = empty_first_col; col < stride; col++)
825 {
826 unsigned char *tsrc, *dst;
827 dst = buf + (w*(start_y+row)) + col + col_off;
828 tsrc = src + stride*row + col;
829 if (dst < endbuf && dst >= tmpbuf)
830 *dst = 0xff - *tsrc;
831 else {
832 err = 1;
833 printf("Error! row: %3d col: %3d\n", row, col);
834 }
835 }
836 }
837 if(err) print_raw_glyph(face);
838
839 buf = tmpbuf;
840 field = 0;
841 numbits = pixel_per_byte;
842
843 for(row=0; row < h; row++)
844 {
845 for(col=0; col < w; col++)
846 {
847 unsigned int src2 = *buf++;
848 unsigned int cur_col = (src2 + 8) / 17;
849 field |= (cur_col << (bit_shift*(pixel_per_byte-numbits)));
850
851 if (--numbits == 0)
852 {
853 export_font.chars_data[idx++] = (unsigned char)field;
854 numbits = pixel_per_byte;
855 field = 0;
856 }
857 }
858 }
859
860 /* Pad last byte */
861 if (numbits != pixel_per_byte)
862 {
863 export_font.chars_data[idx++] = (unsigned char)field;
864 }
865
866 if( dump_glyphs )
867 {
868 /* debug: dump char */
869 unsigned char bit_max = (1 << bit_shift) - 1;
870 printf("\n---Converted Glyph Dump---\n");
871
872 if ( code > 32 && code < 255 ) {
873 unsigned char current_data;
874 unsigned char font_bits;
875
876 row = h;
877 if(use_long_offset)
878 buf = &(export_font.chars_data[export_font.offset_long[
879 code - firstchar]]);
880 else
881 buf = &(export_font.chars_data[export_font.offset[
882 code - firstchar]]);
883 numbits = pixel_per_byte;
884 current_data = *buf;
885 do
886 {
887 col = w;
888 printf("-");
889 do
890 {
891 font_bits = current_data & bit_max;
892 if (font_bits==bit_max)
893 printf(" ");
894 else
895 {
896 if(font_bits > bit_max/2)
897 printf(".");
898 else
899 printf("@");
900 }
901 if (--numbits == 0)
902 {
903 current_data = *(++buf);
904 numbits = pixel_per_byte;
905 }
906 else
907 {
908 current_data >>= bit_shift;
909 }
910 } while (--col);
911 printf("-\n");
912 } while (--row);
913 }
914 buf = NULL;
915 printf("---End Glyph Dump---\n");
916 }
917
918 free(tmpbuf);
919 converted_char_count++;
920 done = (100*(converted_char_count))/char_count;
921 printf("Converted %s %d (%d%%)\e[K\r",
922 char_name,converted_char_count,done); fflush(stdout);
923 }
924
925 file = fopen(destfile, "wb");
926 printf("Writing %s\n", destfile);
927
928 /* font info */
929 writestr(file, VERSION, 4);
930 writeshort(file, export_font.header.maxwidth);
931 writeshort(file, export_font.header.height);
932 writeshort(file, export_font.header.ascent);
933 writeshort(file, export_font.header.depth);
934 writeint(file, export_font.header.firstchar);
935 writeint(file, export_font.header.defaultchar);
936 writeint(file, export_font.header.size);
937 writeint(file, export_font.header.nbits);
938 writeint(file, export_font.header.noffset);
939 writeint(file, export_font.header.nwidth);
940
941 fwrite( (char*)export_font.chars_data, 1,
942 export_font.header.nbits, file);
943 free(export_font.chars_data);
944
945
946
947 if ( use_long_offset )
948 {
949 skip = ((export_font.header.nbits + 3) & ~3) -
950 export_font.header.nbits;
951 fwrite(pad, 1, skip, file); /* pad */
952 for(i = 0; i < export_font.header.noffset; i++)
953 writeint(file, export_font.offset_long[i]);
954 }
955 else
956 {
957 skip = ((export_font.header.nbits + 1) & ~1) -
958 export_font.header.nbits;
959 fwrite(pad, 1, skip, file); /* pad */
960 for(i = 0; i < export_font.header.noffset; i++)
961 writeshort(file, export_font.offset[i]);
962 }
963
964 for(i = 0; i < export_font.header.nwidth; i++)
965 writebyte(file, export_font.width[i]);
966 free(export_font.width);
967
968 if ( use_long_offset )
969 free(export_font.offset_long);
970 else
971 free(export_font.offset);
972
973 fclose(file);
974 FT_Done_Face( face );
975 FT_Done_FreeType( library );
976 printf("done (converted %d glyphs, %d errors).\e[K\n\n",
977 converted_char_count, failed_char_count);
978
979}
980
981void convttc(char* path)
982{
983 struct ttc_table ttcname;
984 FT_Long i;
985
986 get_ttc_table(path, &ttcname);
987
988 if (ttcname.ttc_count == 0)
989 {
990 printf("This file is a not true type font.\n");
991 return;
992 }
993
994 /* default */
995 if (!flg_all_ttc && ttc_index == -1)
996 {
997 if (!oflag)
998 { /* generate filename */
999 snprintf(outfile, sizeof(outfile),
1000 "%d-%s.fnt", pixel_size, basename(path));
1001 }
1002 convttf(path, outfile, (FT_Long) 0);
1003 }
1004
1005 /* set face_index of ttc */
1006 else if (!flg_all_ttc)
1007 {
1008 print_ttc_table(path);
1009 if ( !oflag )
1010 {
1011 if (ttc_index >= 0 &&
1012 ttc_index < ttcname.ttc_count)
1013 {
1014 if (strcmp(ttcname.ttf_name[ttc_index], "") != 0)
1015 {
1016 snprintf(outfile, sizeof(outfile), "%d-%s.fnt",
1017 pixel_size, ttcname.ttf_name[ttc_index]);
1018 }
1019 else
1020 {
1021 snprintf(outfile, sizeof(outfile), "%d-%s-%ld.fnt",
1022 pixel_size, basename(path), ttc_index);
1023 }
1024 }
1025 else
1026 {
1027 printf("illegal face index of ttc.\n");
1028 }
1029 }
1030 convttf(path, outfile, ttc_index);
1031 }
1032 else { /* convert all fonts */
1033 print_ttc_table(path);
1034 for(i = 0; i < ttcname.ttc_count; i++)
1035 {
1036 snprintf(outfile, sizeof(outfile), "%d-%s.fnt",
1037 pixel_size, ttcname.ttf_name[i]);
1038 convttf(path, outfile, i);
1039 }
1040 }
1041
1042 for(i = 0; i < ttcname.ttc_count; i++)
1043 {
1044 free(ttcname.ttf_name[i]);
1045 }
1046 free(ttcname.ttf_name);
1047}
1048
1049
1050
1051/* parse command line options*/
1052void getopts(int *pac, char ***pav)
1053{
1054 char *p;
1055 char **av;
1056 int ac;
1057 ac = *pac;
1058 av = *pav;
1059
1060 limit_char = max_char;
1061 start_char = 0;
1062
1063 while (ac > 0 && av[0][0] == '-') {
1064 p = &av[0][1];
1065 while( *p)
1066 switch(*p++) {
1067 case 'h':case 'H':
1068 usage();
1069 break;
1070 case ' ': /* multiple -args on av[]*/
1071 while( *p && *p == ' ')
1072 p++;
1073 if( *p++ != '-') /* next option must have dash*/
1074 p = "";
1075 break; /* proceed to next option*/
1076 case 'o': /* set output file*/
1077 oflag = 1;
1078 if (*p) {
1079 strcpy(outfile, p);
1080 while (*p && *p != ' ')
1081 p++;
1082 }
1083 else {
1084 av++; ac--;
1085 if (ac > 0)
1086 strcpy(outfile, av[0]);
1087 }
1088 break;
1089 case 'l': /* set encoding limit*/
1090 if (*p) {
1091 limit_char = atoi(p);
1092 while (*p && *p != ' ')
1093 p++;
1094 }
1095 else {
1096 av++; ac--;
1097 if (ac > 0)
1098 limit_char = atoi(av[0]);
1099 }
1100 break;
1101 case 's': /* set encoding start*/
1102 if (*p) {
1103 start_char = atol(p);
1104 while (*p && *p != ' ')
1105 p++;
1106 }
1107 else {
1108 av++; ac--;
1109 if (ac > 0)
1110 start_char = atol(av[0]);
1111 }
1112 break;
1113 case 'p': /* set pixel size*/
1114 if (*p) {
1115 pixel_size = atoi(p);
1116 while (*p && *p != ' ')
1117 p++;
1118 }
1119 else {
1120 av++; ac--;
1121 if (ac > 0)
1122 pixel_size = atoi(av[0]);
1123 }
1124 break;
1125 case 'c': /* set spaece between characters */
1126 {
1127 if (*p) {
1128 between_chr = atof(p);
1129 while (*p && *p != ' ')
1130 p++;
1131 }
1132 else {
1133 av++; ac--;
1134 if (ac > 0)
1135 between_chr = atof(av[0]);
1136 }
1137 break;
1138 }
1139 case 'd':
1140 dump_glyphs = 1;
1141 while (*p && *p != ' ')
1142 p++;
1143 break;
1144 case 'x':
1145 trimming = 1;
1146 while (*p && *p != ' ')
1147 p++;
1148 break;
1149 case 'X':
1150 if (*p) {
1151 hv_resolution = atoi(p);
1152 while (*p && *p != ' ')
1153 p++;
1154 }
1155 else {
1156 av++; ac--;
1157 if (ac > 0)
1158 hv_resolution = atoi(av[0]);
1159 }
1160 break;
1161 case 'r':
1162 if (*p) {
1163 between_row = atof(p);
1164 while (*p && *p != ' ')
1165 p++;
1166 }
1167 else {
1168 av++; ac--;
1169 if (ac > 0)
1170 between_row = atof(av[0]);
1171 }
1172 break;
1173 case 'T':
1174 if(*p == 'A') {
1175 if(*(++p)) {
1176 trim_ap = atoi(p);
1177 while (*p && *p != ' ')
1178 p++;
1179 }
1180 else {
1181 av++; ac--;
1182 if (ac > 0)
1183 trim_ap = atoi(av[0]);
1184 }
1185 break;
1186 }
1187 if(*p == 'D') {
1188 if(*(++p)) {
1189 trim_dp = atoi(p);
1190 while (*p && *p != ' ')
1191 p++;
1192 }
1193 else {
1194 av++; ac--;
1195 if (ac > 0)
1196 trim_dp = atoi(av[0]);
1197 }
1198 break;
1199 }
1200 if(*p == 'a') {
1201 if(*(++p)) {
1202 trim_aa = atoi(p);
1203 while (*p && *p != ' ')
1204 p++;
1205 }
1206 else {
1207 av++; ac--;
1208 if (ac > 0)
1209 trim_aa = atoi(av[0]);
1210 }
1211 break;
1212 }
1213 if(*p == 'd') {
1214 if(*(++p)) {
1215 trim_da = atoi(p);
1216
1217 }
1218 else {
1219 av++; ac--;
1220 if (ac > 0)
1221 trim_da = atoi(av[0]);
1222 }
1223 break;
1224 }
1225 fprintf(stderr, "Unknown option ignored: %s\n", p-1);
1226 while (*p && *p != ' ')
1227 p++;
1228 break;
1229 case 't': /* display ttc table */
1230 if (*p == 't') {
1231 pct = 1;
1232 while (*p && *p != ' ')
1233 p++;
1234 }
1235
1236 else if (*p == 'a') {
1237 flg_all_ttc = 1;
1238 while (*p && *p != ' ')
1239 p++;
1240 }
1241
1242 else if (*p) {
1243 ttc_index = atoi(p);
1244 while (*p && *p != ' ')
1245 p++;
1246 }
1247 else {
1248 av++; ac--;
1249 if (ac > 0)
1250 ttc_index = atoi(av[0]);
1251 }
1252 break;
1253 case 'w': /* Don't try to make digits equally wide */
1254 digits_equally_wide = 0;
1255 while (*p && *p != ' ')
1256 p++;
1257 break;
1258 case 'L': /* Light rendering algorithm */
1259 ft_load_opts |= FT_LOAD_TARGET_LIGHT;
1260 break;
1261
1262 default:
1263 fprintf(stderr, "Unknown option ignored: %s\n", p-1);
1264 while (*p && *p != ' ')
1265 p++;
1266 }
1267 ++av; --ac;
1268 }
1269 *pac = ac;
1270 *pav = av;
1271}
1272
1273
1274int main(int ac, char **av)
1275{
1276 int ret = 0;
1277
1278 ++av; --ac; /* skip av[0]*/
1279
1280 getopts(&ac, &av); /* read command line options*/
1281
1282 if (ac < 1)
1283 {
1284 usage();
1285 }
1286 if (oflag)
1287 {
1288 if (ac > 1)
1289 {
1290 usage();
1291 }
1292 }
1293
1294 if (limit_char < start_char)
1295 {
1296 usage();
1297 exit(0);
1298 }
1299
1300 while (pct && ac > 0)
1301 {
1302 print_ttc_table(av[0]);
1303 ++av; --ac;
1304 exit(0);
1305 }
1306
1307 while (ac > 0)
1308 {
1309 convttc(av[0]);
1310 ++av; --ac;
1311 }
1312
1313 exit(ret);
1314}
1315
1316
1317
1318/*
1319 * Trie node structure.
1320 */
1321typedef struct {
1322 unsigned short key; /* Key value. */
1323 unsigned short val; /* Data for the key. */
1324 unsigned long sibs; /* Offset of siblings from trie beginning. */
1325 unsigned long kids; /* Offset of children from trie beginning. */
1326} node_t;
1327
1328/*
1329 * The trie used for remapping codes.
1330 */
1331static node_t *nodes;
1332static unsigned long nodes_used = 0;
1333
1334int
1335otf2bdf_remap(unsigned short *code)
1336{
1337 unsigned long i, n, t;
1338 unsigned short c, codes[2];
1339
1340 /*
1341 * If no mapping table was loaded, then simply return the code.
1342 */
1343 if (nodes_used == 0)
1344 return 1;
1345
1346 c = *code;
1347 codes[0] = (c >> 8) & 0xff;
1348 codes[1] = c & 0xff;
1349
1350 for (i = n = 0; i < 2; i++) {
1351 t = nodes[n].kids;
1352 if (t == 0)
1353 return 0;
1354 for (; nodes[t].sibs && nodes[t].key != codes[i]; t = nodes[t].sibs);
1355 if (nodes[t].key != codes[i])
1356 return 0;
1357 n = t;
1358 }
1359
1360 *code = nodes[n].val;
1361 return 1;
1362}