added support for text boxes.
[swftools.git] / src / swfbbox.c
index fc6de06..22d9ccd 100644 (file)
@@ -35,14 +35,14 @@ static int optimize = 0;
 static int swifty = 0;
 static int verbose = 0;
 
-struct options_t options[] =
-{
- {"V","version"},
- {"O","optimize"},
- {"o","output"},
- {"S","swifty"},
- {"v","verbose"},
- {0,0}
+static struct options_t options[] = {
+{"h", "help"},
+{"O", "optimize"},
+{"S", "swifty"},
+{"o", "output"},
+{"v", "verbose"},
+{"V", "version"},
+{0,0}
 };
 
 int args_callback_option(char*name,char*val)
@@ -60,7 +60,7 @@ int args_callback_option(char*name,char*val)
        return 0;
     } 
     else if(!strcmp(name, "v")) {
-       verbose = 1;
+       verbose ++;
        return 0;
     } 
     else if(!strcmp(name, "o")) {
@@ -78,15 +78,18 @@ int args_callback_longoption(char*name,char*val)
 {
     return args_long2shortoption(options, name, val);
 }
-void args_callback_usage(char*name)
-{    
+void args_callback_usage(char *name)
+{
+    printf("\n");
     printf("Usage: %s [-OS] file.swf\n", name);
-    printf("\t-h , --help\t\t Print help and exit\n");
-    printf("\t-O , --optimize\t\t Recalculate bounding boxes\n");
-    printf("\t-S , --swifty\t\t Print out transformed bounding boxes\n");
-    printf("\t-o , --output\t\t Set output filename (for -O)\n");
-    printf("\t-v , --verbose\t\t Be more verbose\n");
-    printf("\t-V , --version\t\t Print program version and exit\n");
+    printf("\n");
+    printf("-h , --help                    Print help and exit\n");
+    printf("-O , --optimize                Recalculate bounding boxes\n");
+    printf("-S , --swifty                  Print out transformed bounding boxes\n");
+    printf("-o , --output <filename>       Set output filename to <filename> (for -O)\n");
+    printf("-v , --verbose                 Be more verbose\n");
+    printf("-V , --version                 Print program version and exit\n");
+    printf("\n");
 }
 int args_callback_command(char*name,char*val)
 {
@@ -125,7 +128,6 @@ void parseFillStyleArray(TAG*tag, SHAPE2*shape)
        int type;
        U8*pos;
        FILLSTYLE*dest = &shape->fillstyles[t];
-       swf_ResetReadBits(tag);
        type = swf_GetU8(tag); //type
        shape->fillstyles[t].type = type;
        if(type == 0) {
@@ -141,8 +143,7 @@ void parseFillStyleArray(TAG*tag, SHAPE2*shape)
            swf_ResetReadBits(tag);
            swf_GetMatrix(tag, &dest->m);
            swf_ResetReadBits(tag);
-           dest->gradient = malloc(sizeof(GRADIENT)); // TODO: free this again
-           swf_GetGradient(tag, dest->gradient, num>=3?1:0);
+           swf_GetGradient(tag, &dest->gradient, num>=3?1:0);
        }
        else if(type == 0x40 || type == 0x41)
        {
@@ -161,7 +162,7 @@ void parseFillStyleArray(TAG*tag, SHAPE2*shape)
     if(count == 0xff)
        count = swf_GetU16(tag);
 
-    if(verbose) printf("lnum: %d\n", count);
+    //if(verbose) printf("lnum: %d\n", count);
 
     shape->numlinestyles = count;
     shape->linestyles = malloc(sizeof(LINESTYLE)*count);
@@ -333,9 +334,94 @@ MATRIX getmatrix(TAG*tag)
     return o.matrix;
 }
 
+
+static int fontnum = -1;
+static SWFFONT**fonts;
+static SWF*c_swf;
+static void fontcallback1(U16 id,U8 * name)
+{ fontnum++;
+}
+static void fontcallback2(U16 id,U8 * name)
+{ 
+    fonts[fontnum] = 0;
+    swf_FontExtract(c_swf,id,&fonts[fontnum]);
+    if(verbose) {
+       if(fonts[fontnum]) printf("Extracting font %d (%s)\n", id, name);
+       else               printf("Extracting font %d (%s) failed\n", id, name);
+       fflush(stdout);
+    }
+    fontnum++;
+}
+typedef struct _textbounds
+{
+    SRECT r;
+    MATRIX m; // character transform matrix
+} textbounds_t;
+
+static void textcallback(void*self, int*chars, int*xpos, int nr, int fontid, int fontsize, 
+                   int xstart, int ystart, RGBA* color)
+{
+    textbounds_t * bounds = (textbounds_t*)self;
+    SWFFONT*font = 0;
+    int t;
+    for(t=0;t<fontnum;t++) {
+       if(fonts[t]->id == fontid) {
+           font = fonts[t];
+           break;
+       }
+    }
+    if(!font) {
+       fprintf(stderr, "Font %d unknown\n", fontid);
+       exit(1);
+    }
+    if(!font->layout) {
+       /* This is an expensive operation- but what should we do, we
+          need the glyph's bounding boxes */
+       swf_FontCreateLayout(font);
+    }
+
+    if(verbose)
+       printf("%d chars, font %d, size %d, at (%d,%d)\n", nr, fontid, fontsize, xstart, ystart);
+
+    for(t=0;t<nr;t++) {
+       /* not tested yet- the matrix/fontsize calculation is probably all wrong */
+       int x = xstart + xpos[t];
+       int y = ystart;
+       int ch;
+       SRECT newglyphbbox, glyphbbox = font->layout->bounds[chars[t]];
+       MATRIX m = bounds->m;
+       
+       if(ch < font->numchars && font->glyph2ascii) {
+           ch = font->glyph2ascii[ch];
+       }
+
+       m.sx = (m.sx * fontsize) / 1024;
+       m.sy = (m.sy * fontsize) / 1024;
+       m.r0 = (m.r0 * fontsize) / 1024;
+       m.r1 = (m.r1 * fontsize) / 1024;
+
+       m.tx += x;
+       m.ty += y;
+       newglyphbbox = swf_TurnRect(glyphbbox, &m);
+
+       if(ch<32) ch='?';
+           
+       swf_ExpandRect2(&(bounds->r), &newglyphbbox);
+       if(verbose >= 2) {
+           printf("%5d %c, %d %d %d %d (%d %d %d %d) -> %d %d %d %d\n", 
+               xpos[t], ch, 
+               glyphbbox.xmin, glyphbbox.ymin, glyphbbox.xmax, glyphbbox.ymax,
+               newglyphbbox.xmin, newglyphbbox.ymin, newglyphbbox.xmax, newglyphbbox.ymax,
+               bounds->r.xmin, bounds->r.ymin, bounds->r.xmax, bounds->r.ymax);
+       }
+
+    }
+}
+
 static void swf_OptimizeBoundingBoxes(SWF*swf)
 {
     TAG* tag = swf->firstTag;
+    
     while (tag) {
        if (tag->id == ST_DEFINESHAPE ||
            tag->id == ST_DEFINESHAPE2 ||
@@ -348,6 +434,56 @@ static void swf_OptimizeBoundingBoxes(SWF*swf)
            tag->pos = 0;
            swf_SetShape2(tag, &s);
        }
+       if (tag->id == ST_DEFINETEXT || tag->id == ST_DEFINETEXT2) {
+           SRECT oldbox;
+           int matrix_offset;
+           int len;
+           U8*data;
+           if(verbose) printf("%s\n", swf_TagGetName(tag));
+           if(fontnum < 0) {
+               if(verbose) printf("Extracting fonts...\n");
+               c_swf = swf;
+               fontnum = 0;
+               swf_FontEnumerate(swf,&fontcallback1);
+               fonts = (SWFFONT**)malloc(fontnum*sizeof(SWFFONT*));
+               memset(fonts, 0, fontnum*sizeof(SWFFONT*));
+               fontnum = 0;
+               swf_FontEnumerate(swf,&fontcallback2);
+           }
+
+           textbounds_t bounds;
+           memset(&bounds, 0, sizeof(bounds));
+
+           swf_SetTagPos(tag, 0);
+           swf_GetU16(tag);
+           swf_GetRect(tag,&oldbox);
+           swf_ResetReadBits(tag);
+           matrix_offset = tag->pos;
+           swf_GetMatrix(tag,&bounds.m);
+           swf_ParseDefineText(tag, textcallback, &bounds);
+           if(verbose) {
+               printf("\n");
+               swf_DumpMatrix(stdout, &bounds.m);
+               printf("old: %d %d %d %d\n", oldbox.xmin, oldbox.ymin, oldbox.xmax, oldbox.ymax);
+               printf("new: %d %d %d %d\n", bounds.r.xmin, bounds.r.ymin, bounds.r.xmax, bounds.r.ymax);
+           }
+           
+           /* now comes the tricky part: 
+              we have to fiddle the data back in 
+              thank heavens that the bbox is follow by a matrix
+              struct, which always starts on a byte boundary.
+            */
+           len = tag->len - matrix_offset;
+           data = malloc(len);
+           memcpy(data, &tag->data[matrix_offset], len);
+           tag->writeBit = 0;
+           tag->len = 2;
+           swf_SetRect(tag, &bounds.r);
+           swf_SetBlock(tag, data, len);
+           free(data);
+           tag->pos = tag->readBit = 0;
+       }
+       tag = tag->next;
     }
 }