reduced memory requirements for Illustrator files
[swftools.git] / lib / pdf / bbox.c
index 226d1bb..ac7285c 100644 (file)
@@ -30,7 +30,7 @@ void ibbox_destroy(ibbox_t*b)
     }
 }
 
-ibbox_t*get_bitmap_bboxes_simple(unsigned char*alpha, int width, int height)
+ibbox_t*get_bitmap_bboxes_simple(unsigned char*alpha, int width, int height, int rowsize)
 {
     int ymin = -1;
     int ymax = -1;
@@ -39,7 +39,7 @@ ibbox_t*get_bitmap_bboxes_simple(unsigned char*alpha, int width, int height)
 
     int x,y;
     for(y=0;y<height;y++) {
-       unsigned char*a = &alpha[y*width];
+       unsigned char*a = &alpha[y*rowsize];
        for(x=0;x<width;x++) {
            if(a[x]) break;
        }
@@ -79,6 +79,7 @@ typedef struct _head {
 typedef struct _context {
     void**group;
     unsigned char*alpha;
+    int rowsize;
     int width;
     int height;
     head_t*heads;
@@ -118,6 +119,7 @@ static void head_delete(context_t*context, head_t*h)
        assert(!h->prev);
        context->heads = h->next;
     }
+    free(h);
 }
 
 #define POINTS_TO_HEAD(ptr) (((head_t*)(ptr))->magic==HEAD_MAGIC)
@@ -192,6 +194,21 @@ static inline void merge(context_t*context, int set1, int set2)
     }
 }
 
+ibbox_t ibbox_clip(ibbox_t* outer, ibbox_t* inner)
+{
+    ibbox_t i = {inner->xmin, inner->ymin, inner->xmax, inner->ymax, 0};
+    if(i.xmax > outer->xmax) i.xmax = outer->xmax;
+    if(i.ymax > outer->ymax) i.ymax = outer->ymax;
+    if(i.xmax < outer->xmin) i.xmax = outer->xmin;
+    if(i.ymax < outer->ymin) i.ymax = outer->ymin;
+    
+    if(i.xmin > outer->xmax) i.xmin = outer->xmax;
+    if(i.ymin > outer->ymax) i.ymin = outer->ymax;
+    if(i.xmin < outer->xmin) i.xmin = outer->xmin;
+    if(i.ymin < outer->ymin) i.ymin = outer->ymin;
+    return i;
+}
+
 static void** annotate(context_t*context)
 {
     unsigned char*alpha = context->alpha;
@@ -210,9 +227,11 @@ static void** annotate(context_t*context)
        }
     }
     int pos = 0;
+    int apos = 0;
     for(y=1;y<height;y++) {
        pos += width;
-       if(alpha[pos]) {
+       apos += context->rowsize;
+       if(alpha[apos]) {
            if(group[pos-width])
                link_to(context,pos,pos-width);
            else
@@ -222,7 +241,7 @@ static void** annotate(context_t*context)
            /* once this code is stable we should copy&paste it
               out of the loop, change the loop end to width-1 and
               add the pos-width+1 case */
-           if(alpha[pos+x]) {
+           if(alpha[apos+x]) {
                if(group[pos+x-width]) {
                    link_to(context,pos+x,pos+x-width);
                    if(group[pos+x-1])
@@ -264,17 +283,49 @@ static void overlap_bboxes(context_t*context)
     } while(changed);
 }
 
+typedef struct _circle_coord {
+    S16 x,y;
+} circle_coord_t;
+
+static int compare_circle_coord(const void *_v1, const void *_v2)
+{
+    circle_coord_t*v1=(circle_coord_t*)_v1;
+    circle_coord_t*v2=(circle_coord_t*)_v2;
+    return (v1->x*v1->x + v1->y*v1->y) - (v2->x*v2->x + v2->y*v2->y);
+}
+
 static head_t* search_vicinity(context_t*context, head_t*h, int max_radius, double*cos, double*sin)
 {
+    static circle_coord_t*circle_order = 0;
+    static int circle_order_size = 0;
+    
+    if(!circle_order) {
+       circle_order_size = (max_radius*(max_radius+1))/2;
+       circle_order = malloc(sizeof(circle_coord_t)*circle_order_size);
+       int x,y;
+       int i = 0;
+       for(y=0;y<max_radius;y++) {
+           for(x=0;x<=y;x++) {
+               circle_order[i].x=x;
+               circle_order[i].y=y;
+               i++;
+           }
+       }
+       assert(i==circle_order_size);
+       qsort(circle_order, circle_order_size, sizeof(circle_coord_t), compare_circle_coord);
+    }
+
     int t;
     void**data = context->group;
-    /* FIXME: this function isn't very efficient. We need a better way to iterate
-       through all points, sorted by distance, in the neighborhood of a coordinate */
-    for(t=3;t<max_radius*2;t++) {
+    int signx[4] = {-1,1,-1,1};
+    int signy[4] = {-1,-1,1,1};
+    for(t=1;t<circle_order_size;t++) {
+       int xx = circle_order[t].x;
+       int yy = circle_order[t].y;
        int s;
-       for(s=0;s<256;s++) {
-           int x=h->x+cos[s]*t/4.0+0.5;
-           int y=h->y+sin[s]*t/4.0+0.5;
+       for(s=0;s<4;s++) {
+           int x=h->x+xx*signx[s];
+           int y=h->y+yy*signy[s];
            if(x>=0 && y>=0 && x<context->width && y<context->height) {
                int pos = y*context->width+x;
                if(data[pos]) {
@@ -315,17 +366,26 @@ static void fix_small_boxes(context_t*context)
        while(h) {
            head_t*next = h->next;
            if(!h->seen) {
-               if(h->bbox.xmax - h->bbox.ymin < 16
-               && h->bbox.ymax - h->bbox.ymin < 16) {
+               if(h->bbox.xmax - h->bbox.xmin < 32
+               || h->bbox.ymax - h->bbox.ymin < 32) {
                    head_t*other = search_vicinity(context, h, 64, costab, sintab);
                    if(other) {
                        merge(context, h->pos, other->pos);
                        changed = 1;
                        break;
                    } else {
+                       //printf("nothing in the vicinity of %d,%d,%d,%d\n", h->bbox);
                        h->seen = 1;
                    }
-               }
+               } /*else {
+                   printf("area %d,%d,%d,%d is large enough (%dx%d)\n", 
+                           h->bbox.xmin,
+                           h->bbox.ymin,
+                           h->bbox.xmax,
+                           h->bbox.ymax,
+                           h->bbox.xmax - h->bbox.xmin,
+                           h->bbox.ymax - h->bbox.ymin);
+               } */
            }
            h = next;
        }
@@ -361,14 +421,15 @@ static void display(context_t*context)
     }
 }
 
-ibbox_t*get_bitmap_bboxes(unsigned char*alpha, int width, int height)
+ibbox_t*get_bitmap_bboxes(unsigned char*alpha, int width, int height, int rowsize)
 {
     int size = width*height;
     if(width<=1 || height<=1)
-       return get_bitmap_bboxes_simple(alpha, width, height);
+       return get_bitmap_bboxes_simple(alpha, width, height, rowsize);
     
     context_t context;
     context.alpha = alpha;
+    context.rowsize = rowsize;
     context.width = width;
     context.height = height;
     context.heads = 0;
@@ -377,6 +438,9 @@ ibbox_t*get_bitmap_bboxes(unsigned char*alpha, int width, int height)
     void**group = annotate(&context);
     fix_small_boxes(&context);
     overlap_bboxes(&context);
+#ifdef MAIN
+    display(&context);
+#endif
 
     ibbox_t*bboxes = 0;
 
@@ -412,6 +476,6 @@ int main(int argn, char*argv[])
        "\1\0\0\0\0\0\1\0"
        "\1\1\1\0\0\0\0\0";
 
-    get_bitmap_bboxes(alpha, 8,8);
+    get_bitmap_bboxes(alpha, 8,8, 8);
 }
 #endif