1 /* ft2sswf.c - written by Alexis Wilke for Made to Order Software Corp. (c) 2002-2009 */
2
3 /*
4
5 Copyright (c) 2002-2009 Made to Order Software Corp.
6
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31
32 */
33
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <ctype.h>
40
41 #include <ft2build.h>
42 #include FT_FREETYPE_H
43
44 /* defines the wc_t type for the printf(3C) */
45 #include "sswf/libsswf-config.h"
46
47
48 #ifdef _MSVC
49 #define strcasecmp stricmp
50 // VC8 defines MB_CUR_MAX as a variable!
51 #ifndef MB_CUR_MAX
52 #define MB_CUR_MAX 64
53 //#elif !MB_CUR_MAX
54 //#undef MB_CUR_MAX
55 //#define MB_CUR_MAX 64
56 #endif
57 #endif
58
59
60 const char * progname = "ft2sswf"; /* default name of this tool */
61 const char * version = TO_STR(SSWF_VERSION); /* version of this tool */
62 const char * glyphs; /* glyhps to print out */
63 wchar_t * sorted_glyphs; /* the list of glyphs to print out - sorted and unique */
64 long errcnt; /* count errors, if 1 or more occurs, then exit with 1 */
65 long encoding; /* whether to print out the encoding (0, 1 or 2) */
66 long verbose; /* writes out what we're doing */
67 long output_control; /* if true, print out the control characters too */
68 long comment; /* whether comments are generated */
69 long include_null; /* by default skip any empty character (except the space) */
70 double factor; /* multiply all the points (positions) by this factor */
71 double advance; /* the default number of pixels to the advance to the next character */
72 FILE * output; /* the output file (default stdout) */
73 FT_Library library; /* the font library pointer */
74 FT_Encoding char_map_encoding; /* what character map to use to read the chars (default -1 -- i.e. use 1st entry available) */
75
76 struct option_to_char {
77 size_t length; /* total length so far */
78 int index; /* start at 0 */
79 const char * glyphs; /* the original string */
80 wchar_t letter; /* the last letter returned */
81 };
82
83 struct encoding_list {
84 const char * name;
85 FT_Encoding encoding;
86 };
87
88 struct encoding_list list_of_encodings[] = {
89 { "default", -1 },
90 { "none", ft_encoding_none },
91 { "symbol", ft_encoding_symbol },
92 { "unicode", ft_encoding_unicode },
93 { "latin 1", ft_encoding_latin_1 },
94 { "latin1", ft_encoding_latin_1 },
95 { "latin 2", ft_encoding_latin_2 },
96 { "latin2", ft_encoding_latin_2 },
97 { "japanese", ft_encoding_sjis },
98 { "sjis", ft_encoding_sjis },
99 { "gb2312", ft_encoding_gb2312 },
100 { "big 5", ft_encoding_big5 },
101 { "big5", ft_encoding_big5 },
102 { "wansung", ft_encoding_wansung },
103 { "johab", ft_encoding_johab },
104 { "adobe standard", ft_encoding_adobe_standard },
105 { "adobe-standard", ft_encoding_adobe_standard },
106 { "adobe std", ft_encoding_adobe_standard },
107 { "adobe-std", ft_encoding_adobe_standard },
108 { "adobe expert", ft_encoding_adobe_expert },
109 { "adobe-expert", ft_encoding_adobe_expert },
110 { "adobe custom", ft_encoding_adobe_custom },
111 { "adobe-custom", ft_encoding_adobe_custom },
112 { "apple roman", ft_encoding_apple_roman },
113 { "apple-roman", ft_encoding_apple_roman },
114 { "apple", ft_encoding_apple_roman }
115 };
116 #define MAX_ENCODINGS (sizeof(list_of_encodings) / sizeof(struct encoding_list))
117
118
encoding_to_name(FT_Encoding value,char * enc)119 const char *encoding_to_name(FT_Encoding value, char *enc)
120 {
121 struct encoding_list *l;
122 int i;
123
124 enc[0] = value >> 24;
125 enc[1] = value >> 16;
126 enc[2] = value >> 8;
127 enc[3] = value;
128 enc[4] = '\0';
129
130 l = list_of_encodings;
131 for(i = 0; i < MAX_ENCODINGS; i++, l++) {
132 if(value == l->encoding) {
133 return l->name;
134 }
135 }
136
137 return "(unknown at time of compilation)";
138 }
139
140
escape_char(const char ** s)141 wchar_t escape_char(const char **s)
142 {
143 const char *esc;
144 unsigned char c;
145 wchar_t r;
146
147 esc = *s;
148 c = *esc++;
149 if(c != '\\') {
150 *s = esc;
151 return c;
152 }
153 c = *esc++;
154 switch(c) {
155 case '\0':
156 /* special case of a backslash at the end of a string */
157 esc--;
158 r = '\0';
159 break;
160
161 case 'a':
162 r = '\a';
163 break;
164
165 case 'b':
166 r = '\b';
167 break;
168
169 case 'f':
170 r = '\f';
171 break;
172
173 case 'n':
174 r = '\n';
175 break;
176
177 case 'r':
178 r = '\r';
179 break;
180
181 case 't':
182 r = '\t';
183 break;
184
185 case 'v':
186 r = '\v';
187 break;
188
189 case 'x':
190 r = 0;
191 for(;;) {
192 if(*esc >= '0' && *esc <= '9') {
193 r = r * 16 + (*esc & 15);
194 }
195 else if(*esc >= 'a' && *esc <= 'f') {
196 r = r * 16 + (*esc - 'a' + 10);
197 }
198 else if(*esc >= 'A' && *esc <= 'F') {
199 r = r * 16 + (*esc - 'A' + 10);
200 }
201 else {
202 break;
203 }
204 esc++;
205 }
206 break;
207
208 case '0':
209 case '1':
210 case '2':
211 case '3':
212 case '4':
213 case '5':
214 case '6':
215 case '7':
216 r = c & 7;
217 while(*esc >= '0' && *esc <= '7') {
218 r = r * 8 + (*esc & 7);
219 esc++;
220 }
221 break;
222
223 default:
224 /* copy any other character as is (including '\\') */
225 r = c;
226 break;
227
228 }
229
230 *s = esc;
231
232 return r;
233 }
234
235
next_char(struct option_to_char * o2c)236 wchar_t next_char(struct option_to_char *o2c)
237 {
238 const char *g, *save;
239 wchar_t c1, c2, c3;
240
241 /* here we determine the next character
242 * note that the o2c->index isn't an index from
243 * the start but instead in the current o2c->glyphs
244 * also the oc2->glyphs pointer is modified as we go
245 * this makes things much faster
246 */
247
248 g = o2c->glyphs;
249
250 /* end of string? nothing to do here! */
251 if(g == NULL || *g == '\0') {
252 o2c->letter = L'\0';
253 return L'\0';
254 }
255
256 o2c->length++;
257
258 /* determine the 1st character */
259 c1 = escape_char(&g);
260 save = g;
261
262 c2 = escape_char(&g);
263 if(c2 != L'-') {
264 /* no range, return c1 and save g after we read c1 */
265 o2c->glyphs = save;
266 o2c->index = 0;
267 o2c->letter = c1;
268 return c1;
269 }
270
271 c3 = escape_char(&g);
272 if(c1 > c3) {
273 /* swap so it is ordered */
274 c2 = c1;
275 c1 = c3;
276 c3 = c2;
277 }
278
279 c2 = c1 + o2c->index;
280
281 if(o2c->index + 1 > c3 - c1) {
282 /* Ha! We are done - next time read the following character */
283 o2c->glyphs = g;
284 o2c->index = 0;
285 }
286 else {
287 o2c->index++;
288 }
289
290 o2c->letter = c2;
291 return c2;
292 }
293
294
295
sort_glyphs(void)296 void sort_glyphs(void)
297 {
298 wchar_t wc, swap, *d;
299 struct option_to_char o2c;
300
301 /* first we sort the glyphs */
302 o2c.length = 0;
303 o2c.index = 0;
304 o2c.glyphs = glyphs;
305 o2c.letter = 0;
306
307 /* define the total length including duplicates */
308 while((wc = next_char(&o2c)) != L'\0');
309
310 /* allocate the destination */
311 if(sorted_glyphs != NULL) {
312 /* first free previous instance */
313 free(sorted_glyphs);
314 }
315 /*
316 * Note: this may allocate a HUGE buffer, the only
317 * way around would be to regenerate the ranges
318 * in the output string... We will see with usage
319 * whether this would be necessary or not.
320 */
321 sorted_glyphs = malloc((o2c.length + 1) * sizeof(wchar_t));
322 if(sorted_glyphs == NULL) {
323 fprintf(stderr, "ERROR: out of memory trying to allocate a buffer to sort glyphs.\n");
324 exit(1);
325 }
326
327 /* reset the o2c parameters which we use next */
328 o2c.index = 0;
329 o2c.glyphs = glyphs;
330 *sorted_glyphs = L'\0';
331 while((wc = next_char(&o2c)) != L'\0') {
332 d = sorted_glyphs;
333 while(*d != '\0') {
334 if(*d == wc) {
335 goto skip_duplicate;
336 }
337 if(*d > wc) {
338 break;
339 }
340 d++;
341 }
342 /* insert this character */
343 wc = o2c.letter;
344 do {
345 swap = *d;
346 *d = wc;
347 d++;
348 wc = swap;
349 } while(wc != '\0');
350 *d = '\0';
351 skip_duplicate:;
352 }
353 }
354
355
356
357 struct point {
358 double x;
359 double y;
360 };
361
362 struct entry {
363 long count; /* the number of points */
364 long points_index; /* index to the first point in pts array */
365 };
366
367 struct array {
368 long max_points; /* total size of pts */
369 long idx_points; /* next available pts structure */
370 struct point *points;
371
372 long max_entries; /* total size of entries */
373 long idx_entries; /* next available entry */
374 struct entry *entries;
375 };
376
377
init_array(struct array * array,long points)378 void init_array(struct array *array, long points)
379 {
380 memset(array, 0, sizeof(array));
381
382 array->max_points = points * 2;
383 array->idx_points = 0;
384 array->points = malloc(array->max_points * sizeof(struct point));
385
386 array->max_entries = 100;
387 array->idx_entries = 0;
388 array->entries = malloc(array->max_entries * sizeof(struct entry));
389
390 if(array->points == NULL || array->entries == NULL) {
391 fprintf(stderr, "ERROR: out of memory trying to allocate an array for a glyph outline\n");
392 exit(1);
393 }
394 }
395
396
alloc_point(struct array * array,long x,long y)397 void alloc_point(struct array *array, long x, long y)
398 {
399 struct point *p;
400
401 if(array->idx_points >= array->max_points) {
402 /* enlarge buffer */
403 array->max_points += 100;
404 array->points = realloc(array->points, array->max_points * sizeof(struct point));
405 if(array->points == NULL) {
406 fprintf(stderr, "ERROR: out of memory trying to enlarge an array of points for a glyph outline\n");
407 exit(1);
408 }
409 }
410
411 /* one more point in this set of entries */
412 array->entries[array->idx_entries - 1].count++;
413
414 p = array->points + array->idx_points++;
415 p->x = x;
416 p->y = y;
417 }
418
419
alloc_entry(struct array * array)420 void alloc_entry(struct array *array)
421 {
422 long i;
423
424 if(array->idx_entries >= array->max_entries) {
425 /* enlarge buffer */
426 array->max_entries += 100;
427 array->entries = realloc(array->entries, array->max_entries * sizeof(struct entry));
428 if(array->entries == NULL) {
429 fprintf(stderr, "ERROR: out of memory trying to enlarge an array of entires for a glyph outline\n");
430 exit(1);
431 }
432 }
433
434 i = array->idx_entries++;
435
436 array->entries[i].count = 0;
437 array->entries[i].points_index = array->idx_points;
438 }
439
440
441
442 /*
443 * The inputs are u and points
444 * u will vary from 0.0 (start point) to 1.0 (end point)
445 * the points array must point to 4 points - 2 anchors and 2 control points
446 * (start anchor, ctrl1, ctrl2, and end anchor)
447 *
448 * This function was simplified as much as possible (as far as I can tell)
449 * and thus it doesn't look clear at, does it?
450 *
451 * The computation is as follow:
452 *
453 * R = (U . B) / 6 . P
454 *
455 * Where the matrix U is defined as:
456 *
457 * | u ** 3 |
458 * U = | u ** 2 |
459 * | u |
460 * | 1 |
461 *
462 * The matrix B is defined as:
463 *
464 * | -1 3 -3 1 |
465 * B = | 3 -6 3 0 |
466 * | -3 0 3 0 |
467 * | 1 4 1 0 |
468 *
469 * And P is defined from the input points - this works in 3 dimensional
470 * space, and since we only have an X and Y set of coordinates, we assume
471 * Z is always zero.
472 *
473 * | x1 y1 0 1 |
474 * P = | x2 y2 0 1 |
475 * | x3 y3 0 1 |
476 * | x4 y4 0 1 |
477 *
478 * R is the result of the products.
479 *
480 * Note: you can reuse this function with a Quadratic bezier curve by
481 * setting the P matrix as follow (repeat the control point twice):
482 *
483 * | x1 y1 0 1 |
484 * P = | x2 y2 0 1 |
485 * | x2 y2 0 1 |
486 * | x3 y3 0 1 |
487 *
488 */
bspline_point_at_u(double u,const struct point * points,struct point * result)489 void bspline_point_at_u(double u, const struct point *points, struct point *result)
490 {
491 double u2, u3, u3_div_6, r0, r1, r2;
492
493 #define u1 u
494 #define r3 u3_div_6
495
496 /* u2 - u1 square, u3 - u1 cube */
497 u3_div_6 = (u3 = (u2 = u1 * u1) * u1) / 6.0;
498
499 r0 = 0.5 * (u2 - u1) - u3_div_6 + 1.0 / 6.0;
500 r1 = u3 * 0.5 - u2 + 2.0 / 3.0;
501 r2 = 0.5 * (u2 - u3 + u1) + 1.0 / 6.0;
502
503 result->x = r0 * points[0].x +
504 r1 * points[1].x +
505 r2 * points[2].x +
506 r3 * points[3].x;
507
508 result->y = r0 * points[0].y +
509 r1 * points[1].y +
510 r2 * points[2].y +
511 r3 * points[3].y;
512
513 #undef u1
514 #undef r3
515 }
516
517
close_entry(struct array * array)518 void close_entry(struct array *array)
519 {
520 long i, idx, index, max;
521 struct point *points, r, p;
522
523 i = array->idx_entries - 1;
524
525 max = array->entries[i].count;
526 if(max <= 3) {
527 /*
528 * a line or a curve which already is a quadratic curve
529 * doesn't require any changes
530 */
531 return;
532 }
533
534 /* in this case we have a "complex" bezier curve which requires simplification */
535 points = malloc(max * sizeof(struct point));
536 if(points == NULL) {
537 fprintf(stderr, "ERROR: out of memory in trying to allocate a buffer to copy a the points of a bezier curve.\n");
538 exit(1);
539 }
540
541 /* copy the curve in a temp. buffer, then free the entry and its points */
542 index = array->entries[i].points_index;
543 memcpy(points, array->points + index, max * sizeof(struct point));
544 array->idx_points = index;
545 array->idx_entries = i; /* we will re-allocate this entry later */
546
547 /* now we compute the new curve with only quadratic bezier curves */
548
549 /*
550 * The algorithm supports any degree of B-spline curves and transforms
551 * them in only quadratic Bezier curves. At this time the precision is
552 * no good!
553 */
554
555 p = points[0];
556 max -= 2;
557 for(idx = 1; idx < max; idx++) {
558 /* compute the middle point -- this is a really bad approximation at times! */
559 bspline_point_at_u(0.5, points + idx - 1, &r);
560
561 /* TODO: before to save that we should check to see if the precision is
562 * good enough (it usually is fairly close but at times you can see that
563 * the curve isn't that good)
564 */
565 alloc_entry(array);
566 alloc_point(array, (long) p.x, (long) p.y);
567 alloc_point(array, (long) points[idx].x, (long) points[idx].y);
568 alloc_point(array, (long) r.x, (long) r.y);
569
570 p = r;
571 }
572
573 alloc_entry(array);
574 alloc_point(array, (long) r.x, (long) r.y);
575 alloc_point(array, (long) points[idx].x, (long) points[idx].y);
576 alloc_point(array, (long) points[idx + 1].x, (long) points[idx + 1].y);
577
578 free(points);
579 }
580
581
add_point(struct array * array,double x,double y,long ctrl)582 void add_point(struct array *array, double x, double y, long ctrl)
583 {
584 long i;
585
586 i = array->idx_entries;
587 if(ctrl) {
588 if(i <= 0) {
589 /* changed from ERROR to WARNING proposed by Steve Crook - Sept 2003 */
590 fprintf(stderr, "WARNING: found a glyph which starts with a control point.\n");
591 printf("\n/* NOTE: this glyph starts with a control point */\n");
592 /* exit(1); */
593 alloc_entry(array);
594 }
595 alloc_point(array, (long) x, (long) y);
596 }
597 else {
598 if(i > 0) {
599 /* "close" this entry with this new point then "open" a new entry */
600 alloc_point(array, (long) x, (long) y);
601 close_entry(array);
602 }
603 alloc_entry(array);
604 alloc_point(array, (long) x, (long) y);
605 }
606 }
607
608
empty_glyph(FT_Face face,wchar_t wc)609 int empty_glyph(FT_Face face, wchar_t wc)
610 {
611 return include_null == 0 && wc != ' '
612 && face->glyph->outline.n_points == 0;
613 }
614
615
print_glyph(FT_Face face,wchar_t wc)616 void print_glyph(FT_Face face, wchar_t wc)
617 {
618 char buf[256], *s, *flg;
619 int c, i, maxcnt, maxpts, done, sx, sy;
620 FT_Vector *pts;
621 struct array array;
622 struct point *points;
623
624 /* skip empty glyphs as required */
625 if(empty_glyph(face, wc)) {
626 return;
627 }
628
629 /* give the name of this letter in a comment */
630 s = buf;
631 *s++ = '\'';
632 if(wc < ' ') {
633 *s++ = '^';
634 *s++ = wc + '@';
635 }
636 else if(wc < 0x7F) {
637 *s++ = (char) wc;
638 }
639 else if(wc == 0x7F) {
640 *s++ = '^';
641 *s++ = '?';
642 }
643 else if(wc < 0xA0) {
644 *s++ = '?';
645 *s++ = wc - 0x40;
646 }
647 /* This only works if you're in ISO-8859-1.
648 else if(wc < 0xFF) {
649 *s++ = (char) wc;
650 }
651 */
652 else {
653 s += sprintf(s, "\\x%lX", (unsigned long) wc);
654 }
655 *s++ = '\'';
656 *s = '\0';
657
658 if(face->glyph->format != ft_glyph_format_outline) {
659 fprintf(stderr, "ERROR: glyph format for \"%s\" not supported (only outlines are supported).\n", buf);
660 return;
661 }
662
663 /*
664 * the pts and flg pointers are always increased in the following loop
665 * and never reset
666 */
667 pts = face->glyph->outline.points;
668 flg = face->glyph->outline.tags;
669 init_array(&array, face->glyph->outline.n_points);
670 done = 0;
671 maxcnt = face->glyph->outline.n_contours;
672 fprintf(output, "\t\t\t\t/* Glyph: %s */\n", buf);
673 fprintf(output, "\t\t\t\tglyph \"c_%04lX\" {\n", (unsigned long) wc);
674 fprintf(output, "\t\t\t\t\tdefinitions.fill_glyph;\n");
675
676 /* define the set of points */
677 for(c = 0; c < maxcnt; c++) {
678
679 /*
680 * get the number of points in this entry
681 * then convert the font points in an array
682 * that we understand; finally we save the
683 * result in the output
684 */
685 array.idx_points = 0; /* reset the counters */
686 array.idx_entries = 0;
687 maxpts = face->glyph->outline.contours[c] + 1 - done;
688 done += maxpts;
689 sx = pts->x;
690 sy = pts->y;
691 while(maxpts > 0) {
692 maxpts--;
693 add_point(&array, (double) (pts->x - face->bbox.xMin) / factor, (double) (face->bbox.yMax - pts->y) / factor, (*flg & 1) == 0);
694 pts++;
695 flg++;
696 }
697 /* we now need to close the shape with a last call */
698 alloc_point(&array, (long) ((double) (sx - face->bbox.xMin) / factor), (long) ((double) (face->bbox.yMax - sy) / factor));
699 close_entry(&array);
700
701 /*
702 * We have to use the face->bbox.yMax to invert the Y coordinates because the
703 * descender may not include the entire font (it can be smaller). The descender
704 * + ascender should be used to draw multiple lines of text, but can otherwise
705 * be ignored.
706 printf("Ascender %d descender %d - bbox.yMin %ld, bbox.yMax %ld\n",
707 face->ascender, face->descender, face->bbox.yMin, face->bbox.yMax);
708 */
709 /*
710 * at this point any curve which wasn't a quadratic bezier curve
711 * was already reduced
712 */
713
714 fprintf(output, "\t\t\t\t\tmove: %g, %g;\n", array.points[0].x, array.points[0].y);
715
716 fprintf(output, "\t\t\t\t\tpoints {");
717 maxpts = array.idx_entries;
718 for(i = 0; i < maxpts; i++) {
719 /* once we reach here we have only two types of entries: 2 points or 3 points */
720 points = array.points + array.entries[i].points_index;
721 if(array.entries[i].count == 2) {
722 fprintf(output, " %g, %g;",
723 points[1].x, points[1].y);
724 }
725 else {
726 fprintf(output, " %g, %g, %g, %g;",
727 points[1].x, points[1].y,
728 points[2].x, points[2].y);
729 }
730 }
731 fprintf(output, " };\n");
732 }
733
734 /* save the full bounding box (when SSWF knows how to compute this, we should remove it from here) */
735 fprintf(output, "\t\t\t\t\trect { %d, %ld, %ld, %ld };\n",
736 0,
737 -face->bbox.yMax * 1024 / face->units_per_EM,
738 face->bbox.xMax - face->bbox.xMin,
739 -face->bbox.yMin * 1024 / face->units_per_EM);
740 fprintf(output, "\t\t\t\t};\n");
741 }
742
743
ref_glyph(FT_Face face,FT_ULong wc,double adv)744 void ref_glyph(FT_Face face, FT_ULong wc, double adv)
745 {
746 double width;
747
748 /* skip empty glyphs as required */
749 if(empty_glyph(face, (wchar_t) wc)) {
750 return;
751 }
752
753 fprintf(output, "\t\t\t\t\tchar: \"");
754 if(wc >= ' ' && wc <= 0x7E) {
755 if(wc == '"' || wc == '\\') {
756 fprintf(output, "\\%c", (unsigned char) wc);
757 }
758 else {
759 fprintf(output, "%c", (unsigned char) wc);
760 }
761 }
762 else {
763 fprintf(output, "\\\\x%04lX", wc);
764 }
765 fprintf(output, "\", c_%04lX", (unsigned long) wc);
766
767 width = (double) face->glyph->advance.x / factor;
768 if(width != adv) {
769 fprintf(output, ", %g", width);
770 }
771 fprintf(output, ";\n");
772 }
773
774
font_to_sswf(FT_Face face,const char * filename)775 void font_to_sswf(FT_Face face, const char *filename)
776 {
777 FT_Error error;
778 FT_UInt gindex;
779 FT_ULong wc;
780 int c, len, all;
781 double adv;
782 char *name, *d, enc[5];
783 #ifdef _MSVC
784 char *mbs;
785 #else
786 char mbs[MB_CUR_MAX];
787 #endif
788 const char *s, *encoding_name;
789 const wchar_t *ws;
790
791 /* fix the name of the font so we can use it
792 * in SSWF scripts without the $( ... ) operator
793 */
794 len = strlen(face->family_name);
795 name = malloc(len + 2);
796 if(name == NULL) {
797 fprintf(stderr, "ERROR: out of memory trying to allocate a buffer for the font name.\n");
798 exit(1);
799 }
800 s = face->family_name;
801 d = name;
802 /* can't start with a digit or a period */
803 if((*s >= '0' && *s <= '9') || *s == '.') {
804 *d++ = '_';
805 }
806 while(*s != '\0') {
807 if(strchr(" !@#$%^&*()-+={}[]\\|:;\"'`<>,./?~", *s) == NULL) {
808 *d = *s;
809 }
810 else if(d == name || d[-1] != '_') {
811 /* we try to avoid having multiple '_' in a row */
812 *d = '_';
813 }
814 d++;
815 s++;
816 }
817 *d = '\0';
818
819 /* the user wants to know the encodings only */
820 if(encoding) {
821 fprintf(output, "Family: \"%s\"\n", name);
822 for(c = 0; c < face->num_charmaps; c++) {
823 encoding_name = encoding_to_name(face->charmaps[c]->encoding, enc);
824 fprintf(output, "\t%s - %s\n", enc, encoding_name);
825 }
826 free(name);
827 return;
828 }
829
830 if(face->num_charmaps <= 0) {
831 fprintf(stderr, "ERROR: font \"%s\" doesn't have any encoding information.\n", name);
832 free(name);
833 return;
834 }
835
836 /* select the encoding now */
837 if(char_map_encoding == ft_encoding_none || char_map_encoding == (FT_Encoding) -1) {
838 /* use 1st available encoding */
839 FT_Set_Charmap(face, face->charmaps[0]);
840 }
841 else {
842 error = FT_Select_Charmap(face, char_map_encoding);
843 if(error) {
844 encoding_name = encoding_to_name(char_map_encoding, enc);
845 fprintf(stderr, "ERROR: can't find specified encoding (%s/%s) in this font (%s).\n",
846 enc, encoding_name, name);
847 free(name);
848 return;
849 }
850 }
851
852 /*
853 * The file is actually only in ASCII, but defining the encoding as
854 * ISO-8859-1 is better because then the parser doesn't do any
855 * translation (the parser isn't smart enough to just understand
856 * ASCII...)
857 */
858 fprintf(output, "/* encoding=\"iso8859-1\" */\n");
859 fprintf(output, "block sswf {\n");
860 fprintf(output, "\tblock fnt {\n");
861 fprintf(output, "\t\tlist \"%s\" {\n", name);
862
863 /* the following is really only so we can reference a fill - the color isn't used */
864 fprintf(output, "\t\t\tlist definitions {\n");
865 fprintf(output, "\t\t\t\tfill style \"fill_glyph\" { color { 0, 0, 0 } };\n");
866 fprintf(output, "\t\t\t};\n");
867 fprintf(output, "\t\t\tlist insert {\n");
868
869
870
871 // Ask for the font to be setup according to the Flash
872 // movies specifications (i.e. an EM of 1024x1024). The
873 // DPI isn't specified so we try for 75x75 since that's
874 // the usual to draw on a screen device.
875 FT_Set_Char_Size(face, 1024 << 6, 1024 << 6, 75, 75);
876 //FT_Set_Pixel_Sizes(face, 1024, 1024);
877
878 // in the following we first generate the list of glyphs
879 // note that we use the 'glyphs' variable as defined by
880 // the end user to know which glyphs to print out; note
881 // however that the special case "*" means all in which
882 // case we go through the entire map
883 all = glyphs == NULL || strcmp(glyphs, "*") == 0;
884 if(all) {
885 if(comment != 0) {
886 fprintf(output, "\t\t\t\t/* Extract all the available characters */\n");
887 }
888 wc = FT_Get_First_Char(face, &gindex);
889 while(gindex != 0) {
890 /*
891 * skip ^@ at all times - it doesn't work well in C strings anyway
892 * also, keep control characters only if requested to do so
893 */
894 if(wc != 0 && (output_control || wc >= ' ')) {
895 error = FT_Load_Glyph(face, gindex, FT_LOAD_NO_BITMAP);
896 if(error) {
897 fprintf(stderr, "ERROR: couldn't load glyph 0x%04X from file \"%s\" (Error: %d).\n", (int) wc, filename, error);
898 }
899 else if(empty_glyph(face, (wchar_t) wc)) {
900 fprintf(stderr, "WARNING: the requested character 0x%04X from file \"%s\" is empty.\n", (int) wc, filename);
901 }
902 else {
903 print_glyph(face, (wchar_t) wc);
904 }
905 }
906 wc = FT_Get_Next_Char(face, wc, &gindex);
907 }
908 }
909 else {
910 if(comment != 0) {
911 /* TODO: the 2nd string needs control characters to be remapped */
912 fprintf(output, "\t\t\t\t/* Extracted characters: \"%s\" (%ls) */\n", glyphs, sorted_glyphs);
913 }
914 ws = sorted_glyphs;
915 while(*ws != L'\0') {
916 wc = *ws;
917 error = FT_Load_Char(face, wc, FT_LOAD_NO_BITMAP);
918 len = wctomb(NULL, wc);
919 #ifdef _MSVC
920 mbs = malloc(len + 1);
921 #endif
922 mbs[wctomb(mbs, wc)] = '\0';
923 if(error) {
924 fprintf(stderr, "ERROR: couldn't load char #%s (0x%04X) from file \"%s\" (Error: %d).\n", mbs, (int) wc, filename, error);
925 }
926 else if(empty_glyph(face, (wchar_t) wc)) {
927 fprintf(stderr, "WARNING: the requested character %s (0x%04X) from file \"%s\" is empty.\n", mbs, (int) wc, filename);
928 }
929 else {
930 print_glyph(face, (wchar_t) wc);
931 }
932 #ifdef _MSVC
933 free(mbs);
934 #endif
935 ws++;
936 }
937 }
938
939 fprintf(output, "\t\t\t\tfont \"fnt\" {\n");
940 fprintf(output, "\t\t\t\t\t\"%s\";\n", face->family_name);
941
942 /* try to determine the width of the space character */
943 adv = advance;
944 error = FT_Load_Char(face, ' ', FT_LOAD_NO_BITMAP);
945 if(error == 0) {
946 fprintf(output, "\t\t\t\t\tspace: %g;\n", (double) face->glyph->advance.x / factor);
947 if(advance == 0.0) {
948 /* use the space advance as the default when user didn't define one */
949 /* TODO: once we have a list of all the glyphs advance then we could
950 * compute the one which is used the most and thus will be useful
951 * to declare here
952 */
953 adv = (double) face->glyph->advance.x / factor;
954 }
955 }
956 if(adv != 0.0) {
957 fprintf(output, "\t\t\t\t\tadvance: %g;\n", adv);
958 }
959 fprintf(output, "\t\t\t\t\tlayout: %d, %ld, %d; // Original units per EM was %u\n",
960 face->ascender * 1024 / face->units_per_EM,
961 labs(face->descender) * 1024 / face->units_per_EM, /* the FT_... doc says it should be positive... but it isn't! */
962 face->height * 1024 / face->units_per_EM,
963 face->units_per_EM);
964
965 switch(face->charmap->encoding) {
966 case ft_encoding_unicode:
967 fprintf(output, "\t\t\t\t\ttype: \"unicode\"");
968 break;
969
970 case ft_encoding_sjis:
971 fprintf(output, "\t\t\t\t\ttype: \"shiftjis\"");
972 break;
973
974 default:
975 fprintf(output, "\t\t\t\t\ttype: \"ascii\"");
976 break;
977
978 }
979 if(face->style_flags & FT_STYLE_FLAG_BOLD) {
980 fprintf(output, ", \"bold\"");
981 }
982 if(face->style_flags & FT_STYLE_FLAG_ITALIC) {
983 fprintf(output, ", \"italic\"");
984 }
985 fprintf(output, ";\n");
986
987 if(all) {
988 wc = FT_Get_First_Char(face, &gindex);
989 while(gindex != 0) {
990 if(wc != 0 && (output_control || wc >= ' ')) {
991 error = FT_Load_Glyph(face, gindex, FT_LOAD_NO_BITMAP);
992 if(error == 0 && !empty_glyph(face, (wchar_t) wc)) {
993 ref_glyph(face, wc, advance);
994 }
995 }
996 wc = FT_Get_Next_Char(face, wc, &gindex);
997 }
998 }
999 else {
1000 ws = sorted_glyphs;
1001 while(*ws != L'\0') {
1002 wc = *ws;
1003 error = FT_Load_Char(face, wc, FT_LOAD_NO_BITMAP);
1004 if(error == 0 && !empty_glyph(face, (wchar_t) wc)) {
1005 ref_glyph(face, wc, advance);
1006 }
1007 ws++;
1008 }
1009 }
1010
1011
1012
1013 fprintf(output, "\t\t\t\t};\n");
1014
1015 fprintf(output, "\t\t\t} px;\n"); /* closes the list \"font name\" ... */
1016 fprintf(output, "\t\t};\n"); /* closes the list \"font name\" ... */
1017 fprintf(output, "\t};\n");
1018 fprintf(output, "};\n");
1019
1020 free(name);
1021 }
1022
1023
1024
read_stdin(size_t * size)1025 FT_Byte *read_stdin(size_t *size)
1026 {
1027 int c, left;
1028 size_t max;
1029 FT_Byte *buf, *s;
1030
1031 buf = malloc(1024);
1032 if(buf == NULL) {
1033 fprintf(stderr, "ERROR: can't allocate a memory buffer for the stdin file.\n");
1034 exit(1);
1035 }
1036 max = 1024;
1037 left = 1024;
1038 s = buf;
1039 while((c = getchar()) != EOF) {
1040 if(left <= 0) {
1041 max += 1024;
1042 buf = realloc(buf, max);
1043 if(buf == NULL) {
1044 fprintf(stderr, "ERROR: can't allocate a memory buffer for the stdin file.\n");
1045 exit(1);
1046 }
1047 left = 1024;
1048 s = buf + max - left;
1049 }
1050 *s++ = c;
1051 left--;
1052 }
1053
1054 *size = max - left;
1055
1056 return buf;
1057 }
1058
1059
run_font(const char * filename)1060 void run_font(const char *filename)
1061 {
1062 FT_Error error;
1063 FT_Face face;
1064 size_t size;
1065 FT_Byte *font_buffer;
1066
1067 if(strcmp(filename, "-") == 0) {
1068 /* we have to read the stdin file instead */
1069 if(verbose != 0) {
1070 fprintf(stderr, "INFO: reading the standard input.\n");
1071 }
1072 font_buffer = read_stdin(&size);
1073 error = FT_New_Memory_Face(library, font_buffer, size, 0, &face);
1074 if(error) {
1075 fprintf(stderr, "ERROR: the standard input doesn't represent a valid font.\n");
1076 errcnt++;
1077 free(font_buffer);
1078 return;
1079 }
1080 font_to_sswf(face, filename);
1081 error = FT_Done_Face(face);
1082 if(error) {
1083 fprintf(stderr, "WARNING: the standard input font face generated an error on closure.\n");
1084 }
1085 free(font_buffer);
1086 }
1087 else {
1088 if(verbose != 0) {
1089 fprintf(stderr, "INFO: reading the font from file \"%s\".\n", filename);
1090 }
1091 error = FT_New_Face(library, filename, 0, &face);
1092 if(error) {
1093 fprintf(stderr, "ERROR: the file \"%s\" can't either be open, read or is an invalid font file.\n", filename);
1094 errcnt++;
1095 return;
1096 }
1097 font_to_sswf(face, filename);
1098 error = FT_Done_Face(face);
1099 if(error) {
1100 fprintf(stderr, "WARNING: the font face read from the file \"%s\" generated an error on closure.\n", filename);
1101 }
1102 }
1103 }
1104
1105
show_encodings(void)1106 void show_encodings(void)
1107 {
1108 int i, j;
1109 char enc[5];
1110
1111 enc[4] = '\0';
1112 for(i = 0; i < MAX_ENCODINGS; i++) {
1113 enc[0] = list_of_encodings[i].encoding >> 24;
1114 enc[1] = list_of_encodings[i].encoding >> 16;
1115 enc[2] = list_of_encodings[i].encoding >> 8;
1116 enc[3] = list_of_encodings[i].encoding;
1117 for(j = 0; j < 4; j++) {
1118 if(enc[j] == (char) 0xFF) {
1119 enc[j] = '?';
1120 }
1121 else if(enc[j] == (char) 0) {
1122 enc[j] = ' ';
1123 }
1124 else if(enc[j] < ' ' || enc[j] >= 0x7F) {
1125 enc[j] = '.';
1126 }
1127 }
1128 printf("%5d. %s - %s\n", i + 1, enc, list_of_encodings[i].name);
1129 }
1130
1131 exit(1);
1132 }
1133
1134
string_to_encoding(const char * str)1135 FT_Encoding string_to_encoding(const char *str)
1136 {
1137 struct encoding_list *l;
1138 int i;
1139 char *s, buf[256];
1140 FT_Encoding value;
1141
1142 /* first we clip the string (remove starting and ending spaces) */
1143 while(isspace((unsigned char) *str)) {
1144 str++;
1145 }
1146 strncpy(buf, str, sizeof(buf) - 1);
1147 buf[sizeof(buf) - 1] = '\0';
1148 s = buf + strlen(buf);
1149 while(s > buf && isspace((unsigned char) s[-1])) {
1150 s--;
1151 }
1152 *s = '\0';
1153
1154 /* people may give us a name or directly an encoding */
1155 if(s - buf <= 4) {
1156 value = 0;
1157 s = buf;
1158 for(i = 0; i < 4; i++) {
1159 if(*s == '\0') {
1160 /* fill with spaces */
1161 value = (value << 8) + ' ';
1162 }
1163 else {
1164 value = (value << 8) + *s;
1165 s++;
1166 }
1167 }
1168 }
1169 else {
1170 /* no encoding equals -1 -- so use -2 as a "bad" encoding */
1171 value = (FT_Encoding) -2;
1172 }
1173
1174 l = list_of_encodings;
1175 for(i = 0; i < MAX_ENCODINGS; i++) {
1176 if(strcasecmp(str, l[i].name) == 0 || l[i].encoding == value) {
1177 return l[i].encoding;
1178 }
1179 }
1180
1181 fprintf(stderr, "ERROR: can't determine what encoding \"%s\" is.\n", str);
1182
1183 return -1;
1184 }
1185
1186
usage(const char * cmd)1187 void usage(const char *cmd)
1188 {
1189 fprintf(stderr, "%s V%s -- Written by Alexis Wilke for Made to Order Software Corp. (c) 2002-2009\n", progname, version);
1190 fprintf(stderr, "Usage: %s [-opt] <font-file> ...\n", cmd);
1191 fprintf(stderr, "\n");
1192 fprintf(stderr, "<font-file> can be \"-\" to process the standard input as a font.\n");
1193 fprintf(stderr, "\n");
1194 fprintf(stderr, "The special option \"--\" can be used to stop parsing options and take\n");
1195 fprintf(stderr, "all the other parameters as font filenames\n");
1196 fprintf(stderr, "\n");
1197 fprintf(stderr, "-opt can be one or more of the following:\n");
1198 fprintf(stderr, "\n");
1199 fprintf(stderr, " NOTE: options given after a given font-file don't apply to that\n");
1200 fprintf(stderr, " font-file but only the following ones\n");
1201 fprintf(stderr, "\n");
1202 fprintf(stderr, " --advance(=| )<value>\n");
1203 fprintf(stderr, " specify the default number of pixels to use to advanced\n");
1204 fprintf(stderr, " to the next character.\n");
1205 fprintf(stderr, " -c[0|1] print comments in output file\n");
1206 fprintf(stderr, " --control print out the control characters (otherwise starts at\n");
1207 fprintf(stderr, " 0x20 -- space)\n");
1208 fprintf(stderr, " -e[0|1|2] output the encodings only\n");
1209 fprintf(stderr, " -f[ ]<factor> multiply all of the font coordinates by factor\n");
1210 fprintf(stderr, " (a floating-point value)\n");
1211 fprintf(stderr, " -g[ ]<glyphs> or --glyphs(=| )[<glyphs>]\n");
1212 fprintf(stderr, " list of characters to extract from the font (ISO-8859-1 only)\n");
1213 fprintf(stderr, " -h or --help prints out this help screen\n");
1214 fprintf(stderr, " -m[ ]<name> or --map(=| )[<name>]\n");
1215 fprintf(stderr, " specify which encoding map to use; use -e to have a list\n");
1216 fprintf(stderr, " of available encodings in a given font; by default, use\n");
1217 fprintf(stderr, " the 1st entry\n");
1218 fprintf(stderr, " -n[0|1] or --include-null or --no-null\n");
1219 fprintf(stderr, " include all characters even when empty\n");
1220 fprintf(stderr, " -o[ ][<filename>] or --output(=| )[<filename>]\n");
1221 fprintf(stderr, " specify a filename where the result is written; the\n");
1222 fprintf(stderr, " default is stdout\n");
1223 fprintf(stderr, " -q quiet, i.e. no verbosity (default)\n");
1224 fprintf(stderr, " -v increase verbosity by one\n");
1225 fprintf(stderr, " --version print out the version of this tool and exit\n");
1226 exit(1);
1227 }
1228
run_command_line(int argc,char * argv[])1229 void run_command_line(int argc, char *argv[])
1230 {
1231 int i, j, len, moreoptions;
1232 char *s, *output_filename;
1233
1234 // define the current program name
1235 len = strlen(argv[0]);
1236 s = argv[0] + len;
1237 while(s > argv[0]) {
1238 if(s[-1] == '/') {
1239 break;
1240 }
1241 s--;
1242 }
1243 progname = s;
1244
1245 output = stdout; /* the default output */
1246 char_map_encoding = (FT_Encoding) -1; /* use the 1st entry by default */
1247 factor = 64.0;
1248
1249 moreoptions = 1;
1250 for(i = 1; i < argc; i++) {
1251 if(argv[i][0] == '-' && moreoptions != 0) {
1252 if(argv[i][1] == '-') {
1253 /* full word options */
1254 if(argv[i][2] == '\0') {
1255 moreoptions = 0;
1256 }
1257 else if(strncmp(argv[i] + 2, "advance", 7) == 0) {
1258 advance = 0.0;
1259 if(argv[i][2 + 7] == '=') {
1260 /* name stuck with the option */
1261 advance = strtod(argv[i] + 2 + 7 + 1, NULL);
1262 }
1263 else {
1264 /* get the next argv[] unless it starts with a '-' */
1265 if(i + 1 < argc
1266 && argv[i + 1][0] != '-') {
1267 i++;
1268 advance = strtod(argv[i], NULL);
1269 }
1270 }
1271 }
1272 else if(strcmp(argv[i] + 2, "control") == 0) {
1273 output_control = 1;
1274 }
1275 else if(strncmp(argv[i] + 2, "glyphs", 6) == 0) {
1276 glyphs = NULL;
1277 if(argv[i][2 + 6] == '=') {
1278 /* name stuck with the option */
1279 glyphs = argv[i] + 2 + 6 + 1;
1280 sort_glyphs();
1281 }
1282 else {
1283 /* get the next argv[] unless it starts with a '-' */
1284 if(i + 1 < argc
1285 && argv[i + 1][0] != '-') {
1286 i++;
1287 glyphs = argv[i];
1288 sort_glyphs();
1289 }
1290 }
1291 }
1292 else if(strcmp(argv[i] + 2, "include-null") == 0) {
1293 include_null = 1;
1294 }
1295 else if(strncmp(argv[i] + 2, "map", 3) == 0) {
1296 /* first, we revert to the default */
1297 char_map_encoding = (FT_Encoding) -1;
1298 if(argv[i][2 + 3] == '=') {
1299 /* name stuck with the option */
1300 char_map_encoding = string_to_encoding(argv[i] + 2 + 3 + 1);
1301 }
1302 else {
1303 /* get the next argv[] unless it starts with a '-' */
1304 if(i + 1 < argc
1305 && argv[i + 1][0] != '-') {
1306 i++;
1307 char_map_encoding = string_to_encoding(argv[i]);
1308 }
1309 }
1310 }
1311 else if(strcmp(argv[i] + 2, "no-null") == 0) {
1312 include_null = 0;
1313 }
1314 else if(strncmp(argv[i] + 2, "output", 6) == 0) {
1315 /* first, we revert to the default */
1316 if(output != stdout) {
1317 fclose(output);
1318 output = stdout;
1319 }
1320 output_filename = NULL;
1321 if(argv[i][2 + 6] == '=') {
1322 /* name stuck with the option */
1323 output_filename = argv[i] + 2 + 6 + 1;
1324 if(output_filename[0] != '\0'
1325 && strcmp(output_filename, "-") != 0) {
1326 output = fopen(output_filename, "w");
1327 }
1328 }
1329 else {
1330 /* get the next argv[] unless it starts with a '-' */
1331 if(i + 1 < argc
1332 && argv[i + 1][0] != '-') {
1333 i++;
1334 output_filename = argv[i];
1335 output = fopen(output_filename, "w");
1336 }
1337 }
1338 if(output == NULL) {
1339 fprintf(stderr, "ERROR: can't open ouptut file \"%s\" (errno: %d).\n", output_filename, errno);
1340 exit(1);
1341 }
1342 }
1343 else if(strcmp(argv[i] + 2, "version") == 0) {
1344 printf("%s\n", version);
1345 exit(1);
1346 }
1347 else if(strcmp(argv[i] + 2, "help") == 0) {
1348 usage(argv[0]);
1349 /*NOTREACHED*/
1350 }
1351 else {
1352 fprintf(stderr, "ERROR: unknown option \"%s\", process stopped.\n", argv[i]);
1353 exit(1);
1354 }
1355 }
1356 else if(argv[i][1] == '\0') {
1357 // got a request to process stdin as a font...
1358 run_font("-");
1359 }
1360 else {
1361 len = strlen(argv[i]);
1362 for(j = 1; j < len; j++) {
1363 switch(argv[i][j]) {
1364 case 'c':
1365 switch(argv[i][j + 1]) {
1366 case '0':
1367 comment = 0;
1368 j++;
1369 break;
1370
1371 case '1':
1372 comment = 1;
1373 j++;
1374 break;
1375
1376 default:
1377 comment = 1;
1378 break;
1379
1380 }
1381 break;
1382
1383 case 'e':
1384 switch(argv[i][j + 1]) {
1385 case '0':
1386 encoding = 0;
1387 j++;
1388 break;
1389
1390 case '1':
1391 encoding = 1;
1392 j++;
1393 break;
1394
1395 case '2':
1396 show_encodings();
1397 /*NOTREACHED*/
1398 break;
1399
1400 default:
1401 encoding = 1;
1402 break;
1403
1404 }
1405 break;
1406
1407 case 'f':
1408 if(argv[i][j + 1] != '\0') {
1409 factor = strtod(argv[i] + j + 1, NULL) * 64.0;
1410 }
1411 else if(i + 1 < argc) {
1412 i++;
1413 factor = strtod(argv[i], NULL) * 64.0;
1414 }
1415 else {
1416 factor = 64.0;
1417 }
1418 j = len;
1419 break;
1420
1421 case 'g':
1422 if(argv[i][j + 1] != '\0') {
1423 glyphs = argv[i] + j + 1;
1424 sort_glyphs();
1425 }
1426 else if(i + 1 < argc) {
1427 i++;
1428 glyphs = argv[i];
1429 sort_glyphs();
1430 }
1431 else {
1432 glyphs = NULL;
1433 }
1434 j = len;
1435 break;
1436
1437 case 'h':
1438 usage(argv[0]);
1439 /*NOTREACHED*/
1440 break;
1441
1442 case 'm':
1443 if(argv[i][j + 1] != '\0') {
1444 char_map_encoding = string_to_encoding(argv[i] + j + 1);
1445 }
1446 else if(i + 1 < argc) {
1447 i++;
1448 char_map_encoding = string_to_encoding(argv[i]);
1449 }
1450 else {
1451 char_map_encoding = (FT_Encoding) -1;
1452 }
1453 j = len;
1454 break;
1455
1456 case 'n':
1457 include_null = 1;
1458 switch(argv[i][j + 1]) {
1459 case '0':
1460 include_null = 0;
1461 j++;
1462 break;
1463
1464 case '1':
1465 j++;
1466 break;
1467
1468 }
1469 break;
1470
1471 case 'o':
1472 if(output != stdout) {
1473 fclose(output);
1474 output = stdout;
1475 }
1476 output_filename = NULL;
1477 if(argv[i][j + 1] != '\0') {
1478 output_filename = argv[i] + j + 1;
1479 }
1480 else if(i + 1 < argc) {
1481 i++;
1482 output_filename = argv[i];
1483 }
1484 j = len;
1485 if(output_filename != NULL) {
1486 output = fopen(output_filename, "w");
1487 if(output == NULL) {
1488 fprintf(stderr, "ERROR: can't open ouptut file \"%s\" (errno: %d).\n", output_filename, errno);
1489 exit(1);
1490 }
1491 }
1492 break;
1493
1494 case 'q':
1495 verbose = 0;
1496 break;
1497
1498 case 'v':
1499 verbose++;
1500 break;
1501
1502 default:
1503 fprintf(stderr, "ERROR: unknown option \"-%c\", process stopped.\n", argv[i][j]);
1504 exit(1);
1505
1506 }
1507 }
1508 }
1509 }
1510 else {
1511 /* got a filename, process this font */
1512 run_font(argv[i]);
1513 }
1514 }
1515 }
1516
1517
main(int argc,char * argv[])1518 int main(int argc, char *argv[])
1519 {
1520 FT_Error error;
1521
1522 /* we need to initialize the free font library only once */
1523 error = FT_Init_FreeType(&library);
1524 if(error) {
1525 fprintf(stderr, "ERROR: can't initialize the free type library.\n");
1526 exit(1);
1527 }
1528
1529 run_command_line(argc, argv);
1530
1531 error = FT_Done_FreeType(library);
1532 if(error) {
1533 fprintf(stderr, "WARNING: the release of the FreeFont library failed.\n");
1534 }
1535
1536 exit(errcnt == 0 ? 0 : 1);
1537 return 0;
1538 }
1539
1540