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 }