File indexing completed on 2024-12-22 04:04:10

0001 /* Copyright (C) 2001-2019 Peter Selinger.
0002    This file is part of Potrace. It is free software and it is covered
0003    by the GNU General Public License. See the file COPYING for details. */
0004 
0005 #ifdef HAVE_CONFIG_H
0006 #include <config.h>
0007 #endif
0008 
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012 #include <limits.h>
0013 #ifdef HAVE_INTTYPES_H
0014 #include <inttypes.h>
0015 #endif
0016 
0017 #include "potracelib.h"
0018 #include "curve.h"
0019 #include "lists.h"
0020 #include "bitmap.h"
0021 #include "decompose.h"
0022 #include "progress.h"
0023 
0024 /* ---------------------------------------------------------------------- */
0025 /* deterministically and efficiently hash (x,y) into a pseudo-random bit */
0026 
0027 static inline int detrand(int x, int y) {
0028   unsigned int z;
0029   static const unsigned char t[256] = { 
0030     /* non-linear sequence: constant term of inverse in GF(8), 
0031        mod x^8+x^4+x^3+x+1 */
0032     0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 
0033     0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 
0034     0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 
0035     1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 
0036     0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 
0037     0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 
0038     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 
0039     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 
0040     1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 
0041     0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 
0042     1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 
0043   };
0044 
0045   /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
0046      5-bit sequence */
0047   z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
0048   z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff];
0049   return z;
0050 }
0051 
0052 /* ---------------------------------------------------------------------- */
0053 /* auxiliary bitmap manipulations */
0054 
0055 /* set the excess padding to 0 */
0056 static void bm_clearexcess(potrace_bitmap_t *bm) {
0057   potrace_word mask;
0058   int y;
0059 
0060   if (bm->w % BM_WORDBITS != 0) {
0061     mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS));
0062     for (y=0; y<bm->h; y++) {
0063       *bm_index(bm, bm->w, y) &= mask;
0064     }
0065   }
0066 }
0067 
0068 struct bbox_s {
0069   int x0, x1, y0, y1;    /* bounding box */
0070 };
0071 typedef struct bbox_s bbox_t;
0072 
0073 /* clear the bm, assuming the bounding box is set correctly (faster
0074    than clearing the whole bitmap) */
0075 static void clear_bm_with_bbox(potrace_bitmap_t *bm, bbox_t *bbox) {
0076   int imin = (bbox->x0 / BM_WORDBITS);
0077   int imax = ((bbox->x1 + BM_WORDBITS-1) / BM_WORDBITS);
0078   int i, y;
0079 
0080   for (y=bbox->y0; y<bbox->y1; y++) {
0081     for (i=imin; i<imax; i++) {
0082       bm_scanline(bm, y)[i] = 0;
0083     }
0084   }
0085 }
0086 
0087 /* ---------------------------------------------------------------------- */
0088 /* auxiliary functions */
0089 
0090 /* return the "majority" value of bitmap bm at intersection (x,y). We
0091    assume that the bitmap is balanced at "radius" 1.  */
0092 static int majority(potrace_bitmap_t *bm, int x, int y) {
0093   int i, a, ct;
0094 
0095   for (i=2; i<5; i++) { /* check at "radius" i */
0096     ct = 0;
0097     for (a=-i+1; a<=i-1; a++) {
0098       ct += BM_GET(bm, x+a, y+i-1) ? 1 : -1;
0099       ct += BM_GET(bm, x+i-1, y+a-1) ? 1 : -1;
0100       ct += BM_GET(bm, x+a-1, y-i) ? 1 : -1;
0101       ct += BM_GET(bm, x-i, y+a) ? 1 : -1;
0102     }
0103     if (ct>0) {
0104       return 1;
0105     } else if (ct<0) {
0106       return 0;
0107     }
0108   }
0109   return 0;
0110 }
0111 
0112 /* ---------------------------------------------------------------------- */
0113 /* decompose image into paths */
0114 
0115 /* efficiently invert bits [x,infty) and [xa,infty) in line y. Here xa
0116    must be a multiple of BM_WORDBITS. */
0117 static void xor_to_ref(potrace_bitmap_t *bm, int x, int y, int xa) {
0118   int xhi = x & -BM_WORDBITS;
0119   int xlo = x & (BM_WORDBITS-1);  /* = x % BM_WORDBITS */
0120   int i;
0121   
0122   if (xhi<xa) {
0123     for (i = xhi; i < xa; i+=BM_WORDBITS) {
0124       *bm_index(bm, i, y) ^= BM_ALLBITS;
0125     }
0126   } else {
0127     for (i = xa; i < xhi; i+=BM_WORDBITS) {
0128       *bm_index(bm, i, y) ^= BM_ALLBITS;
0129     }
0130   }
0131   /* note: the following "if" is needed because x86 treats a<<b as
0132      a<<(b&31). I spent hours looking for this bug. */
0133   if (xlo) {
0134     *bm_index(bm, xhi, y) ^= (BM_ALLBITS << (BM_WORDBITS - xlo));
0135   }
0136 }
0137 
0138 /* a path is represented as an array of points, which are thought to
0139    lie on the corners of pixels (not on their centers). The path point
0140    (x,y) is the lower left corner of the pixel (x,y). Paths are
0141    represented by the len/pt components of a path_t object (which
0142    also stores other information about the path) */
0143 
0144 /* xor the given pixmap with the interior of the given path. Note: the
0145    path must be within the dimensions of the pixmap. */
0146 static void xor_path(potrace_bitmap_t *bm, path_t *p) {
0147   int xa, x, y, k, y1;
0148 
0149   if (p->priv->len <= 0) {  /* a path of length 0 is silly, but legal */
0150     return;
0151   }
0152 
0153   y1 = p->priv->pt[p->priv->len-1].y;
0154 
0155   xa = p->priv->pt[0].x & -BM_WORDBITS;
0156   for (k=0; k<p->priv->len; k++) {
0157     x = p->priv->pt[k].x;
0158     y = p->priv->pt[k].y;
0159 
0160     if (y != y1) {
0161       /* efficiently invert the rectangle [x,xa] x [y,y1] */
0162       xor_to_ref(bm, x, min(y,y1), xa);
0163       y1 = y;
0164     }
0165   }
0166 }
0167 
0168 /* Find the bounding box of a given path. Path is assumed to be of
0169    non-zero length. */
0170 static void setbbox_path(bbox_t *bbox, path_t *p) {
0171   int x, y;
0172   int k;
0173 
0174   bbox->y0 = INT_MAX;
0175   bbox->y1 = 0;
0176   bbox->x0 = INT_MAX;
0177   bbox->x1 = 0;
0178 
0179   for (k=0; k<p->priv->len; k++) {
0180     x = p->priv->pt[k].x;
0181     y = p->priv->pt[k].y;
0182 
0183     if (x < bbox->x0) {
0184       bbox->x0 = x;
0185     }
0186     if (x > bbox->x1) {
0187       bbox->x1 = x;
0188     }
0189     if (y < bbox->y0) {
0190       bbox->y0 = y;
0191     }
0192     if (y > bbox->y1) {
0193       bbox->y1 = y;
0194     }
0195   }
0196 }
0197 
0198 #include "stdint.h"
0199 
0200 /* compute a path in the given pixmap, separating black from white.
0201    Start path at the point (x0,x1), which must be an upper left corner
0202    of the path. Also compute the area enclosed by the path. Return a
0203    new path_t object, or NULL on error (note that a legitimate path
0204    cannot have length 0). Sign is required for correct interpretation
0205    of turnpolicies. */
0206 static path_t *findpath(potrace_bitmap_t *bm, int x0, int y0, int sign, int turnpolicy) {
0207   int x, y, dirx, diry, len, size;
0208   uint64_t area;
0209   int c, d, tmp;
0210   point_t *pt, *pt1;
0211   path_t *p = NULL;
0212 
0213   x = x0;
0214   y = y0;
0215   dirx = 0;
0216   diry = -1;
0217 
0218   len = size = 0;
0219   pt = NULL;
0220   area = 0;
0221   
0222   while (1) {
0223     /* add point to path */
0224     if (len>=size) {
0225       size += 100;
0226       size = (int)(1.3 * size);
0227       pt1 = (point_t *)realloc(pt, size * sizeof(point_t));
0228       if (!pt1) {
0229     goto error;
0230       }
0231       pt = pt1;
0232     }
0233     pt[len].x = x;
0234     pt[len].y = y;
0235     len++;
0236     
0237     /* move to next point */
0238     x += dirx;
0239     y += diry;
0240     area += x*diry;
0241     
0242     /* path complete? */
0243     if (x==x0 && y==y0) {
0244       break;
0245     }
0246     
0247     /* determine next direction */
0248     c = BM_GET(bm, x + (dirx+diry-1)/2, y + (diry-dirx-1)/2);
0249     d = BM_GET(bm, x + (dirx-diry-1)/2, y + (diry+dirx-1)/2);
0250     
0251     if (c && !d) {               /* ambiguous turn */
0252       if (turnpolicy == POTRACE_TURNPOLICY_RIGHT
0253       || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+')
0254       || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-')
0255       || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand(x,y))
0256       || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority(bm, x, y))
0257       || (turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority(bm, x, y))) {
0258     tmp = dirx;              /* right turn */
0259     dirx = diry;
0260     diry = -tmp;
0261       } else {
0262     tmp = dirx;              /* left turn */
0263     dirx = -diry;
0264     diry = tmp;
0265       }
0266     } else if (c) {              /* right turn */
0267       tmp = dirx;
0268       dirx = diry;
0269       diry = -tmp;
0270     } else if (!d) {             /* left turn */
0271       tmp = dirx;
0272       dirx = -diry;
0273       diry = tmp;
0274     }
0275   } /* while this path */
0276 
0277   /* allocate new path object */
0278   p = path_new();
0279   if (!p) {
0280     goto error;
0281   }
0282 
0283   p->priv->pt = pt;
0284   p->priv->len = len;
0285   p->area = area <= INT_MAX ? area : INT_MAX; /* avoid overflow */
0286   p->sign = sign;
0287 
0288   return p;
0289  
0290  error:
0291    free(pt);
0292    return NULL; 
0293 }
0294 
0295 /* Give a tree structure to the given path list, based on "insideness"
0296    testing. I.e., path A is considered "below" path B if it is inside
0297    path B. The input pathlist is assumed to be ordered so that "outer"
0298    paths occur before "inner" paths. The tree structure is stored in
0299    the "childlist" and "sibling" components of the path_t
0300    structure. The linked list structure is also changed so that
0301    negative path components are listed immediately after their
0302    positive parent.  Note: some backends may ignore the tree
0303    structure, others may use it e.g. to group path components. We
0304    assume that in the input, point 0 of each path is an "upper left"
0305    corner of the path, as returned by bm_to_pathlist. This makes it
0306    easy to find an "interior" point. The bm argument should be a
0307    bitmap of the correct size (large enough to hold all the paths),
0308    and will be used as scratch space. Return 0 on success or -1 on
0309    error with errno set. */
0310 
0311 static void pathlist_to_tree(path_t *plist, potrace_bitmap_t *bm) {
0312   path_t *p, *p1;
0313   path_t *heap, *heap1;
0314   path_t *cur;
0315   path_t *head;
0316   path_t **plist_hook;          /* for fast appending to linked list */
0317   path_t **hook_in, **hook_out; /* for fast appending to linked list */
0318   bbox_t bbox;
0319   
0320   bm_clear(bm, 0);
0321 
0322   /* save original "next" pointers */
0323   list_forall(p, plist) {
0324     p->sibling = p->next;
0325     p->childlist = NULL;
0326   }
0327   
0328   heap = plist;
0329 
0330   /* the heap holds a list of lists of paths. Use "childlist" field
0331      for outer list, "next" field for inner list. Each of the sublists
0332      is to be turned into a tree. This code is messy, but it is
0333      actually fast. Each path is rendered exactly once. We use the
0334      heap to get a tail recursive algorithm: the heap holds a list of
0335      pathlists which still need to be transformed. */
0336 
0337   while (heap) {
0338     /* unlink first sublist */
0339     cur = heap;
0340     heap = heap->childlist;
0341     cur->childlist = NULL;
0342   
0343     /* unlink first path */
0344     head = cur;
0345     cur = cur->next;
0346     head->next = NULL;
0347 
0348     /* render path */
0349     xor_path(bm, head);
0350     setbbox_path(&bbox, head);
0351 
0352     /* now do insideness test for each element of cur; append it to
0353        head->childlist if it's inside head, else append it to
0354        head->next. */
0355     hook_in=&head->childlist;
0356     hook_out=&head->next;
0357     list_forall_unlink(p, cur) {
0358       if (p->priv->pt[0].y <= bbox.y0) {
0359     list_insert_beforehook(p, hook_out);
0360     /* append the remainder of the list to hook_out */
0361     *hook_out = cur;
0362     break;
0363       }
0364       if (BM_GET(bm, p->priv->pt[0].x, p->priv->pt[0].y-1)) {
0365     list_insert_beforehook(p, hook_in);
0366       } else {
0367     list_insert_beforehook(p, hook_out);
0368       }
0369     }
0370 
0371     /* clear bm */
0372     clear_bm_with_bbox(bm, &bbox);
0373 
0374     /* now schedule head->childlist and head->next for further
0375        processing */
0376     if (head->next) {
0377       head->next->childlist = heap;
0378       heap = head->next;
0379     }
0380     if (head->childlist) {
0381       head->childlist->childlist = heap;
0382       heap = head->childlist;
0383     }
0384   }
0385   
0386   /* copy sibling structure from "next" to "sibling" component */
0387   p = plist;
0388   while (p) {
0389     p1 = p->sibling;
0390     p->sibling = p->next;
0391     p = p1;
0392   }
0393 
0394   /* reconstruct a new linked list ("next") structure from tree
0395      ("childlist", "sibling") structure. This code is slightly messy,
0396      because we use a heap to make it tail recursive: the heap
0397      contains a list of childlists which still need to be
0398      processed. */
0399   heap = plist;
0400   if (heap) {
0401     heap->next = NULL;  /* heap is a linked list of childlists */
0402   }
0403   plist = NULL;
0404   plist_hook = &plist;
0405   while (heap) {
0406     heap1 = heap->next;
0407     for (p=heap; p; p=p->sibling) {
0408       /* p is a positive path */
0409       /* append to linked list */
0410       list_insert_beforehook(p, plist_hook);
0411       
0412       /* go through its children */
0413       for (p1=p->childlist; p1; p1=p1->sibling) {
0414     /* append to linked list */
0415     list_insert_beforehook(p1, plist_hook);
0416     /* append its childlist to heap, if non-empty */
0417     if (p1->childlist) {
0418       list_append(path_t, heap1, p1->childlist);
0419     }
0420       }
0421     }
0422     heap = heap1;
0423   }
0424 
0425   return;
0426 }
0427 
0428 /* find the next set pixel in a row <= y. Pixels are searched first
0429    left-to-right, then top-down. In other words, (x,y)<(x',y') if y>y'
0430    or y=y' and x<x'. If found, return 0 and store pixel in
0431    (*xp,*yp). Else return 1. Note that this function assumes that
0432    excess bytes have been cleared with bm_clearexcess. */
0433 static int findnext(potrace_bitmap_t *bm, int *xp, int *yp) {
0434   int x;
0435   int y;
0436   int x0;
0437 
0438   x0 = (*xp) & ~(BM_WORDBITS-1);
0439 
0440   for (y=*yp; y>=0; y--) {
0441     for (x=x0; x<bm->w && x>=0; x+=(unsigned)BM_WORDBITS) {
0442       if (*bm_index(bm, x, y)) {
0443     while (!BM_GET(bm, x, y)) {
0444       x++;
0445     }
0446     /* found */
0447     *xp = x;
0448     *yp = y;
0449     return 0;
0450       }
0451     }
0452     x0 = 0;
0453   }
0454   /* not found */
0455   return 1;
0456 }
0457 
0458 /* Decompose the given bitmap into paths. Returns a linked list of
0459    path_t objects with the fields len, pt, area, sign filled
0460    in. Returns 0 on success with plistp set, or -1 on error with errno
0461    set. */
0462 
0463 int bm_to_pathlist(const potrace_bitmap_t *bm, path_t **plistp, const potrace_param_t *param, progress_t *progress) {
0464   int x;
0465   int y;
0466   path_t *p;
0467   path_t *plist = NULL;  /* linked list of path objects */
0468   path_t **plist_hook = &plist;  /* used to speed up appending to linked list */
0469   potrace_bitmap_t *bm1 = NULL;
0470   int sign;
0471 
0472   bm1 = bm_dup(bm);
0473   if (!bm1) {
0474     goto error;
0475   }
0476 
0477   /* be sure the byte padding on the right is set to 0, as the fast
0478      pixel search below relies on it */
0479   bm_clearexcess(bm1);
0480 
0481   /* iterate through components */
0482   x = 0;
0483   y = bm1->h - 1;
0484   while (findnext(bm1, &x, &y) == 0) { 
0485     /* calculate the sign by looking at the original */
0486     sign = BM_GET(bm, x, y) ? '+' : '-';
0487 
0488     /* calculate the path */
0489     p = findpath(bm1, x, y+1, sign, param->turnpolicy);
0490     if (p==NULL) {
0491       goto error;
0492     }
0493 
0494     /* update buffered image */
0495     xor_path(bm1, p);
0496 
0497     /* if it's a turd, eliminate it, else append it to the list */
0498     if (p->area <= param->turdsize) {
0499       path_free(p);
0500     } else {
0501       list_insert_beforehook(p, plist_hook);
0502     }
0503 
0504     if (bm1->h > 0) { /* to be sure */
0505       progress_update(1-y/(double)bm1->h, progress);
0506     }
0507   }
0508 
0509   pathlist_to_tree(plist, bm1);
0510   bm_free(bm1);
0511   *plistp = plist;
0512 
0513   progress_update(1.0, progress);
0514 
0515   return 0;
0516 
0517  error:
0518   bm_free(bm1);
0519   list_forall_unlink(p, plist) {
0520     path_free(p);
0521   }
0522   return -1;
0523 }