00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <string.h>
00010 #include <limits.h>
00011
00012 #include "potracelib.h"
00013 #include "curve.h"
00014 #include "lists.h"
00015 #include "auxiliary.h"
00016 #include "bitmap.h"
00017 #include "decompose.h"
00018 #include "progress.h"
00019
00020
00021
00022
00023
00024 static void bm_clearexcess(potrace_bitmap_t *bm) {
00025 potrace_word mask;
00026 int y;
00027
00028 if (bm->w % BM_WORDBITS != 0) {
00029 mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS));
00030 for (y=0; y<bm->h; y++) {
00031 *bm_index(bm, bm->w, y) &= mask;
00032 }
00033 }
00034 }
00035
00036 struct bbox_s {
00037 int x0, x1, y0, y1;
00038 };
00039 typedef struct bbox_s bbox_t;
00040
00041
00042
00043 static void clear_bm_with_bbox(potrace_bitmap_t *bm, bbox_t *bbox) {
00044 int imin = (bbox->x0 / BM_WORDBITS);
00045 int imax = ((bbox->x1 + BM_WORDBITS-1) / BM_WORDBITS);
00046 int i, y;
00047
00048 for (y=bbox->y0; y<bbox->y1; y++) {
00049 for (i=imin; i<imax; i++) {
00050 bm_scanline(bm, y)[i] = 0;
00051 }
00052 }
00053 }
00054
00055
00056
00057
00058
00059 static inline int detrand(int x, int y) {
00060 unsigned int z;
00061 static const unsigned char t[256] = {
00062
00063
00064 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
00065 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
00066 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
00067 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
00068 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
00069 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
00070 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
00071 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
00072 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
00073 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
00074 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
00075 };
00076
00077
00078
00079 z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
00080 z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff];
00081 return z & 1;
00082 }
00083
00084
00085
00086 static int majority(potrace_bitmap_t *bm, int x, int y) {
00087 int i, a, ct;
00088
00089 for (i=2; i<5; i++) {
00090 ct = 0;
00091 for (a=-i+1; a<=i-1; a++) {
00092 ct += BM_GET(bm, x+a, y+i-1) ? 1 : -1;
00093 ct += BM_GET(bm, x+i-1, y+a-1) ? 1 : -1;
00094 ct += BM_GET(bm, x+a-1, y-i) ? 1 : -1;
00095 ct += BM_GET(bm, x-i, y+a) ? 1 : -1;
00096 }
00097 if (ct>0) {
00098 return 1;
00099 } else if (ct<0) {
00100 return 0;
00101 }
00102 }
00103 return 0;
00104 }
00105
00106
00107
00108
00109
00110
00111 static void xor_to_ref(potrace_bitmap_t *bm, int x, int y, int xa) {
00112 int xhi = x & -BM_WORDBITS;
00113 int xlo = x & (BM_WORDBITS-1);
00114 int i;
00115
00116 if (xhi<xa) {
00117 for (i = xhi; i < xa; i+=BM_WORDBITS) {
00118 *bm_index(bm, i, y) ^= BM_ALLBITS;
00119 }
00120 } else {
00121 for (i = xa; i < xhi; i+=BM_WORDBITS) {
00122 *bm_index(bm, i, y) ^= BM_ALLBITS;
00123 }
00124 }
00125
00126
00127 if (xlo) {
00128 *bm_index(bm, xhi, y) ^= (BM_ALLBITS << (BM_WORDBITS - xlo));
00129 }
00130 }
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 static void xor_path(potrace_bitmap_t *bm, path_t *p) {
00141 int xa, x, y, k, y1;
00142
00143 if (p->priv->len <= 0) {
00144 return;
00145 }
00146
00147 y1 = p->priv->pt[p->priv->len-1].y;
00148
00149 xa = p->priv->pt[0].x & -BM_WORDBITS;
00150 for (k=0; k<p->priv->len; k++) {
00151 x = p->priv->pt[k].x;
00152 y = p->priv->pt[k].y;
00153
00154 if (y != y1) {
00155
00156 xor_to_ref(bm, x, min(y,y1), xa);
00157 y1 = y;
00158 }
00159 }
00160 }
00161
00162
00163
00164 static void setbbox_path(bbox_t *bbox, path_t *p) {
00165 int x, y;
00166 int k;
00167
00168 bbox->y0 = INT_MAX;
00169 bbox->y1 = 0;
00170 bbox->x0 = INT_MAX;
00171 bbox->x1 = 0;
00172
00173 for (k=0; k<p->priv->len; k++) {
00174 x = p->priv->pt[k].x;
00175 y = p->priv->pt[k].y;
00176
00177 if (x < bbox->x0) {
00178 bbox->x0 = x;
00179 }
00180 if (x > bbox->x1) {
00181 bbox->x1 = x;
00182 }
00183 if (y < bbox->y0) {
00184 bbox->y0 = y;
00185 }
00186 if (y > bbox->y1) {
00187 bbox->y1 = y;
00188 }
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 static path_t *findpath(potrace_bitmap_t *bm, int x0, int y0, int sign, int turnpolicy) {
00199 int x, y, dirx, diry, len, size, area;
00200 int c, d, tmp;
00201 point_t *pt, *pt1;
00202 path_t *p = NULL;
00203
00204 x = x0;
00205 y = y0;
00206 dirx = 0;
00207 diry = -1;
00208
00209 len = size = 0;
00210 pt = NULL;
00211 area = 0;
00212
00213 while (1) {
00214
00215 if (len>=size) {
00216 size += 100;
00217 size = (int)(1.3 * size);
00218 pt1 = (point_t *)realloc(pt, size * sizeof(point_t));
00219 if (!pt1) {
00220 goto error;
00221 }
00222 pt = pt1;
00223 }
00224 pt[len].x = x;
00225 pt[len].y = y;
00226 len++;
00227
00228
00229 x += dirx;
00230 y += diry;
00231 area += x*diry;
00232
00233
00234 if (x==x0 && y==y0) {
00235 break;
00236 }
00237
00238
00239 c = BM_GET(bm, x + (dirx+diry-1)/2, y + (diry-dirx-1)/2);
00240 d = BM_GET(bm, x + (dirx-diry-1)/2, y + (diry+dirx-1)/2);
00241
00242 if (c && !d) {
00243 if (turnpolicy == POTRACE_TURNPOLICY_RIGHT
00244 || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+')
00245 || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-')
00246 || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand(x,y))
00247 || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority(bm, x, y))
00248 || (turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority(bm, x, y))) {
00249 tmp = dirx;
00250 dirx = diry;
00251 diry = -tmp;
00252 } else {
00253 tmp = dirx;
00254 dirx = -diry;
00255 diry = tmp;
00256 }
00257 } else if (c) {
00258 tmp = dirx;
00259 dirx = diry;
00260 diry = -tmp;
00261 } else if (!d) {
00262 tmp = dirx;
00263 dirx = -diry;
00264 diry = tmp;
00265 }
00266 }
00267
00268
00269 p = path_new();
00270 if (!p) {
00271 goto error;
00272 }
00273
00274 p->priv->pt = pt;
00275 p->priv->len = len;
00276 p->area = area;
00277 p->sign = sign;
00278
00279 return p;
00280
00281 error:
00282 free(pt);
00283 return NULL;
00284 }
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 static void pathlist_to_tree(path_t *plist, potrace_bitmap_t *bm) {
00303 path_t *p, *p1;
00304 path_t *heap, *heap1;
00305 path_t *cur;
00306 path_t *head;
00307 path_t **hook, **hook_in, **hook_out;
00308 bbox_t bbox;
00309
00310 bm_clear(bm, 0);
00311
00312
00313 list_forall(p, plist) {
00314 p->sibling = p->next;
00315 p->childlist = NULL;
00316 }
00317
00318 heap = plist;
00319
00320
00321
00322
00323
00324
00325
00326
00327 while (heap) {
00328
00329 cur = heap;
00330 heap = heap->childlist;
00331 cur->childlist = NULL;
00332
00333
00334 head = cur;
00335 cur = cur->next;
00336 head->next = NULL;
00337
00338
00339 xor_path(bm, head);
00340 setbbox_path(&bbox, head);
00341
00342
00343
00344
00345 hook_in=&head->childlist;
00346 hook_out=&head->next;
00347 list_forall_unlink(p, cur) {
00348 if (p->priv->pt[0].y <= bbox.y0) {
00349 list_insert_beforehook(p, hook_out);
00350
00351 *hook_out = cur;
00352 break;
00353 }
00354 if (BM_GET(bm, p->priv->pt[0].x, p->priv->pt[0].y-1)) {
00355 list_insert_beforehook(p, hook_in);
00356 } else {
00357 list_insert_beforehook(p, hook_out);
00358 }
00359 }
00360
00361
00362 clear_bm_with_bbox(bm, &bbox);
00363
00364
00365
00366 if (head->next) {
00367 head->next->childlist = heap;
00368 heap = head->next;
00369 }
00370 if (head->childlist) {
00371 head->childlist->childlist = heap;
00372 heap = head->childlist;
00373 }
00374 }
00375
00376
00377 p = plist;
00378 while (p) {
00379 p1 = p->sibling;
00380 p->sibling = p->next;
00381 p = p1;
00382 }
00383
00384
00385
00386
00387
00388
00389 heap = plist;
00390 if (heap) {
00391 heap->next = NULL;
00392 }
00393 plist = NULL;
00394 hook = &plist;
00395 while (heap) {
00396 heap1 = heap->next;
00397 for (p=heap; p; p=p->sibling) {
00398
00399
00400 list_insert_beforehook(p, hook);
00401
00402
00403 for (p1=p->childlist; p1; p1=p1->sibling) {
00404
00405 list_insert_beforehook(p1, hook);
00406
00407 if (p1->childlist) {
00408 list_append(path_t, heap1, p1->childlist);
00409 }
00410 }
00411 }
00412 heap = heap1;
00413 }
00414
00415 return;
00416 }
00417
00418
00419
00420
00421
00422
00423 static int findnext(potrace_bitmap_t *bm, int *xp, int *yp) {
00424 int x;
00425 int y;
00426
00427 for (y=*yp; y>=0; y--) {
00428 for (x=0; x<bm->w; x+=BM_WORDBITS) {
00429 if (*bm_index(bm, x, y)) {
00430 while (!BM_GET(bm, x, y)) {
00431 x++;
00432 }
00433
00434 *xp = x;
00435 *yp = y;
00436 return 0;
00437 }
00438 }
00439 }
00440
00441 return 1;
00442 }
00443
00444
00445
00446
00447
00448
00449 int bm_to_pathlist(const potrace_bitmap_t *bm, path_t **plistp, const potrace_param_t *param, progress_t *progress) {
00450 int x;
00451 int y;
00452 path_t *p;
00453 path_t *plist = NULL;
00454 path_t **hook = &plist;
00455 potrace_bitmap_t *bm1 = NULL;
00456 int sign;
00457
00458 bm1 = bm_dup(bm);
00459 if (!bm1) {
00460 goto error;
00461 }
00462
00463
00464
00465 bm_clearexcess(bm1);
00466
00467
00468 y = bm1->h - 1;
00469 while (findnext(bm1, &x, &y) == 0) {
00470
00471 sign = BM_GET(bm, x, y) ? '+' : '-';
00472
00473
00474 p = findpath(bm1, x, y+1, sign, param->turnpolicy);
00475 if (p==NULL) {
00476 goto error;
00477 }
00478
00479
00480 xor_path(bm1, p);
00481
00482
00483 if (p->area <= param->turdsize) {
00484 path_free(p);
00485 } else {
00486 list_insert_beforehook(p, hook);
00487 }
00488
00489 if (bm1->h > 0) {
00490 progress_update(1-y/(double)bm1->h, progress);
00491 }
00492 }
00493
00494 pathlist_to_tree(plist, bm1);
00495 bm_free(bm1);
00496 *plistp = plist;
00497
00498 progress_update(1.0, progress);
00499
00500 return 0;
00501
00502 error:
00503 bm_free(bm1);
00504 list_forall_unlink(p, plist) {
00505 path_free(p);
00506 }
00507 return -1;
00508 }