X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fmodules%2Fswftext.c;h=fb708fa84b7677c9b64dc932f11009c109689de8;hb=51c19ac56edb61ae987df0488bb8cd0f8884b37e;hp=1b770242593d01bb28fe99a8ccdf7f78b79a6ed2;hpb=07b215b2a0b442a8f9b832b9ff94755bb6191d48;p=swftools.git diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index 1b77024..fb708fa 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -24,6 +24,20 @@ #define FF_SHIFTJIS 0x10 #define FF_UNICODE 0x20 +#define FF2_BOLD 0x01 +#define FF2_ITALIC 0x02 +#define FF2_WIDECODES 0x04 +#define FF2_WIDEOFFSETS 0x08 +#define FF2_ANSI 0x10 +#define FF2_UNICODE 0x20 +#define FF2_SHIFTJIS 0x40 +#define FF2_LAYOUT 0x80 + +int swf_FontIsItalic(SWFFONT * f) { return f->version==2?f->flags&FF2_ITALIC:f->flags&FF_ITALIC; } +int swf_FontIsBold(SWFFONT * f) { return f->version==2?f->flags&FF2_BOLD:f->flags&FF_BOLD; } + +static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont + int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*)) { int n; TAG * t; @@ -32,7 +46,8 @@ int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*)) n = 0; while (t) - { if (swf_GetTagID(t)==ST_DEFINEFONTINFO) + { if (swf_GetTagID(t)==ST_DEFINEFONTINFO || + swf_GetTagID(t)==ST_DEFINEFONT2) { n++; if (FontCallback) { U16 id; @@ -40,8 +55,10 @@ int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*)) U8 s[257]; swf_SaveTagPos(t); swf_SetTagPos(t,0); - + id = swf_GetU16(t); + if(swf_GetTagID(t) == ST_DEFINEFONT2) + swf_GetU16(t); l = swf_GetU8(t); swf_GetBlock(t,s,l); s[l] = 0; @@ -56,36 +73,46 @@ int swf_FontEnumerate(SWF * swf,void (*FontCallback) (U16,U8*)) return n; } -int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t,SHAPE * * shapes) +int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t) { U16 fid; swf_SaveTagPos(t); swf_SetTagPos(t,0); fid = swf_GetU16(t); if ((!id)||(id==fid)) - { U16 ofs[MAX_CHAR_PER_FONT]; + { U16 of,*ofs; int n,i; id = fid; + f->version = 1; f->id = fid; - ofs[0] = swf_GetU16(t); - n = ofs[0]/2; + of = swf_GetU16(t); + n = of/2; + f->numchars = n; + f->glyph = malloc(sizeof(SWFGLYPH)*n); + memset(f->glyph, 0, sizeof(SWFGLYPH)*n); - for (i=1;iglyph[i].shape); } swf_RestoreTagPos(t); return id; } -int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t,SHAPE * * shapes) +int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t) { U16 fid; + U16 maxcode; swf_SaveTagPos(t); swf_SetTagPos(t,0); + if(f->version>1) { + // DefineFont2 doesn't have FontInfo fields + fprintf(stderr, "fixme: FontInfo field for DefineFont2 encountered\n"); + return -1; + } + fid = swf_GetU16(t); if (fid==id) { U8 l = swf_GetU8(t); @@ -105,22 +132,130 @@ int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t,SHAPE * * shapes) } f->flags = swf_GetU8(t); - i = 0; - while (shapes[i]) - { U16 code = ((f->flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t))%MAX_CHAR_PER_FONT; - - f->glyph[code].shape = shapes[i]; - f->glyph[code].gid = i; - if (icodes[i] = code; - - i++; + f->glyph2ascii = (U16*)malloc(sizeof(U16)*f->numchars); + maxcode = 0; + for(i=0; i < f->numchars; i++) { + f->glyph2ascii[i] = ((f->flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t)); + if(f->glyph2ascii[i] > maxcode) + maxcode = f->glyph2ascii[i]; } + maxcode++; + if(maxcode<256) + maxcode=256; + f->maxascii = maxcode; + f->ascii2glyph = (int*)malloc(sizeof(int)*maxcode); + memset(f->ascii2glyph, -1, sizeof(int)*maxcode); + + for(i = 0; i < f->numchars; i++) + f->ascii2glyph[f->glyph2ascii[i]] = i; } swf_RestoreTagPos(t); return id; } +int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) +{ + int t, glyphcount; + int maxcode; + int fid; + U8 flags1,flags2,namelen; + swf_SaveTagPos(tag); + swf_SetTagPos(tag,0); + font->version=2; + fid = swf_GetU16(tag); + if(id && id!=fid) + return; + font->id = fid; + flags1 = swf_GetU8(tag); + flags2 = swf_GetU8(tag); //reserved flags + namelen = swf_GetU8(tag); + font->flags = flags1; + font->name = (U8*)malloc(namelen+1); + font->name[namelen]=0; + swf_GetBlock(tag, font->name, namelen); + font->version = 2; + glyphcount = swf_GetU16(tag); + font->numchars = glyphcount; + + font->glyph = (SWFGLYPH*)malloc(sizeof(SWFGLYPH)*glyphcount); + memset(font->glyph, 0, sizeof(SWFGLYPH)*glyphcount); + font->glyph2ascii = (U16*)malloc(sizeof(U16)*glyphcount); + memset(font->glyph2ascii, 0, sizeof(U16)*glyphcount); + + if(flags1&8) { // wide offsets + for(t=0;tglyph[t].shape)); + + maxcode = 0; + for(t=0;tglyph2ascii[t] = code; + if(code > maxcode) + maxcode = code; + } + maxcode++; + if(maxcode<256) + maxcode=256; + font->maxascii = maxcode; + font->ascii2glyph = (int*)malloc(sizeof(int)*maxcode); + memset(font->ascii2glyph, -1, sizeof(int)*maxcode); + for(t=0;tascii2glyph[font->glyph2ascii[t]] = t; + } + + if(flags1&128) { // has layout + U16 kerningcount; + font->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT)); + font->layout->ascent=swf_GetU16(tag); + font->layout->descent=swf_GetU16(tag); + font->layout->leading=swf_GetU16(tag); + for(t=0;tglyph[t].advance = advance; + } + font->layout->bounds = malloc(glyphcount*sizeof(SRECT)); + for(t=0;tlayout->bounds); + } + kerningcount = swf_GetU16(tag); + font->layout->kerningcount = kerningcount; + font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount); + if(kerningcount) { + font->layout->kerning = + malloc(sizeof(*font->layout->kerning)* kerningcount); + for(t=0;tlayout->kerning[t].char1 = swf_GetU16(tag); + font->layout->kerning[t].char2 = swf_GetU16(tag); + } else { + font->layout->kerning[t].char1 = swf_GetU8(tag); + font->layout->kerning[t].char2 = swf_GetU8(tag); + } + font->layout->kerning[t].adjustment = swf_GetS16(tag); + } + } + } + swf_RestoreTagPos(t); + return font->id; +} + + #define FEDTJ_PRINT 0x01 #define FEDTJ_MODIFY 0x02 @@ -165,10 +300,10 @@ int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs) glyph = swf_GetBits(t,gbits); adv = swf_GetBits(t,abits); if (id==fid) // mitlesen ? - { int code = f->codes[glyph]; + { int code = f->glyph2ascii[glyph]; if (jobs&FEDTJ_PRINT) printf("%c",code); if (jobs&FEDTJ_MODIFY) - /*if (f->glyph[code].advance)*/ f->glyph[code].advance = adv; + /*if (!f->glyph[code].advance)*/ f->glyph[glyph].advance = adv; } } if ((id==fid)&&(jobs&FEDTJ_PRINT)) printf("\n"); @@ -183,14 +318,12 @@ int swf_FontExtract_DefineText(int id,SWFFONT * f,TAG * t,int jobs) int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) { TAG * t; SWFFONT * f; - SHAPE * shapes[MAX_CHAR_PER_FONT]; if ((!swf)||(!font)) return -1; f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f; if (!f) return -1; - memset(shapes,0x00,sizeof(shapes)); memset(f,0x00,sizeof(SWFFONT)); t = swf->firstTag; @@ -199,16 +332,20 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) { int nid = 0; switch (swf_GetTagID(t)) { case ST_DEFINEFONT: - nid = swf_FontExtract_DefineFont(id,f,t,shapes); + nid = swf_FontExtract_DefineFont(id,f,t); + break; + + case ST_DEFINEFONT2: + nid = swf_FontExtract_DefineFont2(id,f,t); break; case ST_DEFINEFONTINFO: - nid = swf_FontExtract_DefineFontInfo(id,f,t,shapes); + nid = swf_FontExtract_DefineFontInfo(id,f,t); break; case ST_DEFINETEXT: case ST_DEFINETEXT2: - nid = swf_FontExtract_DefineText(id,f,t,FEDTJ_MODIFY); + nid = swf_FontExtract_DefineText(id,f,t,f->layout?0:FEDTJ_MODIFY); break; } if (nid>0) id = nid; @@ -217,39 +354,39 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) return 0; } -int swf_FontIsItalic(SWFFONT * f) { return f->flags&FF_ITALIC; } -int swf_FontIsBold(SWFFONT * f) { return f->flags&FF_BOLD; } - int swf_FontSetID(SWFFONT * f,U16 id) { if (!f) return -1; f->id = id; return 0; } int swf_FontReduce(SWFFONT * f,FONTUSAGE * use) -{ int i,j; +{ int i,j,num; if ((!f)||(!use)) return -1; - memset(&f->codes,0x00,sizeof(f->codes)); - j = 0; - for (i=0;inumchars;i++) if (f->glyph[i].shape) - { if (use->code[i]) - { f->glyph[i].gid = j; - f->codes[j] = i; + { if (f->glyph2ascii[i]code[f->glyph2ascii[i]]) + { f->ascii2glyph[f->glyph2ascii[i]] = j; + f->glyph2ascii[j] = f->glyph2ascii[i]; + f->glyph[j] = f->glyph[i]; j++; } else { swf_ShapeFree(f->glyph[i].shape); - f->glyph[i].shape = 0; - f->glyph[i].gid = 0; + f->ascii2glyph[f->glyph2ascii[i]] = -1; + f->glyph2ascii[i] = 0; + f->glyph[i].shape = NULL; f->glyph[i].advance = 0; } - } else f->glyph[i].gid = 0; + } else f->ascii2glyph[f->glyph2ascii[i]] = -1; + + f->numchars = j; return j; } int swf_FontInitUsage(FONTUSAGE * use) { if (!use) return -1; - memset(&use->code,0x00,sizeof(use->code)); + memset(use->code,0,sizeof(use->code[0])*MAX_CHAR_PER_FONT); return 0; } @@ -263,7 +400,7 @@ int swf_FontUse(FONTUSAGE * use,U8 * s) } int swf_FontSetDefine(TAG * t,SWFFONT * f) -{ U16 ofs[MAX_CHAR_PER_FONT]; +{ U16*ofs = (U16*)malloc(f->numchars*2); int p,i,j; if ((!t)||(!f)) return -1; @@ -271,7 +408,7 @@ int swf_FontSetDefine(TAG * t,SWFFONT * f) swf_SetU16(t,f->id); p = 0; j = 0; - for (i=0;inumchars;i++) if (f->glyph[i].shape) { ofs[j++] = p; p+=swf_SetSimpleShape(NULL,f->glyph[i].shape); @@ -279,27 +416,33 @@ int swf_FontSetDefine(TAG * t,SWFFONT * f) for (i=0;inumchars;i++) if (f->glyph[i].shape) swf_SetSimpleShape(t,f->glyph[i].shape); swf_ResetWriteBits(t); + free(ofs); return 0; } int swf_FontSetInfo(TAG * t,SWFFONT * f) { int l,i; + U8 wide=0; if ((!t)||(!f)) return -1; swf_ResetWriteBits(t); swf_SetU16(t,f->id); l = strlen(f->name); if (l>255) l = 255; swf_SetU8(t,l); swf_SetBlock(t,f->name,l); - swf_SetU8(t,f->flags&0xfe); // no Wide-Codes + if(f->numchars>=256) + wide=1; + swf_SetU8(t,(f->flags&0xfe)|wide); - for (i=0;inumchars;i++) { if (f->glyph[i].shape) - swf_SetU8(t,i); + wide?swf_SetU16(t,f->glyph2ascii[i]): + swf_SetU8(t,f->glyph2ascii[i]); + } return 0; } @@ -326,14 +469,15 @@ int swf_FontExport(int handle,SWFFONT * f) { l+=sizeof(SWFLAYOUT); if (handle>=0) if (write(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) return -1; - if (f->layout->kerning.data) +/* new kerning struct. hope commenting this out doesn't break things + if (f->layout->kerning.data) { l+=f->layout->kerning.count*4; if (handle>=0) if (write(handle,f->layout->kerning.data,f->layout->kerning.count*4)!=f->layout->kerning.count*4) return -1; - } + }*/ } - for (i=0;inumchars;i++) { if (f->glyph[i].shape) { int ll = swf_ShapeExport(handle,f->glyph[i].shape); if (ll<0) return -1; @@ -344,7 +488,7 @@ int swf_FontExport(int handle,SWFFONT * f) return l; } -int FontImport(int handle,SWFFONT * * font) +int swf_FontImport(int handle,SWFFONT * * font) { SWFFONT * f; int layout; int i = 0; @@ -375,15 +519,16 @@ int FontImport(int handle,SWFFONT * * font) { f->layout = (SWFLAYOUT *)malloc(sizeof(SWFLAYOUT)); if (!f->layout) goto fehler; if (read(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) goto fehler; + /* new kerning struct. hope commenting this out doesn't break things if (f->layout->kerning.data) { int l = f->layout->kerning.count*4; f->layout->kerning.data = (U8*)malloc(l); if (!f->layout->kerning.data) goto fehler; if (read(handle,f->layout->kerning.data,l)!=l) goto fehler; - } + } */ } - for (i=0;inumchars;i++) { if (f->glyph[i].shape) { if (swf_ShapeImport(handle,&f->glyph[i].shape)<0) goto fehler; } @@ -409,8 +554,10 @@ int swf_TextPrintDefineText(TAG * t,SWFFONT * f) void swf_LayoutFree(SWFLAYOUT * l) { if (l) - { if (l->kerning.data) free(l->kerning.data); - l->kerning.data = NULL; + { if (l->kerning) free(l->kerning); + l->kerning = NULL; + if (l->bounds) free(l->bounds); + l->bounds = NULL; } free(l); } @@ -425,11 +572,23 @@ void swf_FontFree(SWFFONT * f) f->name = NULL; f->layout = NULL; - for (i=0;iglyph[i].shape) - { swf_ShapeFree(f->glyph[i].shape); - f->glyph[i].shape = NULL; - } + if(f->glyph) { + for (i=0;inumchars;i++) + if (f->glyph[i].shape) + { swf_ShapeFree(f->glyph[i].shape); + f->glyph[i].shape = NULL; + } + free(f->glyph); + f->glyph = NULL; + } + if(f->ascii2glyph) { + free(f->ascii2glyph); + f->ascii2glyph = NULL; + } + if(f->glyph2ascii) { + free(f->glyph2ascii); + f->glyph2ascii = NULL; + } } free(f); } @@ -455,12 +614,16 @@ int swf_TextSetInfoRecord(TAG * t,SWFFONT * font,U16 size,RGBA * color,S16 dx,S1 int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) { U16 g,a; - if ((!s)||(!font)||((!gbits)&&(!abits))) return -1; + if ((!s)||(!font)||((!gbits)&&(!abits))||(!font->ascii2glyph)) return -1; g = a = 0; while(s[0]) - { g = swf_CountBits(font->glyph[s[0]].gid,g); - a = swf_CountBits((((U32)font->glyph[s[0]].advance)*scale)/100,a); + { + int glyph = font->ascii2glyph[s[0]]; + if(glyph>=0) { + g = swf_CountBits(glyph,g); + a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a); + } s++; } @@ -473,15 +636,19 @@ int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) int swf_TextSetCharRecord(TAG * t,SWFFONT * font,U8 * s,int scale,U8 gbits,U8 abits) { int l,i; - if ((!t)||(!font)||(!s)) return -1; + if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1; l = strlen(s); if (l>0x7f) l = 0x7f; swf_SetU8(t,l); for (i=0;iglyph[s[i]].gid,gbits); - swf_SetBits(t,(((U32)font->glyph[s[i]].advance)*scale)/100,abits); + { + int g = font->ascii2glyph[s[i]]; + if(g>=0) { + swf_SetBits(t,g,gbits); + swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits); + } } swf_ResetWriteBits(t); @@ -493,10 +660,174 @@ U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale) if (font&&s) { while (s[0]) - { res += font->glyph[s[0]].advance; + { + int g = font->ascii2glyph[*s]; + if(g>=0) + res += font->glyph[g].advance; s++; } if (scale) res = (res*scale)/100; } return res; } + +void swf_WriteFont(SWFFONT*font, char* filename, int useDefineFont2) +{ SWF swf; + TAG * t; + SRECT r; + RGBA rgb; + int f; + + if(useDefineFont2) { + fprintf(stderr, "DefineFont2 is not yet supported!\n"); + useDefineFont2 = 0; + } + + font->id = WRITEFONTID; //"FN" + + memset(&swf,0x00,sizeof(SWF)); + + swf.fileVersion = 4; + swf.frameRate = 0x4000; + swf.movieSize.xmax = 20*640; + swf.movieSize.ymax = 20*480; + + if(!useDefineFont2) + /* if we use DefineFont1 to store the characters, + we have to build a textfield to store the + advance values. While at it, we can also + make the whole .swf viewable */ + { + t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); + swf.firstTag = t; + rgb.r = 0xff; + rgb.g = 0xff; + rgb.b = 0xff; + swf_SetRGB(t,&rgb); + t = swf_InsertTag(t,ST_DEFINEFONT); + } + else + { + t = swf_InsertTag(NULL,ST_DEFINEFONT); + swf.firstTag = t; + } + + swf_FontSetDefine(t,font); + + t = swf_InsertTag(t,ST_DEFINEFONTINFO); + swf_FontSetInfo(t,font); + + if(!useDefineFont2) + { int textscale = 400; + int s; + int xmax = 0; + int ymax = textscale * 20; + U8 gbits,abits; + char text[257]; + int x,y; + text[256]=0; + for(s=0;s<256;s++) + { + int g = font->ascii2glyph[s]; + text[s] = s; + if(g>=0) { + if(font->glyph[g].advance*textscale/100 > xmax) + xmax = font->glyph[g].advance*textscale/100; + } + } + swf.movieSize.xmax = xmax*20; + swf.movieSize.ymax = ymax; + + t = swf_InsertTag(t,ST_DEFINETEXT); + + swf_SetU16(t,font->id+1); // ID + + r.xmin = 0; + r.ymin = 0; + r.xmax = swf.movieSize.xmax*20; + r.ymax = swf.movieSize.ymax; + + swf_SetRect(t,&r); + + swf_SetMatrix(t,NULL); + + abits = swf_CountBits(xmax*16, 0); + gbits = 8; + + swf_SetU8(t,gbits); + swf_SetU8(t,abits); + + rgb.r = 0x00; + rgb.g = 0x00; + rgb.b = 0x00; + for(y=0;y<16;y++) + { + int c=0,lastx=-1, firstx=0; + for(x=0;x<16;x++) { + int g = font->ascii2glyph[y*16+x]; + if(g>=0 && font->glyph[g].shape) { + c++; + if(lastx<0) + lastx = x*xmax; + } + } + if(c) { + swf_TextSetInfoRecord(t,font,textscale,&rgb,lastx+1,textscale*y); + for(x=0;x<16;x++) + { + int g = font->ascii2glyph[y*16+x]; + if(g>=0 && font->glyph[g].shape) { + if(lastx != x*xmax) { + swf_TextSetInfoRecord(t,0,0,0,x*xmax+1,0); + } + swf_SetU8(t,1); + swf_SetBits(t, g, gbits); + swf_SetBits(t, font->glyph[g].advance, abits); + lastx = x*xmax+font->glyph[g].advance; + swf_ResetWriteBits(t); + } + } + } + } + swf_SetU8(t,0); + + + t = swf_InsertTag(t,ST_PLACEOBJECT2); + + swf_ObjectPlace(t,font->id+1,1,NULL,NULL,NULL); + + t = swf_InsertTag(t,ST_SHOWFRAME); + } + + t = swf_InsertTag(t,ST_END); + + f = open(filename, O_RDWR|O_CREAT|O_TRUNC,0644); + if FAILED(swf_WriteSWF(f,&swf)) fprintf(stderr,"WriteSWF() failed in writeFont().\n"); + close(f); + + swf_FreeTags(&swf); +} + +SWFFONT* swf_ReadFont(char* filename) +{ + int f; + SWF swf; + if(!filename) + return 0; + f = open(filename,O_RDONLY); + + if (f<0 || swf_ReadSWF(f,&swf)<0) + { fprintf(stderr,"%s is not a valid SWF font file or contains errors.\n",filename); + close(f); + return 0; + } + else + { SWFFONT*font; + close(f); + if(swf_FontExtract(&swf, WRITEFONTID, &font) < 0) + return 0; + swf_FreeTags(&swf); + return font; + } +} +