1 /* autotrace.c --- Autotrace API
2
3 Copyright (C) 2000, 2001, 2002 Martin Weber
4
5 The author can be contacted at <martweb@gmx.net>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include "mallocvar.h"
22
23 #include "autotrace.h"
24 #include "exception.h"
25
26 #include "fit.h"
27 #include "bitmap.h"
28 #include "spline.h"
29
30 #include "image-header.h"
31 #include "image-proc.h"
32 #include "thin-image.h"
33
34
35 #define AT_DEFAULT_DPI 72
36
37 at_fitting_opts_type *
at_fitting_opts_new(void)38 at_fitting_opts_new(void)
39 {
40 at_fitting_opts_type * opts;
41 MALLOCVAR_NOFAIL(opts);
42 return opts;
43 }
44
45 at_fitting_opts_type *
at_fitting_opts_copy(at_fitting_opts_type * original)46 at_fitting_opts_copy (at_fitting_opts_type * original)
47 {
48 at_fitting_opts_type * new_opts;
49 if (original == NULL)
50 return NULL;
51
52 new_opts = at_fitting_opts_new ();
53 *new_opts = *original;
54 new_opts->backgroundSpec = original->backgroundSpec;
55 new_opts->background_color = original->background_color;
56 return new_opts;
57 }
58
59 void
at_fitting_opts_free(at_fitting_opts_type * opts)60 at_fitting_opts_free(at_fitting_opts_type * opts)
61 {
62 free(opts);
63 }
64
65 at_output_opts_type *
at_output_opts_new(void)66 at_output_opts_new(void)
67 {
68 at_output_opts_type * opts;
69 MALLOCVAR_NOFAIL(opts);
70 opts->dpi = AT_DEFAULT_DPI;
71 return opts;
72 }
73
74 at_output_opts_type *
at_output_opts_copy(at_output_opts_type * original)75 at_output_opts_copy(at_output_opts_type * original)
76 {
77 at_output_opts_type * opts = at_output_opts_new();
78 *opts = *original;
79 return opts;
80 }
81
82 void
at_output_opts_free(at_output_opts_type * opts)83 at_output_opts_free(at_output_opts_type * opts)
84 {
85 free(opts);
86 }
87
88 /* at_splines_new_full modifies its 'bitmap' argument
89 when it does the thin_image thing.
90 */
91 at_spline_list_array_type *
at_splines_new_full(at_bitmap_type * const bitmap,at_fitting_opts_type * const opts,at_msg_func msg_func,void * const msg_data,at_progress_func notify_progress,void * const progress_data,at_testcancel_func test_cancel,void * const testcancel_data)92 at_splines_new_full(at_bitmap_type * const bitmap,
93 at_fitting_opts_type * const opts,
94 at_msg_func msg_func,
95 void * const msg_data,
96 at_progress_func notify_progress,
97 void * const progress_data,
98 at_testcancel_func test_cancel,
99 void * const testcancel_data) {
100
101 at_spline_list_array_type * retval;
102 image_header_type image_header;
103 pixel_outline_list_type pixelOutlineList;
104 at_exception_type exp;
105 distance_map_type distanceMap;
106 bool haveDistMap;
107
108 exp = at_exception_new(msg_func, msg_data);
109
110 image_header.width = at_bitmap_get_width(bitmap);
111 image_header.height = at_bitmap_get_height(bitmap);
112
113 if (opts->centerline) {
114 if (opts->preserve_width) {
115 /* Preserve line width prior to thinning. */
116 bool const paddedTrue = true;
117 distanceMap = new_distance_map(*bitmap, 255, paddedTrue, &exp);
118 haveDistMap = true;
119 } else
120 haveDistMap = false;
121 thin_image(bitmap, opts->backgroundSpec, opts->background_color, &exp);
122 } else
123 haveDistMap = false;
124
125 if (at_exception_got_fatal(&exp))
126 retval = NULL;
127 else {
128 if (opts->centerline) {
129 pixel background_color;
130
131 if (opts->backgroundSpec)
132 background_color = opts->background_color;
133 else
134 PPM_ASSIGN(background_color, 255, 255, 255);
135
136 pixelOutlineList =
137 find_centerline_pixels(*bitmap, background_color,
138 notify_progress, progress_data,
139 test_cancel, testcancel_data, &exp);
140 } else
141 pixelOutlineList =
142 find_outline_pixels(*bitmap,
143 opts->backgroundSpec,
144 opts->background_color,
145 notify_progress, progress_data,
146 test_cancel, testcancel_data, &exp);
147
148 if (at_exception_got_fatal(&exp) ||
149 (test_cancel && test_cancel(testcancel_data)))
150 retval = NULL;
151 else {
152 at_spline_list_array_type * splinesP;
153
154 MALLOCVAR_NOFAIL(splinesP);
155 fit_outlines_to_splines(pixelOutlineList, opts,
156 haveDistMap ? &distanceMap : NULL,
157 image_header.width,
158 image_header.height,
159 &exp,
160 notify_progress, progress_data,
161 test_cancel, testcancel_data,
162 splinesP);
163
164 if (at_exception_got_fatal(&exp) ||
165 (test_cancel && test_cancel(testcancel_data)))
166 retval = NULL;
167 else {
168 if (notify_progress)
169 notify_progress(1.0, progress_data);
170
171 retval = splinesP;
172 }
173 free_pixel_outline_list(&pixelOutlineList);
174 }
175 if (haveDistMap)
176 free_distance_map(&distanceMap);
177 }
178 return retval;
179 }
180
181
182
183 void
at_splines_write(at_output_write_func outputWriter,FILE * const writeto,at_output_opts_type * const optsArg,at_spline_list_array_type * const splinesP,at_msg_func msgFunc,void * const msgData)184 at_splines_write(at_output_write_func outputWriter,
185 FILE * const writeto,
186 at_output_opts_type * const optsArg,
187 at_spline_list_array_type * const splinesP,
188 at_msg_func msgFunc,
189 void * const msgData) {
190
191 at_output_opts_type * optsP;
192 bool newOpts;
193 int llx, lly, urx, ury;
194 llx = 0;
195 lly = 0;
196 urx = splinesP->width;
197 ury = splinesP->height;
198
199 if (optsArg == NULL) {
200 newOpts = true;
201 optsP = at_output_opts_new();
202 } else {
203 newOpts = false;
204 optsP = optsArg;
205 }
206 (*outputWriter)(writeto, "DUMMYFILENAME",
207 llx, lly, urx, ury, optsP, *splinesP,
208 msgFunc, msgData);
209 if (newOpts)
210 at_output_opts_free(optsP);
211 }
212
213
214
215 void
at_splines_free(at_spline_list_array_type * const splines)216 at_splines_free(at_spline_list_array_type * const splines) {
217
218 free_spline_list_array(splines);
219 free(splines);
220 }
221