Skip to content

Commit 3c61f79

Browse files
authored
Merge pull request #57 from Kittl/main
Deploy to production 2025-05-27 / 1
2 parents 419e920 + daaea63 commit 3c61f79

7 files changed

Lines changed: 42 additions & 29 deletions

File tree

vectorizing/__init__.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ def process_binary(img):
3535
solver = BinarySolver(img)
3636
return solver.solve()
3737

38-
def process_color(img, color_count, timer):
39-
solver = ColorSolver(img, color_count, timer)
38+
def process_color(img, color_count, tolerance, timer):
39+
solver = ColorSolver(img, color_count, tolerance, timer)
4040
return solver.solve()
4141

4242
def validate_args(args):
@@ -56,12 +56,17 @@ def validate_args(args):
5656
if not only_numbers:
5757
return False
5858

59+
tolerance = args.get("tolerance")
60+
if tolerance is not None and tolerance < 0:
61+
return False
62+
5963
return SimpleNamespace(
60-
crop_box = box,
61-
solver = solver,
62-
url = args.get('url'),
63-
raw = args.get('raw'),
64-
color_count = args.get('color_count'),
64+
crop_box=box,
65+
solver=solver,
66+
url=args.get("url"),
67+
raw=args.get("raw"),
68+
color_count=args.get("color_count"),
69+
tolerance=args.get("tolerance"),
6570
)
6671

6772
def invalid_args():
@@ -87,6 +92,10 @@ def index():
8792
color_count = args.color_count
8893
raw = args.raw
8994
crop_box = args.crop_box
95+
tolerance = args.tolerance
96+
97+
if tolerance is None:
98+
tolerance = 0.2
9099

91100
try:
92101
timer = Timer()
@@ -105,7 +114,7 @@ def index():
105114

106115
else:
107116
timer.start_timer('Color Solver - Total')
108-
solved = process_color(img, color_count, timer)
117+
solved = process_color(img, color_count, tolerance, timer)
109118
timer.end_timer()
110119

111120
compound_paths, colors, width, height = solved
@@ -122,7 +131,7 @@ def index():
122131
timer.end_timer()
123132

124133
timer.start_timer('Bounds Creation')
125-
bounds = compound_path_list_bounds(compound_paths)
134+
bounds = compound_path_list_bounds(compound_paths, tolerance)
126135
timer.end_timer()
127136

128137
app.logger.info(timer.timelog())

vectorizing/geometry/bounds.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,19 @@ def compute_total_bounds(bounds_list):
3434
)
3535

3636
# Calculates bounds of a path made out CubicBeziers and SegmentLists
37-
def path_bounds(path):
38-
bounds = [item.bounds() for item in path]
37+
def path_bounds(path, tolerance):
38+
bounds = [item.bounds(tolerance) for item in path]
3939
return compute_total_bounds(bounds)
4040

4141
# Calculates bounds of a compound path, meaning a list of paths
42-
def compound_path_bounds(compound_path):
43-
bounds = [path_bounds(path) for path in compound_path]
42+
def compound_path_bounds(compound_path, tolerance):
43+
bounds = [path_bounds(path, tolerance) for path in compound_path]
4444
return compute_total_bounds(bounds)
4545

4646
# Calculates bounds of a list of compound paths
47-
def compound_path_list_bounds(compound_path_list):
47+
def compound_path_list_bounds(compound_path_list, tolerance):
4848
bounds = [
49-
compound_path_bounds(compound_path)
49+
compound_path_bounds(compound_path, tolerance)
5050
for compound_path in compound_path_list
5151
if len(compound_path) > 0
5252
]

vectorizing/geometry/cubic_bezier.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ def subdivide(points):
7979
)
8080

8181
@njit
82-
def flatten(points):
82+
def flatten(points, tolerance):
8383
stack = [points]
8484
flattened = []
8585

8686
while len(stack):
8787
first = stack.pop()
8888

89-
if is_flat_enough(first):
89+
if is_flat_enough(first, tolerance):
9090
flattened.append(first[0])
9191
flattened.append(first[1])
9292

@@ -113,9 +113,9 @@ def scaled(self, s):
113113
self.p3 * s
114114
)
115115

116-
def flattened(self):
116+
def flattened(self, tolerance):
117117
points = (tuple(self.p0), tuple(self.p1), tuple(self.p2), tuple(self.p3))
118-
return SegmentList(np.array(flatten(points)))
118+
return SegmentList(np.array(flatten(points, tolerance)))
119119

120-
def bounds(self):
121-
return self.flattened().bounds()
120+
def bounds(self, tolerance):
121+
return self.flattened(tolerance).bounds(tolerance)

vectorizing/geometry/potrace.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,11 @@ def unfold_polygon(folded_polygon):
5555
# Given a compound path, it converts it to a compound polygon
5656
# by flattening curves.
5757
# All coordinates can be scaled for convenience (see pyclipper)
58-
def compound_path_to_compound_polygon(compound_path, scale = 1):
59-
polygons = [[item.flattened().scaled(scale) for item in path] for path in compound_path]
58+
def compound_path_to_compound_polygon(compound_path, tolerance, scale=1):
59+
polygons = [
60+
[item.flattened(tolerance).scaled(scale) for item in path]
61+
for path in compound_path
62+
]
6063
return [unfold_polygon(folded_polygon) for folded_polygon in polygons]
6164

6265
# Given a compound polygon, it converts it to a compound path.

vectorizing/geometry/segment_list.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ def __init__(self, points):
1111
def scaled(self, s):
1212
return SegmentList(self.points * s)
1313

14-
def flattened(self):
14+
def flattened(self, _):
1515
return self
1616

1717
def to_list(self):
1818
return list(self.points)
1919

20-
def bounds(self):
20+
def bounds(self, _):
2121
t = self.points.T
2222
x = t[0]
2323
y = t[1]

vectorizing/solvers/color/ColorSolver.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
from vectorizing.solvers.color.bitmaps import create_bitmaps
88

99
class ColorSolver:
10-
def __init__(self, img, color_count, timer):
10+
def __init__(self, img, color_count, tolerance, timer):
1111
color_count = color_count or ColorSolver.DEFAULT_COLOR_COUNT
1212
color_count = max(color_count, ColorSolver.MIN_COLOR_COUNT)
1313
color_count = min(color_count, ColorSolver.MAX_COLOR_COUNT)
1414
self.color_count = color_count
15+
self.tolerance = tolerance
1516

1617
self.img = limit_size(img)
1718

@@ -34,7 +35,7 @@ def solve(self):
3435
self.timer.end_timer()
3536

3637
self.timer.start_timer('Polygon Clipping')
37-
compound_paths = remove_layering(traced_bitmaps)
38+
compound_paths = remove_layering(traced_bitmaps, self.tolerance)
3839
self.timer.end_timer()
3940

4041
return [

vectorizing/solvers/color/clip.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@
1313

1414
# NOTE: The clipper library uses integer coordinates only for numerical robustness.
1515
# That's why coordinates are scaled by a big factor, to preserve precision.
16-
def remove_layering(traced_bitmaps):
16+
def remove_layering(traced_bitmaps, tolerance):
1717
compound_paths = [
1818
potrace_path_to_compound_path(traced)
1919
for traced in traced_bitmaps
2020
]
2121

2222
compound_polygons = [
23-
compound_path_to_compound_polygon(compound_path, SCALE)
23+
compound_path_to_compound_polygon(compound_path, tolerance, SCALE)
2424
for compound_path in compound_paths
2525
]
2626

0 commit comments

Comments
 (0)