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