25using PathSegment = potrace_dpoint_t[3];
27static int to_potrace(
const TurnPolicy turn_policy)
29 switch (turn_policy) {
30 case TurnPolicy ::Foreground:
31 return POTRACE_TURNPOLICY_BLACK;
32 case TurnPolicy ::Background:
33 return POTRACE_TURNPOLICY_WHITE;
34 case TurnPolicy ::Left:
35 return POTRACE_TURNPOLICY_LEFT;
36 case TurnPolicy ::Right:
37 return POTRACE_TURNPOLICY_RIGHT;
38 case TurnPolicy ::Minority:
39 return POTRACE_TURNPOLICY_MINORITY;
40 case TurnPolicy ::Majority:
41 return POTRACE_TURNPOLICY_MAJORITY;
42 case TurnPolicy ::Random:
43 return POTRACE_TURNPOLICY_RANDOM;
46 return POTRACE_TURNPOLICY_MINORITY;
51 constexpr int BM_WORDSIZE = int(
sizeof(potrace_word));
52 constexpr int BM_WORDBITS = 8 * BM_WORDSIZE;
55 const int32_t dy = (
size.x + BM_WORDBITS - 1) / BM_WORDBITS;
79 constexpr int BM_WORDSIZE = int(
sizeof(potrace_word));
80 constexpr int BM_WORDBITS = 8 * BM_WORDSIZE;
81 constexpr potrace_word BM_HIBIT = potrace_word(1) << (BM_WORDBITS - 1);
88 const int num_words =
bm.dy *
bm.h;
89 const int words_per_scanline =
bm.dy;
95 for (const int y : range) {
96 Span<potrace_word> scanline_words = words.slice(
97 IndexRange(words_per_scanline * y, words_per_scanline));
98 const MutableSpan<ColorGeometry4b> scanline_colors = colors.slice(
99 IndexRange(y * ibuf->x, ibuf->x));
100 for (uint32_t x = 0; x < ibuf->x; x++) {
101 const potrace_word &word = scanline_words[x / BM_WORDBITS];
102 const potrace_word mask = BM_HIBIT >> (x & (BM_WORDBITS - 1));
103 scanline_colors[x] = ((word & mask) != 0 ? ColorGeometry4b(255, 0, 0, 255) :
104 ColorGeometry4b(0, 0, 255, 255));
112Trace *trace_bitmap(
const TraceParams &
params, Bitmap &
bm)
114 potrace_param_t *po_params = potrace_param_default();
118 po_params->turdsize =
params.size_threshold;
119 po_params->turnpolicy = to_potrace(
params.turn_policy);
120 po_params->alphamax =
params.alpha_max;
121 po_params->opticurve =
params.optimize_curves;
122 po_params->opttolerance =
params.optimize_tolerance;
124 potrace_state_t *st = potrace_trace(po_params, &
bm);
125 potrace_param_free(po_params);
127 if (!st || st->status != POTRACE_STATUS_OK) {
129 potrace_state_free(st);
138 potrace_state_free(trace);
154 auto project_pixel = [&](
const potrace_dpoint_t &point) ->
float3 {
155 return pixel_to_position(
int2(point.x, point.y));
160 for (
const potrace_path_t *path = trace.plist; path !=
nullptr; path = path->next) {
161 const Span<int> path_tags = {path->curve.tag, path->curve.n};
165 for (
const int segment_i : path_segments.
index_range()) {
166 switch (path_tags[segment_i]) {
170 case POTRACE_CURVETO:
178 offsets.
append(point_num);
182 const OffsetIndices points_by_curve = offset_indices::accumulate_counts_to_offsets(offsets);
183 if (points_by_curve.is_empty()) {
187 bke::CurvesGeometry curves(points_by_curve.total_size(), points_by_curve.size());
188 curves.offsets_for_write().copy_from(offsets);
192 curves.update_curve_types();
194 curves.cyclic_for_write().fill(
true);
196 bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
202 bke::SpanAttributeWriter<bool> holes = attributes.lookup_or_add_for_write_span<
bool>(
203 hole_attribute_id, bke::AttrDomain::Curve);
207 for (
const potrace_path_t *path = trace.plist; path !=
nullptr; path = path->next, ++curve_i) {
208 const Span<int> path_tags = {path->curve.tag, path->curve.n};
211 const IndexRange points = points_by_curve[curve_i];
218 holes.span[curve_i] = (path->sign ==
'-');
223 int point_i = points.
last();
224 auto next_point = [&]() {
225 point_i = (point_i == points.
last() ? points.
first() : point_i + 1);
228 for (
const int segment_i : path_segments.
index_range()) {
229 const PathSegment &
segment = path_segments[segment_i];
230 switch (path_tags[segment_i]) {
238 positions[point_i] = project_pixel(segment[1]);
243 positions[point_i] = project_pixel(segment[2]);
246 case POTRACE_CURVETO:
250 handle_positions_right[point_i] = project_pixel(segment[0]);
253 positions[point_i] = project_pixel(segment[2]);
255 handle_positions_left[point_i] = project_pixel(segment[1]);
265 curves.tag_topology_changed();
266 curves.tag_positions_changed();
267 curves.tag_radii_changed();
270 curves.calculate_bezier_auto_handles();