-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvectorizer_potrace.cpp
More file actions
100 lines (87 loc) · 4.3 KB
/
vectorizer_potrace.cpp
File metadata and controls
100 lines (87 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
* Vectorix -- line-based image vectorizer
* (c) 2016 Jan Hadrava <had@atrey.karlin.mff.cuni.cz>
*/
#include <cstring>
#include <cerrno>
#include <cstdio>
#include <new>
#include "v_image.h"
#include "pnm_handler.h"
#include "vectorizer_potrace.h"
#include "logger.h"
#ifdef VECTORIX_USE_POTRACE
#include "potrace/include/potracelib.h"
#endif
// Vectorize using potracelib
namespace vectorix {
#ifdef VECTORIX_USE_POTRACE
v_image vectorizer_potrace::vectorize(const pnm_image &original) { // Vectorize using potrace library
pnm_image image = original;
image.convert(pnm_variant_type::binary_pbm); // Potrace uses binary images, packed in word -- almost similar to binary PBM
potrace_bitmap_t pot_bitmap; // Prepare Potrace data structure with image
pot_bitmap.w = image.width;
pot_bitmap.h = image.height;
pot_bitmap.dy = ((image.width - 1) / (8*sizeof(potrace_word))) + 1; // Potrace uses this for accessing lines
pot_bitmap.map = new potrace_word[pot_bitmap.h * pot_bitmap.dy]; // Buffer for real image data data
for (int i = 0; i < image.height; i++) {
for (int j = 0; j < pot_bitmap.dy; j++) {
pot_bitmap.map[i*pot_bitmap.dy + j] = 0;
for (int x = 0; (x < sizeof(potrace_word)) && (x+j*sizeof(potrace_word) < ((image.width-1)/8+1)); x++) { // Fill word with bytes form binary PBM.
pot_bitmap.map[i*pot_bitmap.dy + j] |= (static_cast<potrace_word> (image.data[i*((image.width-1)/8+1) + j*sizeof(potrace_word) + x])) << (8*(sizeof(potrace_word)-x-1));
}
}
}
potrace_param_t *pot_params = potrace_param_default(); // Use default Potrace parameters
if (!pot_params) {
log.log<log_level::error>("Error: " __FILE__ ":%i: In %s(): %s\n", __LINE__, __func__, strerror(errno));
throw std::bad_alloc();
}
potrace_state_t *pot_state = potrace_trace(pot_params, &pot_bitmap); // Run tracing
if (!pot_state || pot_state->status != POTRACE_STATUS_OK) {
log.log<log_level::error>("Error: " __FILE__ ":%i: In %s(): %s\n", __LINE__, __func__, strerror(errno));
throw std::bad_alloc();
}
delete [] pot_bitmap.map; // Binary image is no longer needed
v_image vector(image.width, image.height); // Prepare empty v_image for output
potrace_path_t *pot_path = pot_state->plist;
while (pot_path != NULL) { // Convert each path from Potrace to our v_line format
v_line line;
v_co color(0, 0, 0); // Foreground color should be black since Potrace knows only BW images
if (pot_path->sign == '-') {
color = v_co(255, 255, 255); // Inner curve (subtract) --> white color
if (vector.line.back().get_group() == v_line_group::group_normal) // last segment has + sign
vector.line.back().set_group(v_line_group::group_first); // last segment should be first in a group
if (vector.line.back().get_group() == v_line_group::group_last) // last segment has - sign
vector.line.back().set_group(v_line_group::group_continue); // last segment should be continuation of a group
line.set_group(v_line_group::group_last);
}
line.add_point(v_pt(pot_path->curve.c[pot_path->curve.n - 1][2].x, pot_path->curve.c[pot_path->curve.n - 1][2].y), color); // Add last point --> closed path
for (int n = 0; n < pot_path->curve.n; n++) {
if (pot_path->curve.tag[n] == POTRACE_CORNER) { // Two straight segments
line.add_point(v_pt(pot_path->curve.c[n][1].x, pot_path->curve.c[n][1].y), color);
line.add_point(v_pt(pot_path->curve.c[n][2].x, pot_path->curve.c[n][2].y), color);
}
else if (pot_path->curve.tag[n] == POTRACE_CURVETO) { // Bezier curve with two control points
line.add_point( \
v_pt(pot_path->curve.c[n][0].x, pot_path->curve.c[n][0].y), \
v_pt(pot_path->curve.c[n][1].x, pot_path->curve.c[n][1].y), \
v_pt(pot_path->curve.c[n][2].x, pot_path->curve.c[n][2].y), color);
}
}
line.set_type(v_line_type::fill); // Change type to fill (from default stroke)
vector.add_line(line); // Add line to output
pot_path = pot_path->next; // Process next potrace path
}
potrace_state_free(pot_state);
potrace_param_free(pot_params);
return vector;
}
#else
v_image vectorizer_potrace::vectorize(const pnm_image &original) { // Vectorize using potrace library
v_image vector(original.width, original.height); // Prepare empty v_image for output
log.log<log_level::warning>("Warning: Vectorix was not compiled with Potrace support, the output will be empty\n");
return vector;
}
#endif
}; // namespace