5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2001 Rainer Böhme <rfxswf@reflex-studio.de>
10 This file is distributed under the GPL, see file COPYING for details
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
20 #define FF_WIDECODES 0x01
22 #define FF_ITALIC 0x04
24 #define FF_SHIFTJIS 0x10
25 #define FF_UNICODE 0x20
28 #define FF2_ITALIC 0x02
29 #define FF2_WIDECODES 0x04
30 #define FF2_WIDEOFFSETS 0x08
32 #define FF2_UNICODE 0x20
33 #define FF2_SHIFTJIS 0x40
34 #define FF2_LAYOUT 0x80
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; }
39 static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont
41 int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*))
49 { if (swf_GetTagID(t)==ST_DEFINEFONTINFO)
73 int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t, SHAPE***shapes)
90 (*shapes) = (SHAPE**)malloc(sizeof(SHAPE*)*n);
91 memset((*shapes), 0, sizeof(SHAPE*)*n);
93 for (i=1;i<n;i++) swf_GetU16(t);
94 for (i=0;i<n;i++) swf_GetSimpleShape(t,&((*shapes)[i]));
101 int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t,SHAPE**shapes)
107 // DefineFont2 doesn't have FontInfo fields
108 fprintf(stderr, "fixme: FontInfo field for DefineFont2 encountered\n");
114 { U8 l = swf_GetU8(t);
118 { if (f->name) free(f->name);
119 f->name = (U8*)malloc(l+1);
121 { swf_GetBlock(t,f->name,l);
125 { swf_RestoreTagPos(t);
129 f->flags = swf_GetU8(t);
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));
138 if(code < f->numchars) {
139 f->glyph[code].shape = shapes[i];
140 f->glyph[code].gid = i;
146 swf_RestoreTagPos(t);
150 int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag,SHAPE * * * shapes)
153 U8 flags1,flags2,namelen;
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);
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
173 for(t=0;t<glyphcount;t++)
174 swf_GetU16(tag); //offset[t]
175 swf_GetU16(tag); // fontcodeoffset
177 for(t=0;t<glyphcount;t++)
178 swf_GetSimpleShape(tag,&((*shapes)[t]));
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++) {
186 if(flags1&4) // wide codes
187 code = swf_GetU16(tag);
189 code = swf_GetU8(tag);
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;
196 if(flags1&128) { // has layout
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;
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);
211 kerningcount = swf_GetU16(tag);
212 font->layout->kerningcount = kerningcount;
213 font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount);
215 font->layout->kerning =
216 malloc(sizeof(*font->layout->kerning)* kerningcount);
217 for(t=0;t<kerningcount;t++)
219 if(flags1&4) { // wide codes
220 font->layout->kerning[t].char1 = swf_GetU16(tag);
221 font->layout->kerning[t].char2 = swf_GetU16(tag);
223 font->layout->kerning[t].char1 = swf_GetU16(tag);
224 font->layout->kerning[t].char2 = swf_GetU16(tag);
226 font->layout->kerning[t].adjustment = swf_GetS16(tag);
234 #define FEDTJ_PRINT 0x01
235 #define FEDTJ_MODIFY 0x02
237 int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
241 U8 gbits, abits, flags;
252 gbits = swf_GetU8(t);
253 abits = swf_GetU8(t);
255 flags = swf_GetU8(t);
258 { if (flags&TF_TEXTCONTROL)
259 { if (flags&TF_HASFONT) fid = swf_GetU16(t);
260 if (flags&TF_HASCOLOR)
261 { swf_GetU8(t); // rgb
264 if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_GetU8(t);
266 if (flags&TF_HASXOFFSET) swf_GetS16(t);
267 if (flags&TF_HASYOFFSET) swf_GetS16(t);
268 if (flags&TF_HASFONT) swf_GetU16(t);
272 for (i=0;i<flags;i++)
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;
284 if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
286 flags = swf_GetU8(t);
289 swf_RestoreTagPos(t);
293 int swf_FontExtract(SWF * swf,int id,SWFFONT * * font)
298 if ((!swf)||(!font)) return -1;
300 f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
303 memset(f,0x00,sizeof(SWFFONT));
309 switch (swf_GetTagID(t))
310 { case ST_DEFINEFONT:
311 nid = swf_FontExtract_DefineFont(id,f,t,&shapes);
315 nid = swf_FontExtract_DefineFont2(id,f,t,&shapes);
318 case ST_DEFINEFONTINFO:
319 nid = swf_FontExtract_DefineFontInfo(id,f,t,shapes);
324 nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
333 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
335 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
337 if ((!f)||(!use)) return -1;
339 memset(f->codes,0,sizeof(f->codes[0])*f->numchars);
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;
350 { swf_ShapeFree(f->glyph[i].shape);
351 f->glyph[i].shape = 0;
353 f->glyph[i].advance = 0;
355 } else f->glyph[i].gid = 0;
360 int swf_FontInitUsage(FONTUSAGE * use)
361 { if (!use) return -1;
362 memset(&use->code,0x00,sizeof(use->code));
366 int swf_FontUse(FONTUSAGE * use,U8 * s)
367 { if ((!use)||(!s)) return -1;
369 { use->code[s[0]] = 1;
375 int swf_FontSetDefine(TAG * t,SWFFONT * f)
376 { U16*ofs = (U16*)malloc(f->numchars*2);
379 if ((!t)||(!f)) return -1;
380 swf_ResetWriteBits(t);
384 for (i=0;i<f->numchars;i++)
385 if (f->glyph[i].shape)
387 p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
390 for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
392 for (i=0;i<f->numchars;i++)
393 if (f->glyph[i].shape)
394 swf_SetSimpleShape(t,f->glyph[i].shape);
396 swf_ResetWriteBits(t);
401 int swf_FontSetInfo(TAG * t,SWFFONT * f)
404 if ((!t)||(!f)) return -1;
405 swf_ResetWriteBits(t);
407 l = strlen(f->name); if (l>255) l = 255;
409 swf_SetBlock(t,f->name,l);
412 swf_SetU8(t,(f->flags&0xfe)|wide);
414 for (i=0;i<f->numchars;i++) {
415 if (f->glyph[i].shape)
416 wide?swf_SetU16(t,i):swf_SetU16(t,i);
422 int swf_FontExport(int handle,SWFFONT * f)
429 if (write(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) return -1;
432 { U16 ln = strlen(f->name);
435 { if (write(handle,&ln,2)!=2) return -1;
436 if (write(handle,f->name,ln)!=ln) return -1;
441 { l+=sizeof(SWFLAYOUT);
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;
448 if (write(handle,f->layout->kerning.data,f->layout->kerning.count*4)!=f->layout->kerning.count*4) return -1;
452 for (i=0;i<f->numchars;i++)
453 { if (f->glyph[i].shape)
454 { int ll = swf_ShapeExport(handle,f->glyph[i].shape);
463 int swf_FontImport(int handle,SWFFONT * * font)
468 if ((!font)||(handle<0)) return -1;
470 f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
473 memset(f,0x00,sizeof(SWFFONT));
475 if (read(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) goto fehler;
477 layout = (f->layout)?1:0; // avoid illegal free()
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;
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;
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;
514 if (f) for (;i<MAX_CHAR_PER_FONT;i++) f->glyph[i].shape = NULL;
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);
527 void swf_LayoutFree(SWFLAYOUT * l)
529 { if (l->kerning) free(l->kerning);
531 if (l->bounds) free(l->bounds);
537 void swf_FontFree(SWFFONT * f)
541 if (f->name) free(f->name);
542 if (f->layout) swf_LayoutFree(f->layout);
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;
564 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S16 dy)
568 flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
571 if (font) swf_SetU16(t,font->id);
573 { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
574 else swf_SetRGB(t,color);
576 if (dx) swf_SetS16(t,dx);
577 if (dy) swf_SetS16(t,dy);
578 if (font) swf_SetU16(t,size);
583 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
585 if ((!s)||(!font)||((!gbits)&&(!abits))) return -1;
589 { g = swf_CountBits(font->glyph[s[0]].gid,g);
590 a = swf_CountBits((((U32)font->glyph[s[0]].advance)*scale)/100,a);
594 if (gbits) gbits[0] = (U8)g;
595 if (abits) abits[0] = (U8)a;
600 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
603 if ((!t)||(!font)||(!s)) return -1;
606 if (l>0x7f) l = 0x7f;
610 { swf_SetBits(t,font->glyph[s[i]].gid,gbits);
611 swf_SetBits(t,(((U32)font->glyph[s[i]].advance)*scale)/100,abits);
614 swf_ResetWriteBits(t);
618 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
623 { res += font->glyph[s[0]].advance;
626 if (scale) res = (res*scale)/100;
631 void swf_WriteFont(SWFFONT*font, char* filename, int useDefineFont2)
639 fprintf(stderr, "DefineFont2 is not yet supported!\n");
643 font->id = WRITEFONTID; //"FN"
645 memset(&swf,0x00,sizeof(SWF));
648 swf.frameRate = 0x4000;
649 swf.movieSize.xmax = 20*640;
650 swf.movieSize.ymax = 20*480;
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 */
658 t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
664 t = swf_InsertTag(t,ST_DEFINEFONT);
668 t = swf_InsertTag(NULL,ST_DEFINEFONT);
672 swf_FontSetDefine(t,font);
674 t = swf_InsertTag(t,ST_DEFINEFONTINFO);
675 swf_FontSetInfo(t,font);
682 int ymax = textscale * 20;
690 if(font->glyph[s].advance*textscale/100 > xmax)
691 xmax = font->glyph[s].advance*textscale/100;
693 swf.movieSize.xmax = xmax*20;
694 swf.movieSize.ymax = ymax;
696 t = swf_InsertTag(t,ST_DEFINETEXT);
698 swf_SetU16(t,font->id+1); // ID
702 r.xmax = swf.movieSize.xmax*20;
703 r.ymax = swf.movieSize.ymax;
707 swf_SetMatrix(t,NULL);
709 abits = swf_CountBits(xmax*16, 0);
720 int c=0,lastx=-1, firstx=0;
722 if(font->glyph[y*16+x].shape) {
729 swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y);
732 if(font->glyph[y*16+x].shape) {
733 if(lastx != x*xmax) {
734 swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
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);
747 t = swf_InsertTag(t,ST_PLACEOBJECT2);
749 swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
751 t = swf_InsertTag(t,ST_SHOWFRAME);
754 t = swf_InsertTag(t,ST_END);
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");
763 SWFFONT* swf_ReadFont(char* filename)
769 f = open(filename,O_RDONLY);
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);
779 if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)