added fontalign polygon detector
authorMatthias Kramm <kramm@quiss.org>
Fri, 30 Oct 2009 20:37:29 +0000 (13:37 -0700)
committerMatthias Kramm <kramm@quiss.org>
Fri, 30 Oct 2009 20:37:37 +0000 (13:37 -0700)
lib/Makefile.in
lib/devices/swf.c
lib/modules/swfalignzones.c [new file with mode: 0644]
lib/modules/swftext.c
lib/rfxswf.c
lib/rfxswf.h
src/Makefile.in
src/font2swf.c
src/swfdump.c

index ef5a16c..27aeec3 100644 (file)
@@ -16,12 +16,12 @@ as12compiler_in_source = $(as12compiler_objects)
 as3compiler_objects = as3/abc.$(O) as3/pool.$(O) as3/files.$(O) as3/opcodes.$(O) as3/code.$(O) as3/registry.$(O) as3/builtin.$(O) as3/parser.tab.$(O) as3/tokenizer.yy.$(O) as3/scripts.$(O) as3/compiler.$(O) as3/import.$(O) as3/expr.$(O) as3/common.$(O) as3/initcode.$(O)
 gfxpoly_objects = gfxpoly/active.$(O) gfxpoly/convert.$(O) gfxpoly/poly.$(O) gfxpoly/renderpoly.$(O) gfxpoly/stroke.$(O) gfxpoly/wind.$(O) gfxpoly/xrow.$(O)
 
 as3compiler_objects = as3/abc.$(O) as3/pool.$(O) as3/files.$(O) as3/opcodes.$(O) as3/code.$(O) as3/registry.$(O) as3/builtin.$(O) as3/parser.tab.$(O) as3/tokenizer.yy.$(O) as3/scripts.$(O) as3/compiler.$(O) as3/import.$(O) as3/expr.$(O) as3/common.$(O) as3/initcode.$(O)
 gfxpoly_objects = gfxpoly/active.$(O) gfxpoly/convert.$(O) gfxpoly/poly.$(O) gfxpoly/renderpoly.$(O) gfxpoly/stroke.$(O) gfxpoly/wind.$(O) gfxpoly/xrow.$(O)
 
-rfxswf_modules =  modules/swfbits.c modules/swfaction.c modules/swfdump.c modules/swfcgi.c modules/swfbutton.c modules/swftext.c modules/swffont.c modules/swftools.c modules/swfsound.c modules/swfshape.c modules/swfobject.c modules/swfdraw.c modules/swffilter.c modules/swfrender.c h.263/swfvideo.c
+rfxswf_modules =  modules/swfbits.c modules/swfaction.c modules/swfdump.c modules/swfcgi.c modules/swfbutton.c modules/swftext.c modules/swffont.c modules/swftools.c modules/swfsound.c modules/swfshape.c modules/swfobject.c modules/swfdraw.c modules/swffilter.c modules/swfrender.c h.263/swfvideo.c modules/swfalignzones.c
 
 base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) 
 gfx_objects=gfxtools.$(O) gfxfont.$(O) devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@
 
 
 base_objects=q.$(O) utf8.$(O) png.$(O) jpeg.$(O) wav.$(O) mp3.$(O) os.$(O) bitio.$(O) log.$(O) mem.$(O) 
 gfx_objects=gfxtools.$(O) gfxfont.$(O) devices/dummy.$(O) devices/file.$(O) devices/render.$(O) devices/text.$(O) devices/record.$(O) devices/ops.$(O) devices/polyops.$(O) devices/bbox.$(O) devices/rescale.$(O) @DEVICE_OPENGL@ @DEVICE_PDF@
 
-rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O)
+rfxswf_objects=modules/swfaction.$(O) modules/swfbits.$(O) modules/swfbutton.$(O) modules/swfcgi.$(O) modules/swfdraw.$(O) modules/swfdump.$(O) modules/swffilter.$(O) modules/swffont.$(O) modules/swfobject.$(O) modules/swfrender.$(O) modules/swfshape.$(O) modules/swfsound.$(O) modules/swftext.$(O) modules/swftools.$(O) modules/swfalignzones.$(O)
 ocr_objects=gocr/box.$(O) gocr/database.$(O) gocr/detect.$(O) gocr/job.$(O) gocr/lines.$(O) gocr/list.$(O) gocr/ocr0.$(O) gocr/ocr0n.$(O) gocr/ocr1.$(O) gocr/otsu.$(O) gocr/output.$(O) gocr/pgm2asc.$(O) gocr/pixel.$(O) gocr/progress.$(O) gocr/remove.$(O) gocr/unicode.$(O)
 
 %.$(O): %.c 
 ocr_objects=gocr/box.$(O) gocr/database.$(O) gocr/detect.$(O) gocr/job.$(O) gocr/lines.$(O) gocr/list.$(O) gocr/ocr0.$(O) gocr/ocr0n.$(O) gocr/ocr1.$(O) gocr/otsu.$(O) gocr/output.$(O) gocr/pgm2asc.$(O) gocr/pixel.$(O) gocr/progress.$(O) gocr/remove.$(O) gocr/unicode.$(O)
 
 %.$(O): %.c 
index 6d66409..121d49c 100644 (file)
@@ -1465,25 +1465,26 @@ void swfoutput_finalize(gfxdevice_t*dev)
 
     endpage(dev);
     fontlist_t *iterator = i->fontlist;
 
     endpage(dev);
     fontlist_t *iterator = i->fontlist;
+    char use_font3 = i->config_flashversion>=8 && !NO_FONT3;
     while(iterator) {
        TAG*mtag = i->swf->firstTag;
        if(iterator->swffont) {
     while(iterator) {
        TAG*mtag = i->swf->firstTag;
        if(iterator->swffont) {
+           if(use_font3) {
+               // needs to be done before the reduce
+               swf_FontCreateAlignZones(iterator->swffont);
+           }
            if(!i->config_storeallcharacters) {
                msg("<debug> Reducing font %s", iterator->swffont->name);
                swf_FontReduce(iterator->swffont);
            }
            int used = iterator->swffont->use && iterator->swffont->use->used_glyphs;
            if(used) {
            if(!i->config_storeallcharacters) {
                msg("<debug> Reducing font %s", iterator->swffont->name);
                swf_FontReduce(iterator->swffont);
            }
            int used = iterator->swffont->use && iterator->swffont->use->used_glyphs;
            if(used) {
-               if(i->config_flashversion<8 || NO_FONT3) {
+               if(!use_font3) {
                    mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
                    swf_FontSetDefine2(mtag, iterator->swffont);
                } else {
                    mtag = swf_InsertTag(mtag, ST_DEFINEFONT3);
                    swf_FontSetDefine2(mtag, iterator->swffont);
                    mtag = swf_InsertTag(mtag, ST_DEFINEFONT2);
                    swf_FontSetDefine2(mtag, iterator->swffont);
                } else {
                    mtag = swf_InsertTag(mtag, ST_DEFINEFONT3);
                    swf_FontSetDefine2(mtag, iterator->swffont);
-          
-                   if(i->config_flashversion>=10)
-                       swf_FontCreateAlignZones(iterator->swffont);
-                  
                    if(iterator->swffont->alignzones) {
                        mtag = swf_InsertTag(mtag, ST_DEFINEFONTALIGNZONES);
                        swf_FontSetAlignZones(mtag, iterator->swffont);
                    if(iterator->swffont->alignzones) {
                        mtag = swf_InsertTag(mtag, ST_DEFINEFONTALIGNZONES);
                        swf_FontSetAlignZones(mtag, iterator->swffont);
diff --git a/lib/modules/swfalignzones.c b/lib/modules/swfalignzones.c
new file mode 100644 (file)
index 0000000..0c5f663
--- /dev/null
@@ -0,0 +1,212 @@
+#include "../rfxswf.h"
+
+static inline double sqr(double x) {return x*x;}
+
+static void draw_line(float*row, float x1, float x2, float y1, float y2, int min, int max)
+{
+    if(x2<x1) {int x=x1;x1=x2;x2=x;}
+    if(x1<min || x2>max) {
+       fprintf(stderr, "error: glyph x stroke out of bounds\n");
+       return;
+    }
+    x1 -= min;
+    x2 -= min;
+
+    double d = sqrt(sqr(y2-y1)+sqr(x2-x1));
+    if(floor(x1)==floor(x2)) {
+       row[(int)floor(x1)] += d;
+    } else {
+       double i = d/(x2-x1);
+       int x;
+       int xx1 = ceil(x1);
+       int xx2 = floor(x2);
+       row[xx1] += i*(xx1-x1);
+       row[xx2] += i*(x2-xx2);
+       for(x=xx1;x<xx2;x++) {
+           row[x]+=i;
+       }
+    }
+}
+
+static void draw_line_xy(float*row,float*column, float x1, float y1, float x2, float y2,SRECT* area)
+{
+    draw_line(row, x1, x2, y1, y2, area->xmin, area->xmax);
+    draw_line(column, y1, y2, x1, x2, area->ymin, area->ymax);
+}
+
+static void find_best(float*_row, int width, int*_x1, int*_x2, int min_dist)
+{
+    int x1=-1, x2=-1;
+    float max1=-1,max2=-1;
+    int t;
+    float*row = malloc(sizeof(float)*(width+1));
+    int filter_size = 100;
+    float* filter = malloc(sizeof(float)*(filter_size*2+1));
+    double var = filter_size/3;
+    for(t=-filter_size;t<=filter_size;t++) {
+       double v = t/var;
+        float r = v*v/2;
+       filter[filter_size+t] = exp(-r);
+    }
+    filter[0]=1;filter_size=0;
+
+    for(t=0;t<=width;t++) {
+       int s;
+       double sum = 0;
+       for(s=-filter_size;s<=filter_size;s++) {
+           if(t+s<0) continue;
+           if(t+s>width) continue;
+           sum += _row[t+s]*filter[s+filter_size];
+       }
+       row[t] = sum;
+    }
+
+    for(t=0;t<=width;t++) {
+       if(row[t]>max1) {
+           max1 = row[t];
+           x1 = t;
+       }
+    }
+    // invalidate everything around the maximum
+    for(t=-min_dist+1;t<min_dist;t++) {
+       if(t+x1<0 || t+x1>width) continue;
+       row[t+x1]=-1;
+    }
+    for(t=0;t<=width;t++) {
+       if(row[t]>max2) {
+           max2 = row[t];
+           x2 = t;
+       }
+    }
+
+    if(x1>0 && x2>0 && x1>x2) {int x=x1;x1=x2;x2=x;}
+    *_x1=x1;
+    *_x2=x2;
+    free(row);
+}
+
+static ALIGNZONE detect_for_char(SWFFONT * f, int nr)
+{
+    SWFGLYPH*g = &f->glyph[nr];
+    SRECT b = f->layout->bounds[nr];
+    ALIGNZONE a = {0xffff,0xffff,0xffff,0xffff};
+
+    // negate y
+    int by1=b.ymin,by2=b.ymax;
+    b.ymin = -by2;
+    b.ymax = -by1;
+
+    int width = b.xmax - b.xmin + 1;
+    int height = b.ymax - b.ymin + 1;
+    if(!width || !height)
+       return a;
+           
+    float*row = rfx_calloc(sizeof(float)*width);
+    float*column = rfx_calloc(sizeof(float)*height);
+
+    SHAPE2*s = swf_ShapeToShape2(g->shape);
+    SHAPELINE*l = s->lines;
+    int x=0,y=0;
+    while(l) {
+       if(l->type == lineTo) {
+           draw_line_xy(row,column,x,-y,l->x,-l->y,&b);
+       } else if(l->type == splineTo) {
+           double x1=x,x2=l->sx,x3=l->x;
+           double y1=y,y2=l->sy,y3=l->y;
+            double c = fabs(x3-2*x2+x1) + fabs(y3-2*y2+y1);
+            int parts = ((int)(sqrt(c)/6))*2+1;
+           float xx=x1,yy=y1;
+           int t;
+            for(t=1;t<=parts;t++) {
+                float nx = ((t*t*x3 + 2*t*(parts-t)*x2 + (parts-t)*(parts-t)*x1)/(double)(parts*parts));
+                float ny = ((t*t*y3 + 2*t*(parts-t)*y2 + (parts-t)*(parts-t)*y1)/(double)(parts*parts));
+                draw_line_xy(row,column,xx,-yy,nx,-ny,&b);
+                xx = nx;
+                yy = ny;
+            }
+       }
+       x = l->x;
+       y = l->y;
+       l = l->next;
+    }
+
+    int t;
+
+    /* find two best x values */
+    int x1=-1,y1=-1,x2=-1,y2=-1;
+    //int min_dist = 4000;
+    int min_dist = 1;
+    find_best(row,width,&x1,&x2,min_dist);
+    find_best(column,height,&y1,&y2,min_dist);
+
+    if(x1>=0) a.x  = floatToF16((x1+b.xmin) / 20480.0);
+    if(x2>=0) a.dx = floatToF16((x2-x1) / 20480.0);
+    if(y1>=0) a.y  = floatToF16((y1+b.ymin) / 20480.0);
+    if(y2>=0) a.dy = floatToF16((y2-y1) / 20480.0);
+    return a;
+}
+
+void swf_FontCreateAlignZones(SWFFONT * f)
+{
+    if(f->alignzones)
+       return;
+
+    if(!f->layout) {
+       fprintf(stderr, "Error: font needs a layout for alignzones to be detected.");
+       return;
+    }
+
+    
+    f->alignzones = (ALIGNZONE*)rfx_calloc(sizeof(ALIGNZONE)*f->numchars);
+    f->alignzone_flags = FONTALIGN_THIN;
+
+    if(!f->layout) {
+       int t;
+       for(t=0;t<f->numchars;t++) {
+           // just align the baseline
+           f->alignzones[t].x = 0xffff;
+           f->alignzones[t].y = 0;
+           f->alignzones[t].dx = 0xffff;
+           f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
+       }
+    } else {
+       int t;
+       for(t=0;t<f->numchars;t++) {
+           f->alignzones[t] = detect_for_char(f, t);
+       }
+    }
+
+/*
+    "-^_~\xad\xaf+`\xac\xb7\xf7" //chars for which to detect one y value
+    "#=:;\xb1" //chars for which to detect two y values
+    "\"\xa8" //chars for which to detect two x values
+*/
+}
+
+void swf_FontSetAlignZones(TAG*t, SWFFONT *f)
+{
+    swf_SetU16(t, f->id);
+    swf_SetU8(t, f->alignzone_flags);
+    int i;
+    for(i=0;i<f->numchars;i++) {
+       ALIGNZONE*a = &f->alignzones[i];
+       U8 flags = 0;
+       if((a->x & a->dx)!=0xffff)
+           flags |= 1;
+       if((a->y & a->dy)!=0xffff)
+           flags |= 2;
+       int num = 1;
+       if(a->dx != 0xffff || a->dy != 0xffff)
+           num++;
+       swf_SetU8(t, num);
+       if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0);
+       if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0);
+       if(num==2) {
+           if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0);
+           if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0);
+       }
+       swf_SetU8(t, flags);
+    }
+}
+
+
index 912e8fa..b5d74f0 100644 (file)
@@ -373,28 +373,6 @@ int swf_FontExtract_DefineFont2(int id, SWFFONT * font, TAG * tag)
     return font->id;
 }
 
     return font->id;
 }
 
-static float F16toFloat(U16 x)
-{
-    TAG t;
-    t.data = (void*)&x;
-    t.readBit = 0;
-    t.pos = 0;
-    t.len = 2;
-    return swf_GetF16(&t);
-}
-
-static float floatToF16(float f)
-{
-    U16 u = 0;
-    TAG t;
-    t.data = (void*)&u;
-    t.len = 0;
-    t.memsize = 2;
-    t.writeBit = 0;
-    swf_SetF16(&t, f);
-    return u;
-}
-
 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
 {
     U16 fid;
 int swf_FontExtract_DefineFontAlignZones(int id, SWFFONT * font, TAG * tag)
 {
     U16 fid;
@@ -1103,27 +1081,6 @@ int swf_FontSetDefine2(TAG * tag, SWFFONT * f)
     return 0;
 }
 
     return 0;
 }
 
-void swf_FontSetAlignZones(TAG*t, SWFFONT *f)
-{
-    swf_SetU16(t, f->id);
-    swf_SetU8(t, f->alignzone_flags);
-    int i;
-    for(i=0;i<f->numchars;i++) {
-       ALIGNZONE*a = &f->alignzones[i];
-       U8 flags = 0;
-       if((a->x & a->dx)!=0xffff)
-           flags |= 1;
-       if((a->y & a->dy)!=0xffff)
-           flags |= 2;
-       swf_SetU8(t, 2);
-       if(flags&1) swf_SetU16(t, a->x); else swf_SetU16(t, 0);
-       if(flags&2) swf_SetU16(t, a->y); else swf_SetU16(t, 0);
-       if((flags&1) && a->dx!=0xffff) swf_SetU16(t, a->dx); else swf_SetU16(t, 0);
-       if((flags&2) && a->dy!=0xffff) swf_SetU16(t, a->dy); else swf_SetU16(t, 0);
-       swf_SetU8(t, flags);
-    }
-}
-
 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
 {
     f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
 void swf_FontAddLayout(SWFFONT * f, int ascent, int descent, int leading)
 {
     f->layout = (SWFLAYOUT *) rfx_alloc(sizeof(SWFLAYOUT));
@@ -1608,46 +1565,6 @@ void swf_FontCreateLayout(SWFFONT * f)
     }
 }
 
     }
 }
 
-#define FONTALIGN_THIN
-#define FONTALIGN_MEDIUM
-#define FONTALIGN_THICK
-
-void swf_FontCreateAlignZones(SWFFONT * f)
-{
-    if(f->alignzones)
-       return;
-    
-    f->alignzones = (ALIGNZONE*)rfx_calloc(sizeof(ALIGNZONE)*f->numchars);
-    f->alignzone_flags = 0; // thin
-
-    if(!f->layout) {
-       int t;
-       for(t=0;t<f->numchars;t++) {
-           // just align the baseline
-           f->alignzones[t].x = 0xffff;
-           f->alignzones[t].y = 0;
-           f->alignzones[t].dx = 0xffff;
-           f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
-       }
-    } else {
-       int t;
-       for(t=0;t<f->numchars;t++) {
-           // just align the baseline
-           f->alignzones[t].x = 0xffff;
-           f->alignzones[t].y = 0;
-           f->alignzones[t].dx = 0xffff;
-           f->alignzones[t].dy = 0xffff;//floatToF16(460.80 / 1024.0);
-       }
-    }
-
-/*
-    "-^_~\xad\xaf+`\xac\xb7\xf7" //chars for which to detect one y value
-    "#=:;\xb1" //chars for which to detect two y values
-    "\"\xa8" //chars for which to detect two x values
-*/
-}
-
-
 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
 {
     U8 *s = (U8 *) text;
 void swf_DrawText(drawer_t * draw, SWFFONT * font, int size, const char *text)
 {
     U8 *s = (U8 *) text;
@@ -2082,4 +1999,3 @@ char*data =
     swf_SaveSWF(&swf, filename);
     swf_FreeTags(&swf);
 }
     swf_SaveSWF(&swf, filename);
     swf_FreeTags(&swf);
 }
-
index 025bcaf..c9006c1 100644 (file)
@@ -474,6 +474,28 @@ void swf_SetF16(TAG * t, float f)
     swf_SetU16(t, result);
 }
 
     swf_SetU16(t, result);
 }
 
+float F16toFloat(U16 x)
+{
+    TAG t;
+    t.data = (void*)&x;
+    t.readBit = 0;
+    t.pos = 0;
+    t.len = 2;
+    return swf_GetF16(&t);
+}
+
+float floatToF16(float f)
+{
+    U16 u = 0;
+    TAG t;
+    t.data = (void*)&u;
+    t.len = 0;
+    t.memsize = 2;
+    t.writeBit = 0;
+    swf_SetF16(&t, f);
+    return u;
+}
+
 double swf_GetD64(TAG*tag)
 {
     /* FIXME: this is not big-endian compatible */
 double swf_GetD64(TAG*tag)
 {
     /* FIXME: this is not big-endian compatible */
index f586849..8c102c9 100644 (file)
@@ -245,6 +245,9 @@ int   swf_SetU32(TAG * t,U32 v);
 void  swf_SetF16(TAG * t,float f);
 void  swf_SetString(TAG*t,const char*s);
 
 void  swf_SetF16(TAG * t,float f);
 void  swf_SetString(TAG*t,const char*s);
 
+float floatToF16(float f);
+float F16toFloat(U16 x);
+
 /* abc datatypes */
 U32 swf_GetU30(TAG*tag);
 int swf_SetU30(TAG*tag, U32 u);
 /* abc datatypes */
 U32 swf_GetU30(TAG*tag);
 int swf_SetU30(TAG*tag, U32 u);
@@ -540,6 +543,10 @@ typedef struct _FONTUSAGE
 #define FONT_ENCODING_ANSI 2
 #define FONT_ENCODING_SHIFTJIS 4
 
 #define FONT_ENCODING_ANSI 2
 #define FONT_ENCODING_SHIFTJIS 4
 
+#define FONTALIGN_THIN 0 
+#define FONTALIGN_MEDIUM 1
+#define FONTALIGN_THICK 2
+
 typedef struct _ALIGNZONE
 {
     U16 x,y;
 typedef struct _ALIGNZONE
 {
     U16 x,y;
index 86cf573..463b8d9 100644 (file)
@@ -53,7 +53,7 @@ swfc-interpolation.$(O): swfc-interpolation.c swfc-interpolation.h ../lib/q.h
 parser.$(O): parser.yy.c parser.h ../lib/q.h
        $(C) parser.yy.c -o $@
 
 parser.$(O): parser.yy.c parser.h ../lib/q.h
        $(C) parser.yy.c -o $@
 
-../lib/librfxswf$(A): ../lib/modules/swfrender.c ../lib/modules/swfshape.c ../lib/modules/swftext.c ../lib/modules/swffont.c ../lib/modules/swfbits.c ../lib/rfxswf.c ../lib/devices/swf.c
+../lib/librfxswf$(A): ../lib/modules/swfrender.c ../lib/modules/swfshape.c ../lib/modules/swftext.c ../lib/modules/swffont.c ../lib/modules/swfbits.c ../lib/rfxswf.c ../lib/devices/swf.c ../lib/modules/swfalignzones.c
        cd ../lib;$(MAKE) librfxswf$(A);cd -
 
 # TODO: include the following rule only if lex is available
        cd ../lib;$(MAKE) librfxswf$(A);cd -
 
 # TODO: include the following rule only if lex is available
index cd30118..55c06cd 100644 (file)
@@ -98,6 +98,7 @@ static void convertFont(char*infile, char*outfile)
     SWFFONT * font;
     
     font = swf_LoadFont(infile);
     SWFFONT * font;
     
     font = swf_LoadFont(infile);
+    swf_FontCreateAlignZones(font);
 
     if(fontname)
         font->name = strdup(fontname);
 
     if(fontname)
         font->name = strdup(fontname);
index acc1806..f903aa7 100644 (file)
@@ -1016,15 +1016,18 @@ static void handleFontAlign2(TAG*tag, char*prefix)
        printf("%sglyph %d) ", prefix, num);
        int nr = swf_GetU8(tag); // should be 2
        int t;
        printf("%sglyph %d) ", prefix, num);
        int nr = swf_GetU8(tag); // should be 2
        int t;
-       for(t=0;t<nr;t++) {
+       for(t=0;t<2;t++) {
            // pos
            float v = swf_GetF16(tag);
            printf("%f ", v*1024.0);
        }
            // pos
            float v = swf_GetF16(tag);
            printf("%f ", v*1024.0);
        }
-       for(t=0;t<nr;t++) {
-           // width
-           float v = swf_GetF16(tag);
-           printf("+%f ", v*1024.0);
+       int s;
+       for(s=0;s<nr-1;s++) {
+           for(t=0;t<2;t++) {
+               // width
+               float v = swf_GetF16(tag);
+               printf("+%f ", v*1024.0);
+           }
        }
        U8 xyflags = swf_GetU8(tag);
        printf("xy:%02x\n", xyflags);
        }
        U8 xyflags = swf_GetU8(tag);
        printf("xy:%02x\n", xyflags);