X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fmodules%2Fswftext.c;h=10b04fc3b7cadd0a3e3f8c1827c379e4d8b58dfd;hb=8c202278a45cb308cbb8df21f0bf6b1cc931b77f;hp=411ab9d829d4aa18911a9bad050fd092ce8a9674;hpb=138f9803b5b4d091a6ac75487a21858a5bbbcb9f;p=swftools.git diff --git a/lib/modules/swftext.c b/lib/modules/swftext.c index 411ab9d..10b04fc 100644 --- a/lib/modules/swftext.c +++ b/lib/modules/swftext.c @@ -33,8 +33,8 @@ #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; } +int swf_FontIsItalic(SWFFONT * f) { return f->style&FONT_STYLE_ITALIC;} +int swf_FontIsBold(SWFFONT * f) { return f->style&FONT_STYLE_BOLD;} static const int WRITEFONTID = 0x4e46; // font id for WriteFont and ReadFont @@ -46,7 +46,7 @@ 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_DEFINEFONTINFO2 || swf_GetTagID(t)==ST_DEFINEFONT2) { n++; if (FontCallback) @@ -80,7 +80,7 @@ int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t) fid = swf_GetU16(t); if ((!id)||(id==fid)) - { U16 of,*ofs; + { U16 of; int n,i; id = fid; @@ -104,39 +104,48 @@ int swf_FontExtract_DefineFont(int id,SWFFONT * f,TAG * t) int swf_FontExtract_DefineFontInfo(int id,SWFFONT * f,TAG * t) { U16 fid; U16 maxcode; + U8 flags; swf_SaveTagPos(t); swf_SetTagPos(t,0); - fid = swf_GetU16(t); if (fid==id) { U8 l = swf_GetU8(t); int i; if(f->version>1) { - // DefineFont2 doesn't have FontInfo fields - fprintf(stderr, "fixme: FontInfo field for DefineFont2 encountered\n"); - return -1; + /* Especially with Flash MX, DefineFont2 may have FontInfo fields, + too. However, they only add little information to what's already + inside the DefineFont2 tag */ + return id; } - if (l) - { if (f->name) free(f->name); - f->name = (U8*)malloc(l+1); - if (f->name) - { swf_GetBlock(t,f->name,l); - f->name[l] = 0; - } - else - { swf_RestoreTagPos(t); - return -1; - } + if (f->name) free(f->name); + + f->name = (U8*)malloc(l+1); + swf_GetBlock(t,f->name,l); + f->name[l] = 0; + + flags = swf_GetU8(t); + if(flags & 2) + f->style |= FONT_STYLE_BOLD; + if(flags & 4) + f->style |= FONT_STYLE_ITALIC; + if(flags & 8) + f->encoding |= FONT_ENCODING_ANSI; + if(flags & 16) + f->encoding |= FONT_ENCODING_SHIFTJIS; + if(flags & 32) + f->encoding |= FONT_ENCODING_UNICODE; + + if(t->id == ST_DEFINEFONTINFO2) { + f->language = swf_GetU8(t); } - f->flags = swf_GetU8(t); 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)); + f->glyph2ascii[i] = ((flags&FF_WIDECODES)?swf_GetU16(t):swf_GetU8(t)); if(f->glyph2ascii[i] > maxcode) maxcode = f->glyph2ascii[i]; } @@ -170,8 +179,19 @@ int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) font->id = fid; flags1 = swf_GetU8(tag); flags2 = swf_GetU8(tag); //reserved flags + + if(flags1 & 1) + font->style |= FONT_STYLE_BOLD; + if(flags1 & 2) + font->style |= FONT_STYLE_ITALIC; + if(flags1 & 16) + font->encoding |= FONT_ENCODING_ANSI; + if(flags1 & 32) + font->encoding |= FONT_ENCODING_UNICODE; + if(flags1 & 64) + font->encoding |= FONT_ENCODING_SHIFTJIS; + namelen = swf_GetU8(tag); - font->flags = flags1; font->name = (U8*)malloc(namelen+1); font->name[namelen]=0; swf_GetBlock(tag, font->name, namelen); @@ -187,11 +207,15 @@ int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) if(flags1&8) { // wide offsets for(t=0;tglyph[t].shape)); @@ -231,10 +255,12 @@ int swf_FontExtract_DefineFont2(int id,SWFFONT * font,TAG * tag) font->layout->bounds = malloc(glyphcount*sizeof(SRECT)); for(t=0;tlayout->bounds); + swf_GetRect(tag, &font->layout->bounds[t]); } + kerningcount = swf_GetU16(tag); font->layout->kerningcount = kerningcount; + font->layout->kerning = (SWFKERNING*)malloc(sizeof(SWFKERNING)*kerningcount); if(kerningcount) { font->layout->kerning = @@ -335,9 +361,7 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) if ((!swf)||(!font)) return -1; - f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f; - if (!f) return -1; - + f = (SWFFONT *)malloc(sizeof(SWFFONT)); memset(f,0x00,sizeof(SWFFONT)); t = swf->firstTag; @@ -354,6 +378,7 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) break; case ST_DEFINEFONTINFO: + case ST_DEFINEFONTINFO2: nid = swf_FontExtract_DefineFontInfo(id,f,t); break; @@ -365,13 +390,18 @@ int swf_FontExtract(SWF * swf,int id,SWFFONT * * font) if (nid>0) id = nid; t = swf_NextTag(t); } + if(f->id != id) { + free(f); + f=0; + } + font[0] = f; return 0; } 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,num; +{ int i,j; if ((!f)||(!use)) return -1; j = 0; @@ -429,6 +459,10 @@ int swf_FontSetDefine(TAG * t,SWFFONT * f) } for (i=0;inumchars;i++) if (f->glyph[i].shape) @@ -439,18 +473,130 @@ int swf_FontSetDefine(TAG * t,SWFFONT * f) return 0; } +int swf_FontSetDefine2(TAG *tag, SWFFONT * f) +{ + U8 flags = 0; + int t; + int pos; + int pos2; + swf_SetU16(tag, f->id); + if(f->layout) + flags |= 128; // haslayout + if(f->numchars>256) + flags |= 4; // widecodes + if(f->style & FONT_STYLE_BOLD) + flags |= 1; // bold + if(f->style & FONT_STYLE_ITALIC) + flags |= 2; // italic + /* wideoffs 8 */ + if(f->encoding & FONT_ENCODING_ANSI) + flags |= 16; // ansi + if(f->encoding & FONT_ENCODING_UNICODE) + flags |= 32; // unicode + if(f->encoding & FONT_ENCODING_SHIFTJIS) + flags |= 64; // shiftjis + + swf_SetU8(tag, flags); + swf_SetU8(tag, 0); //reserved flags + if(f->name) { + /* font name */ + swf_SetU8(tag, strlen(f->name)); + swf_SetBlock(tag, f->name, strlen(f->name)); + } else { + /* font name (="") */ + swf_SetU8(tag, 0); /*placeholder*/ + } + /* number of glyphs */ + swf_SetU16(tag, f->numchars); + /* font offset table */ + pos = tag->len; + for(t=0;tnumchars;t++) + { + swf_SetU16(tag, /* fontoffset */ 0); /*placeholder*/ + } + pos2 = tag->len; + swf_SetU16(tag, 0); //fontcode-fontoffset + for(t=0;tnumchars;t++) { + tag->data[pos + t*2] = (tag->len-pos); + tag->data[pos + t*2 + 1] = (tag->len-pos) >> 8; + swf_SetSimpleShape(tag, f->glyph[t].shape); + } + + tag->data[pos2] = tag->len - pos; + tag->data[pos2 + 1] = (tag->len - pos) >> 8; + + /* font code table */ + if(flags & 4) /* wide codes */ { + for(t=0;tnumchars;t++) + swf_SetU16(tag,f->glyph2ascii[t]); + } else { + for(t=0;tnumchars;t++) + swf_SetU8(tag,f->glyph2ascii[t]); + } + if(f->layout) + { + swf_SetU16(tag,f->layout->ascent); + swf_SetU16(tag,f->layout->descent); + swf_SetU16(tag,f->layout->leading); + for(t=0;tnumchars;t++) + swf_SetU16(tag,f->glyph[t].advance); + for(t=0;tnumchars;t++) { + swf_ResetWriteBits(tag); + swf_SetRect(tag,&f->layout->bounds[t]); + } + swf_SetU16(tag, f->layout->kerningcount); + for(t=0;tlayout->kerningcount;t++) { + if(flags & 4) /* wide codes */ { + swf_SetU8(tag,f->layout->kerning[t].char1); + swf_SetU8(tag,f->layout->kerning[t].char2); + } else { + swf_SetU16(tag,f->layout->kerning[t].char1); + swf_SetU16(tag,f->layout->kerning[t].char2); + } + swf_SetU16(tag,f->layout->kerning[t].adjustment); + } + } + return 0; +} + +void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading) +{ + f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT)); + f->layout->ascent = ascent; + f->layout->descent = descent; + f->layout->leading = leading; + f->layout->kerningcount = 0; + f->layout->kerning = 0; + f->layout->bounds = (SRECT*)malloc(sizeof(SRECT)*f->numchars); + memset(f->layout->bounds, 0, sizeof(SRECT)*f->numchars); +} + int swf_FontSetInfo(TAG * t,SWFFONT * f) { int l,i; U8 wide=0; + U8 flags = 0; if ((!t)||(!f)) return -1; swf_ResetWriteBits(t); swf_SetU16(t,f->id); - l = strlen(f->name); if (l>255) l = 255; + l = f->name?strlen(f->name):0; if (l>255) l = 255; swf_SetU8(t,l); - swf_SetBlock(t,f->name,l); + if(l) + swf_SetBlock(t,f->name,l); if(f->numchars>=256) wide=1; - swf_SetU8(t,(f->flags&0xfe)|wide); + + if(f->style & FONT_STYLE_BOLD) + flags |= 2; + if(f->style & FONT_STYLE_ITALIC) + flags |= 4; + if(f->style & FONT_ENCODING_ANSI) + flags |= 8; + if(f->style & FONT_ENCODING_SHIFTJIS) + flags |= 16; + if(f->style & FONT_ENCODING_UNICODE) + flags |= 32; + + swf_SetU8(t,(flags&0xfe)|wide); for (i=0;inumchars;i++) { if (f->glyph[i].shape) @@ -461,104 +607,6 @@ int swf_FontSetInfo(TAG * t,SWFFONT * f) return 0; } -int swf_FontExport(int handle,SWFFONT * f) -{ int l; - int i; - if (!f) return 0; - - l = sizeof(SWFFONT); - if (handle>=0) - if (write(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) return -1; - - if (f->name) - { U16 ln = strlen(f->name); - l+=2+ln; - if (handle>=0) - { if (write(handle,&ln,2)!=2) return -1; - if (write(handle,f->name,ln)!=ln) return -1; - } - } - - if (f->layout) - { l+=sizeof(SWFLAYOUT); - if (handle>=0) - if (write(handle,f->layout,sizeof(SWFLAYOUT))!=sizeof(SWFLAYOUT)) return -1; -/* 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; - l+=ll; - } - } - - return l; -} - -int swf_FontImport(int handle,SWFFONT * * font) -{ SWFFONT * f; - int layout; - int i = 0; - - if ((!font)||(handle<0)) return -1; - - f = (SWFFONT *)malloc(sizeof(SWFFONT)); font[0] = f; - if (!f) return -1; - - memset(f,0x00,sizeof(SWFFONT)); - - if (read(handle,f,sizeof(SWFFONT))!=sizeof(SWFFONT)) goto fehler; - - layout = (f->layout)?1:0; // avoid illegal free() - f->layout = NULL; - - if (f->name) - { U16 ln; - f->name = NULL; - if (read(handle,&ln,2)!=2) goto fehler; - f->name = (U8*)malloc(ln+1); - if (!f->name) goto fehler; - if (read(handle,f->name,ln)!=ln) goto fehler; - f->name[ln] = 0; - } - - if (f->layout) - { 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; - } - } - - f->id = 0; - - return 0; - -fehler: - if (f) for (;iglyph[i].shape = NULL; - swf_FontFree(f); - font[0] = NULL; - return -1; -} - int swf_TextPrintDefineText(TAG * t,SWFFONT * f) { int id = swf_GetTagID(t); if ((id==ST_DEFINETEXT)||(id==ST_DEFINETEXT2)) swf_FontExtract_DefineText(f->id,f,t,FEDTJ_PRINT); @@ -633,7 +681,9 @@ int swf_TextCountBits(SWFFONT * font,U8 * s,int scale,U8 * gbits,U8 * abits) while(s[0]) { - int glyph = font->ascii2glyph[s[0]]; + int glyph = -1; + if(s[0] < font->maxascii) + glyph = font->ascii2glyph[s[0]]; if(glyph>=0) { g = swf_CountBits(glyph,g); a = swf_CountBits((((U32)font->glyph[glyph].advance)*scale)/100,a); @@ -648,23 +698,29 @@ 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; +{ int l=0,i,pos; if ((!t)||(!font)||(!s)||(!font->ascii2glyph)) return -1; - l = strlen(s); - if (l>0x7f) l = 0x7f; - swf_SetU8(t,l); + pos = t->len; + swf_SetU8(t, l); //placeholder - for (i=0;iascii2glyph[s[i]]; + int g = -1; + if(s[i] < font->maxascii) + g = font->ascii2glyph[s[i]]; if(g>=0) { swf_SetBits(t,g,gbits); swf_SetBits(t,(((U32)font->glyph[g].advance)*scale)/100,abits); + l++; + if(l==0x7f) + break; } } + PUT8(&t->data[pos], l); + swf_ResetWriteBits(t); return 0; } @@ -675,7 +731,9 @@ U32 swf_TextGetWidth(SWFFONT * font,U8 * s,int scale) if (font&&s) { while (s[0]) { - int g = font->ascii2glyph[*s]; + int g = -1; + if(*s < font->maxascii) + g = font->ascii2glyph[*s]; if(g>=0) res += font->glyph[g].advance; s++; @@ -714,12 +772,11 @@ void swf_WriteFont(SWFFONT*font, char* filename) SRECT r; RGBA rgb; int f; - int useDefineFont2 = 1; + int useDefineFont2 = 0; - if(useDefineFont2) { - //fprintf(stderr, "DefineFont2 is not yet supported!\n"); - useDefineFont2 = 0; - } + if(font->layout) + useDefineFont2 = 1; /* the only thing new in definefont2 + is layout information. */ font->id = WRITEFONTID; //"FN" @@ -728,38 +785,36 @@ void swf_WriteFont(SWFFONT*font, char* filename) swf.fileVersion = 4; swf.frameRate = 0x4000; - 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); + /* we now always create viewable swfs, even if we + did use definefont2 -mk*/ + t = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR); + swf.firstTag = t; + rgb.r = 0xff; + rgb.g = 0xff; + rgb.b = 0xff; + swf_SetRGB(t,&rgb); + if(!useDefineFont2) { + t = swf_InsertTag(t,ST_DEFINEFONT); + swf_FontSetDefine(t,font); + t = swf_InsertTag(t,ST_DEFINEFONTINFO); + swf_FontSetInfo(t,font); + } else { + t = swf_InsertTag(t,ST_DEFINEFONT2); + swf_FontSetDefine2(t,font); + } - if(!useDefineFont2) + if(1) //useDefineFont2 { int textscale = 400; int s; int xmax = 0; int ymax = textscale * 2 * (font->maxascii/16+1); U8 gbits,abits; - char text[MAX_CHAR_PER_FONT+1]; + U8 text[MAX_CHAR_PER_FONT+1]; int x,y; text[MAX_CHAR_PER_FONT]=0; for(s=0;smaxascii;s++) @@ -767,8 +822,8 @@ void swf_WriteFont(SWFFONT*font, char* filename) int g = font->ascii2glyph[s]; text[s] = s; if(g>=0) { - if(font->glyph[g].advance*textscale/200 > xmax) - xmax = font->glyph[g].advance*textscale/200; + if(font->glyph[g].advance*textscale/64 > xmax) + xmax = font->glyph[g].advance*textscale/64; } } swf.movieSize.xmax = xmax*20; @@ -798,7 +853,8 @@ void swf_WriteFont(SWFFONT*font, char* filename) rgb.b = 0x00; for(y=0;y<=((font->maxascii-1)/16);y++) { - int c=0,lastx=-1, firstx=0; + int c=0,lastx=-1; + /* TODO: firstx?? */ for(x=0;x<16;x++) { int g = (y*16+xmaxascii)?font->ascii2glyph[y*16+x]:-1; if(g>=0 && font->glyph[g].shape) { @@ -882,3 +938,104 @@ void swf_SetEditText(TAG*tag, U16 flags, SRECT r, char*text, RGBA*color, swf_SetString(tag,text); } +SRECT swf_SetDefineText(TAG*tag, SWFFONT*font, RGBA*rgb, char*text, int scale) +{ + SRECT r; + U8 gbits, abits; + U8*c = (U8*)text; + int pos = 0; + swf_GetRect(0, &r); + if(font->layout) { + while(*c) { + if(*c < font->maxascii) { + int g = font->ascii2glyph[*c]; + if(g>=0) { + SRECT rn = font->layout->bounds[g]; + rn.xmin = (rn.xmin * scale)/100 + pos; + rn.xmax = (rn.xmax * scale)/100 + pos; + rn.ymin = (rn.ymin * scale)/100; + rn.ymax = (rn.ymax * scale)/100; + swf_ExpandRect2(&r, &rn); + pos += (font->glyph[g].advance*scale*20)/100; + } + } + c++; + } + } else { + /* Hm, without layout information, we can't compute a bounding + box. We could call swf_FontCreateLayout to create a layout, + but the caller probably doesn't want us to mess up his font + structure. + */ + r.xmin = r.ymin = 0; + r.xmax = r.ymax = 1024*20; + } + + swf_SetRect(tag,&r); + swf_SetMatrix(tag,NULL); + swf_TextCountBits(font,text,scale*20,&gbits,&abits); + swf_SetU8(tag,gbits); + swf_SetU8(tag,abits); + + /* now set the text params- notice that a font size of + 1024 means that the glyphs will be displayed exactly + as they would be in/with a defineshape. (Try to find + *that* in the flash specs) + */ + swf_TextSetInfoRecord(tag,font,(scale*1024)/100,rgb,0,0); //scale + + /* set the actual text- notice that we just pass our scale + parameter over, as TextSetCharRecord calculates with + percent, too */ + swf_TextSetCharRecord(tag,font,text,scale*20,gbits,abits); + + swf_SetU8(tag,0); + return r; +} + +void swf_FontCreateLayout(SWFFONT*f) +{ + S16 leading = 0; + int t; + if(f->layout) + return; + if(!f->numchars) + return; + + f->layout = (SWFLAYOUT*)malloc(sizeof(SWFLAYOUT)); + memset(f->layout, 0, sizeof(SWFLAYOUT)); + f->layout->bounds = (SRECT*)malloc(f->numchars*sizeof(SRECT)); + f->layout->ascent = -32767; + f->layout->descent = -32767; + + for(t=0;tnumchars;t++) { + SHAPE2*shape2; + SRECT bbox; + int width; + shape2 = swf_ShapeToShape2(f->glyph[t].shape); + if(!shape2) { + fprintf(stderr, "Shape parse error\n");exit(1); + } + bbox = swf_GetShapeBoundingBox(shape2->lines); + swf_Shape2Free(shape2); + f->layout->bounds[t] = bbox; + /* FIXME */ + //width = (bbox.xmax - bbox.xmin)/20; + width = (bbox.xmax)/20; + + /* The following is a heuristic- it may be that extractfont_DefineText + has already found out some widths for individual characters (from the way + they are used)- we now have to guess whether that width might be possible, + which is the case if it isn't either much too big or much too small */ + if(width > f->glyph[t].advance*3/2 || + width*2 < f->glyph[t].advance) + f->glyph[t].advance = width; + + if(-bbox.ymin > f->layout->ascent) + f->layout->ascent = bbox.ymin; + if(bbox.ymax > f->layout->descent) + f->layout->descent = bbox.ymax; + } +} + +