xref: /potrace-1.14/src/decompose.c (revision b3fce824)
1 /* Copyright (C) 2001-2017 Peter Selinger.
2    This file is part of Potrace. It is free software and it is covered
3    by the GNU General Public License. See the file COPYING for details. */
4 
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <limits.h>
13 
14 #include "potracelib.h"
15 #include "curve.h"
16 #include "lists.h"
17 #include "bitmap.h"
18 #include "decompose.h"
19 #include "progress.h"
20 
21 /* ---------------------------------------------------------------------- */
22 /* deterministically and efficiently hash (x,y) into a pseudo-random bit */
23 
detrand(int x,int y)24 static inline int detrand(int x, int y) {
25   unsigned int z;
26   static const unsigned char t[256] = {
27     /* non-linear sequence: constant term of inverse in GF(8),
28        mod x^8+x^4+x^3+x+1 */
29     0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
30     0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
31     0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
32     1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
33     0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
34     0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
35     0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
36     0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
37     1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
38     0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
39     1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
40   };
41 
42   /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
43      5-bit sequence */
44   z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
45   z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff];
46   return z;
47 }
48 
49 /* ---------------------------------------------------------------------- */
50 /* auxiliary bitmap manipulations */
51 
52 /* set the excess padding to 0 */
bm_clearexcess(potrace_bitmap_t * bm)53 static void bm_clearexcess(potrace_bitmap_t *bm) {
54   potrace_word mask;
55   int y;
56 
57   if (bm->w % BM_WORDBITS != 0) {
58     mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS));
59     for (y=0; y<bm->h; y++) {
60       *bm_index(bm, bm->w, y) &= mask;
61     }
62   }
63 }
64 
65 struct bbox_s {
66   int x0, x1, y0, y1;    /* bounding box */
67 };
68 typedef struct bbox_s bbox_t;
69 
70 /* clear the bm, assuming the bounding box is set correctly (faster
71    than clearing the whole bitmap) */
clear_bm_with_bbox(potrace_bitmap_t * bm,bbox_t * bbox)72 static void clear_bm_with_bbox(potrace_bitmap_t *bm, bbox_t *bbox) {
73   int imin = (bbox->x0 / BM_WORDBITS);
74   int imax = ((bbox->x1 + BM_WORDBITS-1) / BM_WORDBITS);
75   int i, y;
76 
77   for (y=bbox->y0; y<bbox->y1; y++) {
78     for (i=imin; i<imax; i++) {
79       bm_scanline(bm, y)[i] = 0;
80     }
81   }
82 }
83 
84 /* ---------------------------------------------------------------------- */
85 /* auxiliary functions */
86 
87 /* return the "majority" value of bitmap bm at intersection (x,y). We
88    assume that the bitmap is balanced at "radius" 1.  */
majority(potrace_bitmap_t * bm,int x,int y)89 static int majority(potrace_bitmap_t *bm, int x, int y) {
90   int i, a, ct;
91 
92   for (i=2; i<5; i++) { /* check at "radius" i */
93     ct = 0;
94     for (a=-i+1; a<=i-1; a++) {
95       ct += BM_GET(bm, x+a, y+i-1) ? 1 : -1;
96       ct += BM_GET(bm, x+i-1, y+a-1) ? 1 : -1;
97       ct += BM_GET(bm, x+a-1, y-i) ? 1 : -1;
98       ct += BM_GET(bm, x-i, y+a) ? 1 : -1;
99     }
100     if (ct>0) {
101       return 1;
102     } else if (ct<0) {
103       return 0;
104     }
105   }
106   return 0;
107 }
108 
109 /* ---------------------------------------------------------------------- */
110 /* decompose image into paths */
111 
112 /* efficiently invert bits [x,infty) and [xa,infty) in line y. Here xa
113    must be a multiple of BM_WORDBITS. */
xor_to_ref(potrace_bitmap_t * bm,int x,int y,int xa)114 static void xor_to_ref(potrace_bitmap_t *bm, int x, int y, int xa) {
115   int xhi = x & -BM_WORDBITS;
116   int xlo = x & (BM_WORDBITS-1);  /* = x % BM_WORDBITS */
117   int i;
118 
119   if (xhi<xa) {
120     for (i = xhi; i < xa; i+=BM_WORDBITS) {
121       *bm_index(bm, i, y) ^= BM_ALLBITS;
122     }
123   } else {
124     for (i = xa; i < xhi; i+=BM_WORDBITS) {
125       *bm_index(bm, i, y) ^= BM_ALLBITS;
126     }
127   }
128   /* note: the following "if" is needed because x86 treats a<<b as
129      a<<(b&31). I spent hours looking for this bug. */
130   if (xlo) {
131     *bm_index(bm, xhi, y) ^= (BM_ALLBITS << (BM_WORDBITS - xlo));
132   }
133 }
134 
135 /* a path is represented as an array of points, which are thought to
136    lie on the corners of pixels (not on their centers). The path point
137    (x,y) is the lower left corner of the pixel (x,y). Paths are
138    represented by the len/pt components of a path_t object (which
139    also stores other information about the path) */
140 
141 /* xor the given pixmap with the interior of the given path. Note: the
142    path must be within the dimensions of the pixmap. */
xor_path(potrace_bitmap_t * bm,path_t * p)143 static void xor_path(potrace_bitmap_t *bm, path_t *p) {
144   int xa, x, y, k, y1;
145 
146   if (p->priv->len <= 0) {  /* a path of length 0 is silly, but legal */
147     return;
148   }
149 
150   y1 = p->priv->pt[p->priv->len-1].y;
151 
152   xa = p->priv->pt[0].x & -BM_WORDBITS;
153   for (k=0; k<p->priv->len; k++) {
154     x = p->priv->pt[k].x;
155     y = p->priv->pt[k].y;
156 
157     if (y != y1) {
158       /* efficiently invert the rectangle [x,xa] x [y,y1] */
159       xor_to_ref(bm, x, min(y,y1), xa);
160       y1 = y;
161     }
162   }
163 }
164 
165 /* Find the bounding box of a given path. Path is assumed to be of
166    non-zero length. */
setbbox_path(bbox_t * bbox,path_t * p)167 static void setbbox_path(bbox_t *bbox, path_t *p) {
168   int x, y;
169   int k;
170 
171   bbox->y0 = INT_MAX;
172   bbox->y1 = 0;
173   bbox->x0 = INT_MAX;
174   bbox->x1 = 0;
175 
176   for (k=0; k<p->priv->len; k++) {
177     x = p->priv->pt[k].x;
178     y = p->priv->pt[k].y;
179 
180     if (x < bbox->x0) {
181       bbox->x0 = x;
182     }
183     if (x > bbox->x1) {
184       bbox->x1 = x;
185     }
186     if (y < bbox->y0) {
187       bbox->y0 = y;
188     }
189     if (y > bbox->y1) {
190       bbox->y1 = y;
191     }
192   }
193 }
194 
195 /* compute a path in the given pixmap, separating black from white.
196    Start path at the point (x0,x1), which must be an upper left corner
197    of the path. Also compute the area enclosed by the path. Return a
198    new path_t object, or NULL on error (note that a legitimate path
199    cannot have length 0). Sign is required for correct interpretation
200    of turnpolicies. */
findpath(potrace_bitmap_t * bm,int x0,int y0,int sign,int turnpolicy)201 static path_t *findpath(potrace_bitmap_t *bm, int x0, int y0, int sign, int turnpolicy) {
202   int x, y, dirx, diry, len, size, area;
203   int c, d, tmp;
204   point_t *pt, *pt1;
205   path_t *p = NULL;
206 
207   x = x0;
208   y = y0;
209   dirx = 0;
210   diry = -1;
211 
212   len = size = 0;
213   pt = NULL;
214   area = 0;
215 
216   while (1) {
217     /* add point to path */
218     if (len>=size) {
219       size += 100;
220       size = (int)(1.3 * size);
221       pt1 = (point_t *)realloc(pt, size * sizeof(point_t));
222       if (!pt1) {
223 	goto error;
224       }
225       pt = pt1;
226     }
227     pt[len].x = x;
228     pt[len].y = y;
229     len++;
230 
231     /* move to next point */
232     x += dirx;
233     y += diry;
234     area += x*diry;
235 
236     /* path complete? */
237     if (x==x0 && y==y0) {
238       break;
239     }
240 
241     /* determine next direction */
242     c = BM_GET(bm, x + (dirx+diry-1)/2, y + (diry-dirx-1)/2);
243     d = BM_GET(bm, x + (dirx-diry-1)/2, y + (diry+dirx-1)/2);
244 
245     if (c && !d) {               /* ambiguous turn */
246       if (turnpolicy == POTRACE_TURNPOLICY_RIGHT
247 	  || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+')
248 	  || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-')
249 	  || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand(x,y))
250 	  || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority(bm, x, y))
251 	  || (turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority(bm, x, y))) {
252 	tmp = dirx;              /* right turn */
253 	dirx = diry;
254 	diry = -tmp;
255       } else {
256 	tmp = dirx;              /* left turn */
257 	dirx = -diry;
258 	diry = tmp;
259       }
260     } else if (c) {              /* right turn */
261       tmp = dirx;
262       dirx = diry;
263       diry = -tmp;
264     } else if (!d) {             /* left turn */
265       tmp = dirx;
266       dirx = -diry;
267       diry = tmp;
268     }
269   } /* while this path */
270 
271   /* allocate new path object */
272   p = path_new();
273   if (!p) {
274     goto error;
275   }
276 
277   p->priv->pt = pt;
278   p->priv->len = len;
279   p->area = area;
280   p->sign = sign;
281 
282   return p;
283 
284  error:
285    free(pt);
286    return NULL;
287 }
288 
289 /* Give a tree structure to the given path list, based on "insideness"
290    testing. I.e., path A is considered "below" path B if it is inside
291    path B. The input pathlist is assumed to be ordered so that "outer"
292    paths occur before "inner" paths. The tree structure is stored in
293    the "childlist" and "sibling" components of the path_t
294    structure. The linked list structure is also changed so that
295    negative path components are listed immediately after their
296    positive parent.  Note: some backends may ignore the tree
297    structure, others may use it e.g. to group path components. We
298    assume that in the input, point 0 of each path is an "upper left"
299    corner of the path, as returned by bm_to_pathlist. This makes it
300    easy to find an "interior" point. The bm argument should be a
301    bitmap of the correct size (large enough to hold all the paths),
302    and will be used as scratch space. Return 0 on success or -1 on
303    error with errno set. */
304 
pathlist_to_tree(path_t * plist,potrace_bitmap_t * bm)305 static void pathlist_to_tree(path_t *plist, potrace_bitmap_t *bm) {
306   path_t *p, *p1;
307   path_t *heap, *heap1;
308   path_t *cur;
309   path_t *head;
310   path_t **plist_hook;          /* for fast appending to linked list */
311   path_t **hook_in, **hook_out; /* for fast appending to linked list */
312   bbox_t bbox;
313 
314   bm_clear(bm, 0);
315 
316   /* save original "next" pointers */
317   list_forall(p, plist) {
318     p->sibling = p->next;
319     p->childlist = NULL;
320   }
321 
322   heap = plist;
323 
324   /* the heap holds a list of lists of paths. Use "childlist" field
325      for outer list, "next" field for inner list. Each of the sublists
326      is to be turned into a tree. This code is messy, but it is
327      actually fast. Each path is rendered exactly once. We use the
328      heap to get a tail recursive algorithm: the heap holds a list of
329      pathlists which still need to be transformed. */
330 
331   while (heap) {
332     /* unlink first sublist */
333     cur = heap;
334     heap = heap->childlist;
335     cur->childlist = NULL;
336 
337     /* unlink first path */
338     head = cur;
339     cur = cur->next;
340     head->next = NULL;
341 
342     /* render path */
343     xor_path(bm, head);
344     setbbox_path(&bbox, head);
345 
346     /* now do insideness test for each element of cur; append it to
347        head->childlist if it's inside head, else append it to
348        head->next. */
349     hook_in=&head->childlist;
350     hook_out=&head->next;
351     list_forall_unlink(p, cur) {
352       if (p->priv->pt[0].y <= bbox.y0) {
353 	list_insert_beforehook(p, hook_out);
354 	/* append the remainder of the list to hook_out */
355 	*hook_out = cur;
356 	break;
357       }
358       if (BM_GET(bm, p->priv->pt[0].x, p->priv->pt[0].y-1)) {
359 	list_insert_beforehook(p, hook_in);
360       } else {
361 	list_insert_beforehook(p, hook_out);
362       }
363     }
364 
365     /* clear bm */
366     clear_bm_with_bbox(bm, &bbox);
367 
368     /* now schedule head->childlist and head->next for further
369        processing */
370     if (head->next) {
371       head->next->childlist = heap;
372       heap = head->next;
373     }
374     if (head->childlist) {
375       head->childlist->childlist = heap;
376       heap = head->childlist;
377     }
378   }
379 
380   /* copy sibling structure from "next" to "sibling" component */
381   p = plist;
382   while (p) {
383     p1 = p->sibling;
384     p->sibling = p->next;
385     p = p1;
386   }
387 
388   /* reconstruct a new linked list ("next") structure from tree
389      ("childlist", "sibling") structure. This code is slightly messy,
390      because we use a heap to make it tail recursive: the heap
391      contains a list of childlists which still need to be
392      processed. */
393   heap = plist;
394   if (heap) {
395     heap->next = NULL;  /* heap is a linked list of childlists */
396   }
397   plist = NULL;
398   plist_hook = &plist;
399   while (heap) {
400     heap1 = heap->next;
401     for (p=heap; p; p=p->sibling) {
402       /* p is a positive path */
403       /* append to linked list */
404       list_insert_beforehook(p, plist_hook);
405 
406       /* go through its children */
407       for (p1=p->childlist; p1; p1=p1->sibling) {
408 	/* append to linked list */
409 	list_insert_beforehook(p1, plist_hook);
410 	/* append its childlist to heap, if non-empty */
411 	if (p1->childlist) {
412 	  list_append(path_t, heap1, p1->childlist);
413 	}
414       }
415     }
416     heap = heap1;
417   }
418 
419   return;
420 }
421 
422 /* find the next set pixel in a row <= y. Pixels are searched first
423    left-to-right, then top-down. In other words, (x,y)<(x',y') if y>y'
424    or y=y' and x<x'. If found, return 0 and store pixel in
425    (*xp,*yp). Else return 1. Note that this function assumes that
426    excess bytes have been cleared with bm_clearexcess. */
findnext(potrace_bitmap_t * bm,int * xp,int * yp)427 static int findnext(potrace_bitmap_t *bm, int *xp, int *yp) {
428   int x;
429   int y;
430   int x0;
431 
432   x0 = (*xp) & ~(BM_WORDBITS-1);
433 
434   for (y=*yp; y>=0; y--) {
435     for (x=x0; x<bm->w && x>=0; x+=(unsigned)BM_WORDBITS) {
436       if (*bm_index(bm, x, y)) {
437 	while (!BM_GET(bm, x, y)) {
438 	  x++;
439 	}
440 	/* found */
441 	*xp = x;
442 	*yp = y;
443 	return 0;
444       }
445     }
446     x0 = 0;
447   }
448   /* not found */
449   return 1;
450 }
451 
452 /* Decompose the given bitmap into paths. Returns a linked list of
453    path_t objects with the fields len, pt, area, sign filled
454    in. Returns 0 on success with plistp set, or -1 on error with errno
455    set. */
456 
bm_to_pathlist(const potrace_bitmap_t * bm,path_t ** plistp,const potrace_param_t * param,progress_t * progress)457 int bm_to_pathlist(const potrace_bitmap_t *bm, path_t **plistp, const potrace_param_t *param, progress_t *progress) {
458   int x;
459   int y;
460   path_t *p;
461   path_t *plist = NULL;  /* linked list of path objects */
462   path_t **plist_hook = &plist;  /* used to speed up appending to linked list */
463   potrace_bitmap_t *bm1 = NULL;
464   int sign;
465 
466   bm1 = bm_dup(bm);
467   if (!bm1) {
468     goto error;
469   }
470 
471   /* be sure the byte padding on the right is set to 0, as the fast
472      pixel search below relies on it */
473   bm_clearexcess(bm1);
474 
475   /* iterate through components */
476   x = 0;
477   y = bm1->h - 1;
478   while (findnext(bm1, &x, &y) == 0) {
479     /* calculate the sign by looking at the original */
480     sign = BM_GET(bm, x, y) ? '+' : '-';
481 
482     /* calculate the path */
483     p = findpath(bm1, x, y+1, sign, param->turnpolicy);
484     if (p==NULL) {
485       goto error;
486     }
487 
488     /* update buffered image */
489     xor_path(bm1, p);
490 
491     /* if it's a turd, eliminate it, else append it to the list */
492     if (p->area <= param->turdsize) {
493       path_free(p);
494     } else {
495       list_insert_beforehook(p, plist_hook);
496     }
497 
498     if (bm1->h > 0) { /* to be sure */
499       progress_update(1-y/(double)bm1->h, progress);
500     }
501   }
502 
503   pathlist_to_tree(plist, bm1);
504   bm_free(bm1);
505   *plistp = plist;
506 
507   progress_update(1.0, progress);
508 
509   return 0;
510 
511  error:
512   bm_free(bm1);
513   list_forall_unlink(p, plist) {
514     path_free(p);
515   }
516   return -1;
517 }
518