|
1 | | -from pathops import op, PathOp |
| 1 | +from pathops import op, PathOp, Path |
2 | 2 | from vectorizing.geometry.potrace import potrace_path_to_compound_path |
3 | 3 |
|
4 | | -def remove_layering(traced_bitmaps): |
| 4 | +def create_background_rect(img, padding): |
| 5 | + """ |
| 6 | + Creates a rectangle that matches the image dimensions plus |
| 7 | + some padding. |
| 8 | +
|
| 9 | + Parameters: |
| 10 | + img: A Pillow image instance. |
| 11 | +
|
| 12 | + Returns: |
| 13 | + The rectangle. |
| 14 | + """ |
| 15 | + rect = Path() |
| 16 | + rect.moveTo(-padding, -padding) |
| 17 | + rect.lineTo(img.width + padding, -padding) |
| 18 | + rect.lineTo(img.width + padding, img.height + padding) |
| 19 | + rect.lineTo(-padding, img.height + padding) |
| 20 | + rect.close() |
| 21 | + return rect |
| 22 | + |
| 23 | +def remove_layering(traced_bitmaps, img): |
5 | 24 | """ |
6 | 25 | Performs boolean operations on a list of traced bitmaps |
7 | 26 | to ensure that they are all disjoint. |
8 | 27 |
|
9 | | - Parameters: |
10 | | - traced_bitmaps: The list of traced bitmaps (potrace paths). |
| 28 | + This function uses a technique devised to try to minimize |
| 29 | + the holes created / outright failures of SKPath boolean operations. |
| 30 | + Even so, a failure can still happen (and often does), particularly |
| 31 | + for very intricate paths (usually coming from real world photographs). |
| 32 | + In such cases, the routine fallbacks to a mixture of disjoint paths |
| 33 | + (the ones for which the boolean operations didn't fail), and layered paths. |
| 34 | +
|
| 35 | + Parameters: |
| 36 | + traced_bitmaps: The list of traced bitmaps (potrace paths). |
| 37 | + img: A Pillow image. |
11 | 38 |
|
12 | | - Returns: |
13 | | - The processed list of compound paths. |
| 39 | + Returns: |
| 40 | + The processed list of compound paths. |
14 | 41 | """ |
15 | 42 | compound_paths = [ |
16 | 43 | potrace_path_to_compound_path(traced) for traced in traced_bitmaps |
17 | 44 | ] |
18 | 45 |
|
| 46 | + disjoint_paths = [] |
19 | 47 | for x in range(len(compound_paths) - 1): |
20 | | - next = compound_paths[x + 1] |
21 | | - compound_paths[x] = op(compound_paths[x], next, PathOp.DIFFERENCE) |
| 48 | + # Each base path has bigger padding to reduce |
| 49 | + # the amount of overlapping borders. |
| 50 | + base = create_background_rect(img, (x + 1) * 10) |
| 51 | + |
| 52 | + to_subtract = Path() |
| 53 | + for y in range(0, x): |
| 54 | + to_subtract.addPath(disjoint_paths[y]) |
| 55 | + to_subtract.addPath(compound_paths[x + 1]) |
| 56 | + |
| 57 | + try: |
| 58 | + result = op(base, to_subtract, PathOp.DIFFERENCE) |
| 59 | + except: |
| 60 | + break |
| 61 | + disjoint_paths.append(result) |
| 62 | + |
| 63 | + for x in range(len(disjoint_paths)): |
| 64 | + try: |
| 65 | + disjoint_paths[x] = op(disjoint_paths[x], create_background_rect(img, 0), PathOp.INTERSECTION) |
| 66 | + except: |
| 67 | + return compound_paths |
22 | 68 |
|
23 | | - return compound_paths |
| 69 | + disjoint_paths = disjoint_paths + compound_paths[len(disjoint_paths) : len(compound_paths)] |
| 70 | + return disjoint_paths |
0 commit comments