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 ||
50 swf_GetTagID(t)==ST_DEFINEFONT2)
60 if(swf_GetTagID(t) == ST_DEFINEFONT2)
76 int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t)
93 f->glyph = malloc(sizeof(SWFGLYPH)*n);
94 memset(f->glyph, 0, sizeof(SWFGLYPH)*n);
96 for (i=1;i<n;i++) swf_GetU16(t);
97 for (i=0;i<n;i++) swf_GetSimpleShape(t,&f->glyph[i].shape);
100 swf_RestoreTagPos(t);
104 int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t)
111 // DefineFont2 doesn't have FontInfo fields
112 fprintf(stderr, "fixme: FontInfo field for DefineFont2 encountered\n");
118 { U8 l = swf_GetU8(t);
122 { if (f->name) free(f->name);
123 f->name = (U8*)malloc(l+1);
125 { swf_GetBlock(t,f->name,l);
129 { swf_RestoreTagPos(t);
133 f->flags = swf_GetU8(t);
135 f->glyph2ascii = (U16*)malloc(sizeof(U16)*f->numchars);
137 for(i=0; i < f->numchars; i++) {
138 f->glyph2ascii[i] = ((f->flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t));
139 if(f->glyph2ascii[i] > maxcode)
140 maxcode = f->glyph2ascii[i];
145 f->maxascii = maxcode;
146 f->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
147 memset(f->ascii2glyph, -1, sizeof(int)*maxcode);
149 for(i = 0; i < f->numchars; i++)
150 f->ascii2glyph[f->glyph2ascii[i]] = i;
153 swf_RestoreTagPos(t);
157 int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag)
162 U8 flags1,flags2,namelen;
164 swf_SetTagPos(tag,0);
166 fid = swf_GetU16(tag);
170 flags1 = swf_GetU8(tag);
171 flags2 = swf_GetU8(tag); //reserved flags
172 namelen = swf_GetU8(tag);
173 font->flags = flags1;
174 font->name = (U8*)malloc(namelen+1);
175 font->name[namelen]=0;
176 swf_GetBlock(tag, font->name, namelen);
178 glyphcount = swf_GetU16(tag);
179 font->numchars = glyphcount;
181 font->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*glyphcount);
182 memset(font->glyph, 0, sizeof(SWFGLYPH)*glyphcount);
183 font->glyph2ascii = (U16*)malloc(sizeof(U16)*glyphcount);
184 memset(font->glyph2ascii, 0, sizeof(U16)*glyphcount);
186 if(flags1&8) { // wide offsets
187 for(t=0;t<glyphcount;t++)
188 swf_GetU32(tag); //offset[t]
189 swf_GetU32(tag); // fontcodeoffset
191 for(t=0;t<glyphcount;t++)
192 swf_GetU16(tag); //offset[t]
193 swf_GetU16(tag); // fontcodeoffset
195 for(t=0;t<glyphcount;t++)
196 swf_GetSimpleShape(tag,&(font->glyph[t].shape));
199 for(t=0;t<glyphcount;t++) {
201 if(flags1&4) // wide codes
202 code = swf_GetU16(tag);
204 code = swf_GetU8(tag);
205 font->glyph2ascii[t] = code;
212 font->maxascii = maxcode;
213 font->ascii2glyph = (int*)malloc(sizeof(int)*maxcode);
214 memset(font->ascii2glyph, -1, sizeof(int)*maxcode);
215 for(t=0;t<glyphcount;t++)
217 font->ascii2glyph[font->glyph2ascii[t]] = t;
220 if(flags1&128) { // has layout
222 font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT));
223 font->layout->ascent=swf_GetU16(tag);
224 font->layout->descent=swf_GetU16(tag);
225 font->layout->leading=swf_GetU16(tag);
226 for(t=0;t<glyphcount;t++) {
227 S16 advance = swf_GetS16(tag);
228 font->glyph[t].advance = advance;
230 font->layout->bounds = malloc(glyphcount*sizeof(SRECT));
231 for(t=0;t<glyphcount;t++) {
232 swf_ResetReadBits(tag);
233 swf_GetRect(tag, font->layout->bounds);
235 kerningcount = swf_GetU16(tag);
236 font->layout->kerningcount = kerningcount;
237 font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount);
239 font->layout->kerning =
240 malloc(sizeof(*font->layout->kerning)* kerningcount);
241 for(t=0;t<kerningcount;t++)
243 if(flags1&4) { // wide codes
244 font->layout->kerning[t].char1 = swf_GetU16(tag);
245 font->layout->kerning[t].char2 = swf_GetU16(tag);
247 font->layout->kerning[t].char1 = swf_GetU8(tag);
248 font->layout->kerning[t].char2 = swf_GetU8(tag);
250 font->layout->kerning[t].adjustment = swf_GetS16(tag);
254 swf_RestoreTagPos(t);
259 #define FEDTJ_PRINT 0x01
260 #define FEDTJ_MODIFY 0x02
261 #define FEDTJ_CALLBACK 0x04
263 int swf_FontExtract_DefineTextCallback(int id,SWFFONT * f,TAG * t,int jobs,
264 void(*callback)(int*chars, int nr, int fontid))
268 U8 gbits, abits, flags;
279 gbits = swf_GetU8(t);
280 abits = swf_GetU8(t);
282 flags = swf_GetU8(t);
285 { if (flags&TF_TEXTCONTROL)
286 { if (flags&TF_HASFONT) fid = swf_GetU16(t);
287 if (flags&TF_HASCOLOR)
288 { swf_GetU8(t); // rgb
291 if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_GetU8(t);
293 if (flags&TF_HASXOFFSET) swf_GetS16(t);
294 if (flags&TF_HASYOFFSET) swf_GetS16(t);
295 if (flags&TF_HASFONT) swf_GetU16(t);
300 for (i=0;i<flags;i++)
303 glyph = swf_GetBits(t,gbits);
304 adv = swf_GetBits(t,abits);
305 if (id==fid) // mitlesen ?
306 { int code = f->glyph2ascii[glyph];
307 if (jobs&FEDTJ_PRINT) printf("%c",code);
308 if (jobs&FEDTJ_MODIFY)
309 /*if (!f->glyph[code].advance)*/ f->glyph[glyph].advance = adv;
313 if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n");
314 if (jobs&FEDTJ_CALLBACK)
315 callback(buf, flags, fid);
317 flags = swf_GetU8(t);
320 swf_RestoreTagPos(t);
324 int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs)
326 return swf_FontExtract_DefineTextCallback(id,f,t,jobs,0);
329 int swf_FontExtract(SWF * swf,int id,SWFFONT * * font)
333 if ((!swf)||(!font)) return -1;
335 f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
338 memset(f,0x00,sizeof(SWFFONT));
344 switch (swf_GetTagID(t))
345 { case ST_DEFINEFONT:
346 nid = swf_FontExtract_DefineFont(id,f,t);
350 nid = swf_FontExtract_DefineFont2(id,f,t);
353 case ST_DEFINEFONTINFO:
354 nid = swf_FontExtract_DefineFontInfo(id,f,t);
359 nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY);
368 int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; }
370 int swf_FontReduce(SWFFONT * f,FONTUSAGE * use)
372 if ((!f)||(!use)) return -1;
375 for (i=0;i<f->numchars;i++)
376 if (f->glyph[i].shape)
377 { if (f->glyph2ascii[i]<MAX_CHAR_PER_FONT &&
378 use->code[f->glyph2ascii[i]])
379 { f->ascii2glyph[f->glyph2ascii[i]] = j;
380 f->glyph2ascii[j] = f->glyph2ascii[i];
381 f->glyph[j] = f->glyph[i];
385 { swf_ShapeFree(f->glyph[i].shape);
386 f->ascii2glyph[f->glyph2ascii[i]] = -1;
387 f->glyph2ascii[i] = 0;
388 f->glyph[i].shape = NULL;
389 f->glyph[i].advance = 0;
391 } else f->ascii2glyph[f->glyph2ascii[i]] = -1;
398 int swf_FontInitUsage(FONTUSAGE * use)
399 { if (!use) return -1;
400 memset(use->code,0,sizeof(use->code[0])*MAX_CHAR_PER_FONT);
404 int swf_FontUse(FONTUSAGE * use,U8 * s)
405 { if ((!use)||(!s)) return -1;
407 { use->code[s[0]] = 1;
413 int swf_FontSetDefine(TAG * t,SWFFONT * f)
414 { U16*ofs = (U16*)malloc(f->numchars*2);
417 if ((!t)||(!f)) return -1;
418 swf_ResetWriteBits(t);
422 for (i=0;i<f->numchars;i++)
423 if (f->glyph[i].shape)
425 p+=swf_SetSimpleShape(NULL,f->glyph[i].shape);
428 for (i=0;i<j;i++) swf_SetU16(t,ofs[i]+j*2);
430 for (i=0;i<f->numchars;i++)
431 if (f->glyph[i].shape)
432 swf_SetSimpleShape(t,f->glyph[i].shape);
434 swf_ResetWriteBits(t);
439 int swf_FontSetInfo(TAG * t,SWFFONT * f)
442 if ((!t)||(!f)) return -1;
443 swf_ResetWriteBits(t);
445 l = strlen(f->name); if (l>255) l = 255;
447 swf_SetBlock(t,f->name,l);
450 swf_SetU8(t,(f->flags&0xfe)|wide);
452 for (i=0;i<f->numchars;i++) {
453 if (f->glyph[i].shape)
454 wide?swf_SetU16(t,f->glyph2ascii[i]):
455 swf_SetU8(t,f->glyph2ascii[i]);
461 int swf_FontExport(int handle,SWFFONT * f)
468 if (write(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) return -1;
471 { U16 ln = strlen(f->name);
474 { if (write(handle,&ln,2)!=2) return -1;
475 if (write(handle,f->name,ln)!=ln) return -1;
480 { l+=sizeof(SWFLAYOUT);
482 if (write(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) return -1;
483 /* new kerning struct. hope commenting this out doesn't break things
484 if (f->layout->kerning.data)
485 { l+=f->layout->kerning.count*4;
487 if (write(handle,f->layout->kerning.data,f->layout->kerning.count*4)!=f->layout->kerning.count*4) return -1;
491 for (i=0;i<f->numchars;i++)
492 { if (f->glyph[i].shape)
493 { int ll = swf_ShapeExport(handle,f->glyph[i].shape);
502 int swf_FontImport(int handle,SWFFONT * * font)
507 if ((!font)||(handle<0)) return -1;
509 f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f;
512 memset(f,0x00,sizeof(SWFFONT));
514 if (read(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) goto fehler;
516 layout = (f->layout)?1:0; // avoid illegal free()
522 if (read(handle,&ln,2)!=2) goto fehler;
523 f->name = (U8*)malloc(ln+1);
524 if (!f->name) goto fehler;
525 if (read(handle,f->name,ln)!=ln) goto fehler;
530 { f->layout = (SWFLAYOUT *)malloc(sizeof(SWFLAYOUT));
531 if (!f->layout) goto fehler;
532 if (read(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) goto fehler;
533 /* new kerning struct. hope commenting this out doesn't break things
534 if (f->layout->kerning.data)
535 { int l = f->layout->kerning.count*4;
536 f->layout->kerning.data = (U8*)malloc(l);
537 if (!f->layout->kerning.data) goto fehler;
538 if (read(handle,f->layout->kerning.data,l)!=l) goto fehler;
542 for (i=0;i<f->numchars;i++)
543 { if (f->glyph[i].shape)
544 { if (swf_ShapeImport(handle,&f->glyph[i].shape)<0) goto fehler;
553 if (f) for (;i<MAX_CHAR_PER_FONT;i++) f->glyph[i].shape = NULL;
559 int swf_TextPrintDefineText(TAG * t,SWFFONT * f)
560 { int id = swf_GetTagID(t);
561 if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT);
566 void swf_LayoutFree(SWFLAYOUT * l)
568 { if (l->kerning) free(l->kerning);
570 if (l->bounds) free(l->bounds);
576 void swf_FontFree(SWFFONT * f)
580 if (f->name) free(f->name);
581 if (f->layout) swf_LayoutFree(f->layout);
587 for (i=0;i<f->numchars;i++)
588 if (f->glyph[i].shape)
589 { swf_ShapeFree(f->glyph[i].shape);
590 f->glyph[i].shape = NULL;
596 free(f->ascii2glyph);
597 f->ascii2glyph = NULL;
600 free(f->glyph2ascii);
601 f->glyph2ascii = NULL;
607 int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S16 dy)
611 flags = TF_TEXTCONTROL|(font?TF_HASFONT:0)|(color?TF_HASCOLOR:0)|(dx?TF_HASXOFFSET:0)|(dy?TF_HASYOFFSET:0);
614 if (font) swf_SetU16(t,font->id);
616 { if (swf_GetTagID(t)==ST_DEFINETEXT2) swf_SetRGBA(t,color);
617 else swf_SetRGB(t,color);
619 if (dx) swf_SetS16(t,dx);
620 if (dy) swf_SetS16(t,dy);
621 if (font) swf_SetU16(t,size);
626 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits)
628 if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1;
633 int glyph = font->ascii2glyph[s[0]];
635 g = swf_CountBits(glyph,g);
636 a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a);
641 if (gbits) gbits[0] = (U8)g;
642 if (abits) abits[0] = (U8)a;
647 int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits)
650 if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1;
653 if (l>0x7f) l = 0x7f;
658 int g = font->ascii2glyph[s[i]];
660 swf_SetBits(t,g,gbits);
661 swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits);
665 swf_ResetWriteBits(t);
669 U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale)
675 int g = font->ascii2glyph[*s];
677 res += font->glyph[g].advance;
680 if (scale) res = (res*scale)/100;
685 SWFFONT* swf_ReadFont(char* filename)
691 f = open(filename,O_RDONLY);
693 if (f<0 || swf_ReadSWF(f,&swf)<0)
694 { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename);
701 if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0)
708 void swf_WriteFont(SWFFONT*font, char* filename)
714 int useDefineFont2 = 1;
717 //fprintf(stderr, "DefineFont2 is not yet supported!\n");
721 font->id = WRITEFONTID; //"FN"
723 memset(&swf,0x00,sizeof(SWF));
726 swf.frameRate = 0x4000;
727 swf.movieSize.xmax = 20*640;
728 swf.movieSize.ymax = 20*480;
731 /* if we use DefineFont1 to store the characters,
732 we have to build a textfield to store the
733 advance values. While at it, we can also
734 make the whole .swf viewable */
736 t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
742 t = swf_InsertTag(t,ST_DEFINEFONT);
746 t = swf_InsertTag(NULL,ST_DEFINEFONT);
750 swf_FontSetDefine(t,font);
752 t = swf_InsertTag(t,ST_DEFINEFONTINFO);
753 swf_FontSetInfo(t,font);
756 { int textscale = 400;
759 int ymax = textscale * 2 * 20;
766 int g = font->ascii2glyph[s];
769 if(font->glyph[g].advance*textscale/100 > xmax)
770 xmax = font->glyph[g].advance*textscale/100;
773 swf.movieSize.xmax = xmax*20;
774 swf.movieSize.ymax = ymax;
776 t = swf_InsertTag(t,ST_DEFINETEXT);
778 swf_SetU16(t,font->id+1); // ID
782 r.xmax = swf.movieSize.xmax*20;
783 r.ymax = swf.movieSize.ymax;
787 swf_SetMatrix(t,NULL);
789 abits = swf_CountBits(xmax*16, 0);
800 int c=0,lastx=-1, firstx=0;
802 int g = font->ascii2glyph[y*16+x];
803 if(g>=0 && font->glyph[g].shape) {
810 swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y*2);
813 int g = font->ascii2glyph[y*16+x];
814 if(g>=0 && font->glyph[g].shape) {
815 if(lastx != x*xmax) {
816 swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0);
819 swf_SetBits(t, g, gbits);
820 swf_SetBits(t, font->glyph[g].advance, abits);
821 lastx = x*xmax+font->glyph[g].advance;
822 swf_ResetWriteBits(t);
830 t = swf_InsertTag(t,ST_PLACEOBJECT2);
832 swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL);
834 t = swf_InsertTag(t,ST_SHOWFRAME);
837 t = swf_InsertTag(t,ST_END);
839 f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644);
840 if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n");