* implemented definefont2 parsing
[swftools.git] / lib / modules / swftext.c
1 /* swftext.c
2
3    Text and font routines
4       
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
9  
10    This file is distributed under the GPL, see file COPYING for details 
11
12 */
13
14 #define TF_TEXTCONTROL  0x80
15 #define TF_HASFONT      0x08
16 #define TF_HASCOLOR     0x04
17 #define TF_HASYOFFSET   0x02
18 #define TF_HASXOFFSET   0x01
19
20 #define FF_WIDECODES    0x01
21 #define FF_BOLD         0x02
22 #define FF_ITALIC       0x04
23 #define FF_ANSI         0x08
24 #define FF_SHIFTJIS     0x10
25 #define FF_UNICODE      0x20
26
27 #define FF2_BOLD         0x01
28 #define FF2_ITALIC       0x02
29 #define FF2_WIDECODES    0x04
30 #define FF2_WIDEOFFSETS  0x08
31 #define FF2_ANSI         0x10
32 #define FF2_UNICODE      0x20
33 #define FF2_SHIFTJIS     0x40
34 #define FF2_LAYOUT       0x80
35
36 int swf_FontIsItalic(SWFFONT * f) { return f->version==2?f->flags&FF2_ITALIC:f->flags&FF_ITALIC; }
37 int swf_FontIsBold(SWFFONT * f)   { return f->version==2?f->flags&FF2_BOLD:f->flags&FF_BOLD; }
38
39 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
40
41 int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*))
42 { int n;
43   TAG * t;
44   if (!swf) return -1;
45   t = swf->firstTag;
46   n = 0;
47
48   while (t)
49   { if (swf_GetTagID(t)==ST_DEFINEFONTINFO)
50     { n++;
51       if (FontCallback)
52       { U16 id;
53         int l;
54         U8 s[257];
55         swf_SaveTagPos(t);
56         swf_SetTagPos(t,0);
57
58         id  = swf_GetU16(t);
59         l   = swf_GetU8(t);
60         swf_GetBlock(t,s,l);
61         s[l] = 0;
62
63         (FontCallback)(id,s); 
64       
65         swf_RestoreTagPos(t);
66       }
67     }
68     t = swf_NextTag(t);
69   }
70   return n;
71 }
72
73 int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t, SHAPE***shapes)
74 { U16 fid;
75   swf_SaveTagPos(t);
76   swf_SetTagPos(t,0);
77
78   fid = swf_GetU16(t);
79   if ((!id)||(id==fid))
80   { U16 of,*ofs;
81     int n,i;
82       
83     id = fid;
84     f->version = 1;
85     f->id = fid;
86
87     of = swf_GetU16(t);
88     n = of/2;
89     f->numchars = n;
90     (*shapes) = (SHAPE**)malloc(sizeof(SHAPE*)*n);
91     memset((*shapes), 0, sizeof(SHAPE*)*n);
92
93     for (i=1;i<n;i++) swf_GetU16(t);
94     for (i=0;i<n;i++) swf_GetSimpleShape(t,&((*shapes)[i]));
95   }
96
97   swf_RestoreTagPos(t);
98   return id;
99 }
100
101 int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t,SHAPE**shapes)
102 { U16 fid;
103   swf_SaveTagPos(t);
104   swf_SetTagPos(t,0);
105
106   if(f->version>1) {
107       // DefineFont2 doesn't have FontInfo fields
108       fprintf(stderr, "fixme: FontInfo field for DefineFont2 encountered\n");
109       return -1;
110   }
111
112   fid = swf_GetU16(t);
113   if (fid==id)
114   { U8 l = swf_GetU8(t);
115     int i;
116     
117     if (l)
118     { if (f->name) free(f->name);
119       f->name = (U8*)malloc(l+1);
120       if (f->name)
121       { swf_GetBlock(t,f->name,l);
122         f->name[l] = 0;
123       }
124       else
125       { swf_RestoreTagPos(t);
126         return -1;
127       }
128     }
129     f->flags = swf_GetU8(t);
130
131     f->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*f->numchars);
132     memset(f->glyph, 0, sizeof(SWFGLYPH)*f->numchars);
133     f->codes = (U16*)malloc(sizeof(U16)*f->numchars);
134     memset(f->codes, 0, sizeof(U16)*f->numchars);
135     for(i=0; i < f->numchars; i++)
136     { U16 code = ((f->flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t));
137        
138       if(code < f->numchars) {
139           f->glyph[code].shape = shapes[i];
140           f->glyph[code].gid   = i;
141       }
142       f->codes[i] = code;
143     }
144   }
145
146   swf_RestoreTagPos(t);
147   return id;
148 }
149
150 int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag,SHAPE * * * shapes)
151 {
152     int t, glyphcount;
153     U8 flags1,flags2,namelen;
154     font->version=2;
155     font->id = swf_GetU16(tag);
156     flags1 = swf_GetU8(tag);
157     flags2 = swf_GetU8(tag); //reserved flags
158     namelen = swf_GetU8(tag);
159     font->flags = flags1;
160     font->name = (U8*)malloc(namelen+1);
161     font->name[namelen]=0;
162     swf_GetBlock(tag, font->name, namelen);
163     font->version = 2;
164     glyphcount = swf_GetU16(tag);
165     font->numchars = glyphcount;
166     (*shapes) = (SHAPE**)malloc(sizeof(SHAPE*)*glyphcount);
167     memset((*shapes), 0, sizeof(SHAPE*)*glyphcount);
168     if(flags1&8) { // wide offsets
169         for(t=0;t<glyphcount;t++)
170             swf_GetU32(tag); //offset[t]
171         swf_GetU32(tag); // fontcodeoffset
172     } else {
173         for(t=0;t<glyphcount;t++)
174             swf_GetU16(tag); //offset[t]
175         swf_GetU16(tag); // fontcodeoffset
176     }
177     for(t=0;t<glyphcount;t++)
178         swf_GetSimpleShape(tag,&((*shapes)[t]));
179
180     font->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*glyphcount);
181     memset(font->glyph, 0, sizeof(SWFGLYPH)*glyphcount);
182     font->codes = (U16*)malloc(sizeof(U16)*glyphcount);
183     memset(font->codes, 0, sizeof(U16)*glyphcount);
184     for(t=0;t<glyphcount;t++) {
185         U16 code;
186         if(flags1&4) // wide codes
187             code = swf_GetU16(tag);
188         else
189             code = swf_GetU8(tag);
190
191         font->glyph[code].shape = (*shapes)[t];
192         font->glyph[code].gid   = t;
193         if (t<MAX_CHAR_PER_FONT) 
194             font->codes[t] = code;
195     }
196     if(flags1&128) { // has layout
197         U16 kerningcount;
198         font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
199         font->layout->ascent=swf_GetU16(tag);
200         font->layout->descent=swf_GetU16(tag);
201         font->layout->leading=swf_GetU16(tag);
202         for(t=0;t<glyphcount;t++) {
203             S16 advance = swf_GetS16(tag);
204             font->glyph[t].advance = advance;
205         }
206         font->layout->bounds = malloc(glyphcount*sizeof(SRECT));
207         for(t=0;t<glyphcount;t++) {
208             swf_ResetReadBits(tag);
209             swf_GetRect(tag, font->layout->bounds);
210         }
211         kerningcount = swf_GetU16(tag);
212         font->layout->kerningcount = kerningcount;
213         font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount);
214         if(kerningcount) {
215             font->layout->kerning = 
216                 malloc(sizeof(*font->layout->kerning)* kerningcount);
217             for(t=0;t<kerningcount;t++)
218             {
219                 if(flags1&4) { // wide codes
220                     font->layout->kerning[t].char1 = swf_GetU16(tag);
221                     font->layout->kerning[t].char2 = swf_GetU16(tag);
222                 } else {
223                     font->layout->kerning[t].char1 = swf_GetU16(tag);
224                     font->layout->kerning[t].char2 = swf_GetU16(tag);
225                 }
226                 font->layout->kerning[t].adjustment = swf_GetS16(tag);
227             }
228         }
229     }
230     return font->id;
231 }
232
233
234 #define FEDTJ_PRINT  0x01
235 #define FEDTJ_MODIFY 0x02
236
237 int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
238 { U16    cid;
239   SRECT  r;
240   MATRIX m;
241   U8     gbits, abits, flags;
242   int    fid;
243
244   fid = 0;
245
246   swf_SaveTagPos(t);
247   swf_SetTagPos(t,0);
248
249   cid = swf_GetU16(t);
250   swf_GetRect(t,&r);
251   swf_GetMatrix(t,&m);
252   gbits = swf_GetU8(t);
253   abits = swf_GetU8(t);
254
255   flags = swf_GetU8(t);
256   
257   while(flags)
258   { if (flags&TF_TEXTCONTROL)
259     { if (flags&TF_HASFONT) fid = swf_GetU16(t);
260       if (flags&TF_HASCOLOR)
261       { swf_GetU8(t); // rgb
262         swf_GetU8(t);
263         swf_GetU8(t);
264         if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_GetU8(t);
265       }
266       if (flags&TF_HASXOFFSET) swf_GetS16(t);
267       if (flags&TF_HASYOFFSET) swf_GetS16(t);
268       if (flags&TF_HASFONT) swf_GetU16(t);
269     }
270     else
271     { int i;
272       for (i=0;i<flags;i++)
273       { int glyph;
274         int adv;
275         glyph = swf_GetBits(t,gbits);
276         adv = swf_GetBits(t,abits);
277         if (id==fid)                    // mitlesen ?
278         { int code = f->codes[glyph];
279           if (jobs&FEDTJ_PRINT) printf("%c",code);
280           if (jobs&FEDTJ_MODIFY)
281             /*if (!f->glyph[code].advance)*/ f->glyph[code].advance = adv;
282         }
283       }
284       if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
285     }
286     flags = swf_GetU8(t);
287   }
288   
289   swf_RestoreTagPos(t);
290   return id;
291 }  
292
293 int swf_FontExtract(SWF * swf,int id,SWFFONT * * font)
294 { TAG * t;
295   SWFFONT * f;
296   SHAPE ** shapes;
297     
298   if ((!swf)||(!font)) return -1;
299
300   f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
301   if (!f) return -1;
302   
303   memset(f,0x00,sizeof(SWFFONT));
304
305   t = swf->firstTag;
306
307   while (t)
308   { int nid = 0;
309     switch (swf_GetTagID(t))
310     { case ST_DEFINEFONT:
311         nid = swf_FontExtract_DefineFont(id,f,t,&shapes);
312         break;
313     
314       case ST_DEFINEFONT2:
315         nid = swf_FontExtract_DefineFont2(id,f,t,&shapes);
316         break;
317         
318       case ST_DEFINEFONTINFO:
319         nid = swf_FontExtract_DefineFontInfo(id,f,t,shapes);
320         break;
321         
322       case ST_DEFINETEXT:
323       case ST_DEFINETEXT2:
324         nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
325         break;
326     }
327     if (nid>0) id = nid;
328     t = swf_NextTag(t);
329   }
330   return 0;
331 }
332
333 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
334
335 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
336 { int i,j,num;
337   if ((!f)||(!use)) return -1;
338
339   memset(f->codes,0,sizeof(f->codes[0])*f->numchars);
340
341   j = 0;
342   for (i=0;i<f->numchars;i++)
343     if (f->glyph[i].shape)
344     { if (i<MAX_CHAR_PER_FONT && use->code[i])
345       { f->glyph[i].gid = j;
346         f->codes[j] = i;
347         j++;
348       }
349       else
350       { swf_ShapeFree(f->glyph[i].shape);
351         f->glyph[i].shape   = 0;
352         f->glyph[i].gid     = 0;
353         f->glyph[i].advance = 0;
354       }
355     } else f->glyph[i].gid = 0;
356     
357   return j;
358 }
359
360 int swf_FontInitUsage(FONTUSAGE * use)
361 { if (!use) return -1;
362   memset(&use->code,0x00,sizeof(use->code));
363   return 0;
364 }
365
366 int swf_FontUse(FONTUSAGE * use,U8 * s)
367 { if ((!use)||(!s)) return -1;
368   while (s[0])
369   { use->code[s[0]] = 1;
370     s++;
371   }
372   return 0;  
373 }
374
375 int swf_FontSetDefine(TAG * t,SWFFONT * f)
376 { U16*ofs = (U16*)malloc(f->numchars*2);
377   int p,i,j;
378     
379   if ((!t)||(!f)) return -1;
380   swf_ResetWriteBits(t);
381   swf_SetU16(t,f->id);
382
383   p = 0; j = 0;
384   for (i=0;i<f->numchars;i++)
385     if (f->glyph[i].shape)
386     { ofs[j++] = p;
387       p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
388     }
389
390   for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
391   
392   for (i=0;i<f->numchars;i++)
393     if (f->glyph[i].shape)
394       swf_SetSimpleShape(t,f->glyph[i].shape);
395   
396   swf_ResetWriteBits(t);
397   free(ofs);
398   return 0;
399 }
400
401 int swf_FontSetInfo(TAG * t,SWFFONT * f)
402 { int l,i;
403   U8 wide=0;
404   if ((!t)||(!f)) return -1;
405   swf_ResetWriteBits(t);
406   swf_SetU16(t,f->id);
407   l = strlen(f->name); if (l>255) l = 255;
408   swf_SetU8(t,l);
409   swf_SetBlock(t,f->name,l);
410   if(f->numchars>=256)
411       wide=1;
412   swf_SetU8(t,(f->flags&0xfe)|wide);
413
414   for (i=0;i<f->numchars;i++) {
415     if (f->glyph[i].shape)
416       wide?swf_SetU16(t,i):swf_SetU16(t,i);
417   }
418   
419   return 0;
420 }
421
422 int swf_FontExport(int handle,SWFFONT * f)
423 { int l;
424   int i;
425   if (!f) return 0;
426
427   l = sizeof(SWFFONT);
428   if (handle>=0)
429     if (write(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) return -1;
430
431   if (f->name)
432   { U16 ln = strlen(f->name);
433     l+=2+ln;
434     if (handle>=0)
435     { if (write(handle,&ln,2)!=2) return -1;
436       if (write(handle,f->name,ln)!=ln) return -1;
437     }
438   }
439
440   if (f->layout)
441   { l+=sizeof(SWFLAYOUT);
442     if (handle>=0)
443       if (write(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) return -1;
444 /*    new kerning struct. hope commenting this out doesn't break things
445       if (f->layout->kerning.data)
446     { l+=f->layout->kerning.count*4;
447       if (handle>=0)
448         if (write(handle,f->layout->kerning.data,f->layout->kerning.count*4)!=f->layout->kerning.count*4) return -1;
449     }*/
450   }
451
452   for (i=0;i<f->numchars;i++)
453   { if (f->glyph[i].shape)
454     { int ll = swf_ShapeExport(handle,f->glyph[i].shape);
455       if (ll<0) return -1;
456       l+=ll;
457     }  
458   }
459
460   return l;
461 }
462
463 int swf_FontImport(int handle,SWFFONT * * font)
464 { SWFFONT * f;
465   int layout;
466   int i = 0;
467
468   if ((!font)||(handle<0)) return -1;
469
470   f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
471   if (!f) return -1;
472
473   memset(f,0x00,sizeof(SWFFONT));
474   
475   if (read(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) goto fehler;
476
477   layout = (f->layout)?1:0;             // avoid illegal free()
478   f->layout = NULL;
479
480   if (f->name)
481   { U16 ln;
482     f->name = NULL;
483     if (read(handle,&ln,2)!=2) goto fehler;
484     f->name = (U8*)malloc(ln+1);
485     if (!f->name) goto fehler;
486     if (read(handle,f->name,ln)!=ln) goto fehler;
487     f->name[ln] = 0;
488   }
489
490   if (f->layout)
491   { f->layout = (SWFLAYOUT *)malloc(sizeof(SWFLAYOUT));
492     if (!f->layout) goto fehler;
493     if (read(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) goto fehler;
494     /* new kerning struct. hope commenting this out doesn't break things
495     if (f->layout->kerning.data)
496     { int l = f->layout->kerning.count*4;
497       f->layout->kerning.data = (U8*)malloc(l);
498       if (!f->layout->kerning.data) goto fehler;
499       if (read(handle,f->layout->kerning.data,l)!=l) goto fehler;
500     } */
501   }
502
503   for (i=0;i<f->numchars;i++)
504   { if (f->glyph[i].shape)
505     { if (swf_ShapeImport(handle,&f->glyph[i].shape)<0) goto fehler;
506     }
507   }
508
509   f->id = 0;
510   
511   return 0;
512   
513 fehler:
514   if (f) for (;i<MAX_CHAR_PER_FONT;i++) f->glyph[i].shape = NULL;
515   swf_FontFree(f);
516   font[0] = NULL;
517   return -1;
518 }
519
520 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
521 { int id = swf_GetTagID(t);
522   if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
523     else return -1;
524   return 0;
525 }
526
527 void swf_LayoutFree(SWFLAYOUT * l)
528 { if (l)
529   { if (l->kerning) free(l->kerning);
530     l->kerning = NULL;
531     if (l->bounds) free(l->bounds);
532     l->bounds = NULL;
533   }
534   free(l);
535 }
536
537 void swf_FontFree(SWFFONT * f)
538 { if (f)
539   { int i;
540       
541     if (f->name) free(f->name);
542     if (f->layout) swf_LayoutFree(f->layout);
543
544     f->name = NULL;
545     f->layout = NULL;
546
547     if(f->glyph) {
548       for (i=0;i<f->numchars;i++)
549         if (f->glyph[i].shape)
550         { swf_ShapeFree(f->glyph[i].shape);
551           f->glyph[i].shape = NULL;
552         }
553       free(f->glyph);
554       f->glyph = NULL;
555     }
556     if(f->codes) {
557       free(f->codes);
558       f->codes = NULL;
559     }
560   }
561   free(f);
562 }
563
564 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S16 dy)
565 { U8 flags;
566   if (!t) return -1;
567
568   flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
569
570   swf_SetU8(t,flags);
571   if (font) swf_SetU16(t,font->id);
572   if (color)
573   { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
574     else swf_SetRGB(t,color);
575   }
576   if (dx) swf_SetS16(t,dx);
577   if (dy) swf_SetS16(t,dy);
578   if (font) swf_SetU16(t,size);
579   
580   return 0;
581 }
582
583 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
584 { U16 g,a;
585   if ((!s)||(!font)||((!gbits)&&(!abits))) return -1;
586   g = a = 0;
587
588   while(s[0])
589   { g = swf_CountBits(font->glyph[s[0]].gid,g);
590     a = swf_CountBits((((U32)font->glyph[s[0]].advance)*scale)/100,a);
591     s++;
592   }
593
594   if (gbits) gbits[0] = (U8)g;
595   if (abits) abits[0] = (U8)a;
596
597   return 0;
598 }
599
600 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
601 { int l,i;
602     
603   if ((!t)||(!font)||(!s)) return -1;
604
605   l = strlen(s);
606   if (l>0x7f) l = 0x7f;
607   swf_SetU8(t,l);
608
609   for (i=0;i<l;i++)
610   { swf_SetBits(t,font->glyph[s[i]].gid,gbits);
611     swf_SetBits(t,(((U32)font->glyph[s[i]].advance)*scale)/100,abits);
612   }
613
614   swf_ResetWriteBits(t);
615   return 0;
616 }
617
618 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
619 { U32 res = 0;
620
621   if (font&&s)
622   { while (s[0])
623     { res += font->glyph[s[0]].advance;
624       s++;
625     }
626     if (scale) res = (res*scale)/100;
627   }
628   return res;
629 }
630
631 void swf_WriteFont(SWFFONT*font, char* filename, int useDefineFont2)
632 { SWF swf;
633   TAG * t;
634   SRECT r;
635   RGBA rgb;
636   int f;
637
638   if(useDefineFont2) {
639       fprintf(stderr, "DefineFont2 is not yet supported!\n");
640       useDefineFont2 = 0;
641   }
642
643   font->id = WRITEFONTID; //"FN"
644
645   memset(&swf,0x00,sizeof(SWF));
646
647   swf.fileVersion    = 4;
648   swf.frameRate      = 0x4000;
649   swf.movieSize.xmax = 20*640;
650   swf.movieSize.ymax = 20*480;
651
652   if(!useDefineFont2)
653   /* if we use DefineFont1 to store the characters,
654      we have to build a textfield to store the
655      advance values. While at it, we can also
656      make the whole .swf viewable */
657   {
658       t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
659       swf.firstTag = t;
660             rgb.r = 0xff;
661             rgb.g = 0xff;
662             rgb.b = 0xff;
663             swf_SetRGB(t,&rgb);
664       t = swf_InsertTag(t,ST_DEFINEFONT);
665   }
666   else
667   {
668       t = swf_InsertTag(NULL,ST_DEFINEFONT);
669       swf.firstTag = t;
670   }
671
672         swf_FontSetDefine(t,font);
673   
674   t = swf_InsertTag(t,ST_DEFINEFONTINFO);
675         swf_FontSetInfo(t,font);
676
677   if(!useDefineFont2)
678   {
679         int textscale = 400;
680         int s;
681         int xmax = 0;
682         int ymax = textscale * 20;
683         U8 gbits,abits;
684         char text[257];
685         int x,y;
686         text[256]=0;
687         for(s=0;s<256;s++)
688         {
689             text[s] = s;
690             if(font->glyph[s].advance*textscale/100 > xmax)
691                 xmax = font->glyph[s].advance*textscale/100;
692         }
693         swf.movieSize.xmax = xmax*20;
694         swf.movieSize.ymax = ymax;
695
696         t = swf_InsertTag(t,ST_DEFINETEXT);
697
698             swf_SetU16(t,font->id+1);            // ID
699
700             r.xmin = 0;
701             r.ymin = 0;
702             r.xmax = swf.movieSize.xmax*20;
703             r.ymax = swf.movieSize.ymax;
704             
705             swf_SetRect(t,&r);
706
707             swf_SetMatrix(t,NULL);
708
709             abits = swf_CountBits(xmax*16, 0);
710             gbits = 8;
711             
712             swf_SetU8(t,gbits);
713             swf_SetU8(t,abits);
714
715             rgb.r = 0x00;
716             rgb.g = 0x00;
717             rgb.b = 0x00;
718             for(y=0;y<16;y++)
719             {
720                 int c=0,lastx=-1, firstx=0;
721                 for(x=0;x<16;x++) {
722                     if(font->glyph[y*16+x].shape) {
723                         c++;
724                         if(lastx<0) 
725                             lastx = x*xmax;
726                     }
727                 }
728                 if(c) {
729                   swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y);
730                   for(x=0;x<16;x++)
731                   {
732                       if(font->glyph[y*16+x].shape) {
733                         if(lastx != x*xmax) {
734                             swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
735                         }
736                         swf_SetU8(t,1);
737                         swf_SetBits(t, font->glyph[y*16+x].gid, gbits);
738                         swf_SetBits(t, font->glyph[y*16+x].advance, abits);
739                         lastx = x*xmax+font->glyph[y*16+x].advance;
740                         swf_ResetWriteBits(t);
741                       }
742                   }
743                 } 
744             }
745             swf_SetU8(t,0);
746         
747         t = swf_InsertTag(t,ST_PLACEOBJECT2);
748
749             swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
750      
751         t = swf_InsertTag(t,ST_SHOWFRAME);
752   }
753   
754   t = swf_InsertTag(t,ST_END);
755
756   f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
757   if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");
758   close(f);
759
760   swf_FreeTags(&swf);
761 }
762
763 SWFFONT* swf_ReadFont(char* filename)
764 {
765   int f;
766   SWF swf;
767   if(!filename)
768       return 0;
769   f = open(filename,O_RDONLY);
770   
771   if (f<0 || swf_ReadSWF(f,&swf)<0)
772   { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
773     close(f);
774     return 0;
775   }
776   else
777   { SWFFONT*font;
778     close(f);
779     if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
780        return 0;
781     swf_FreeTags(&swf);
782     return font;
783   }
784 }
785