Tue, 25 Mar 2003 09:38:08 +0000
support both big- and little-endian TIFF files. don't crash in close_input_file() if current_input_handler is NULL.
1 /*
2 * tumble: build a PDF file from image files
3 *
4 * Main program
5 * $Id: tumble.c,v 1.41 2003/03/20 08:23:37 eric Exp $
6 * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation. Note that permission is
11 * not granted to redistribute this program under the terms of any
12 * other version of the General Public License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
22 */
25 #include <stdarg.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
34 #include "semantics.h"
35 #include "parser.tab.h"
36 #include "tumble.h"
37 #include "bitblt.h"
38 #include "pdf.h"
39 #include "tumble_input.h"
42 #define MAX_INPUT_FILES 5000
44 typedef struct output_file_t
45 {
46 struct output_file_t *next;
47 char *name;
48 pdf_file_handle pdf;
49 } output_file_t;
52 int verbose;
55 output_file_t *output_files;
56 output_file_t *out;
59 char *progname;
62 bool close_pdf_output_files (void);
65 void usage (void)
66 {
67 fprintf (stderr, "\n");
68 fprintf (stderr, "tumble - Copyright 2001-2003 Eric Smith <eric@brouhaha.com>\n");
69 fprintf (stderr, "http://tumble.brouhaha.com/\n");
70 fprintf (stderr, "\n");
71 fprintf (stderr, "usage:\n");
72 fprintf (stderr, " %s [options] -c <control.tum>\n", progname);
73 fprintf (stderr, " %s [options] <input.tif>... -o <output.pdf>\n", progname);
74 fprintf (stderr, "options:\n");
75 fprintf (stderr, " -v verbose\n");
76 fprintf (stderr, " -b <fmt> create bookmarks\n");
77 fprintf (stderr, "bookmark format:\n");
78 fprintf (stderr, " %%F file name (sans suffix)\n");
79 fprintf (stderr, " %%p page number\n");
80 }
83 /* generate fatal error message to stderr, doesn't return */
84 void fatal (int ret, char *format, ...) __attribute__ ((noreturn));
86 void fatal (int ret, char *format, ...)
87 {
88 va_list ap;
90 fprintf (stderr, "fatal error");
91 if (format)
92 {
93 fprintf (stderr, ": ");
94 va_start (ap, format);
95 vfprintf (stderr, format, ap);
96 va_end (ap);
97 }
98 else
99 fprintf (stderr, "\n");
100 if (ret == 1)
101 usage ();
102 close_input_file ();
103 close_pdf_output_files ();
104 exit (ret);
105 }
108 bool close_pdf_output_files (void)
109 {
110 output_file_t *o, *n;
112 for (o = output_files; o; o = n)
113 {
114 n = o->next;
115 pdf_close (o->pdf, PDF_PAGE_MODE_USE_OUTLINES);
116 free (o->name);
117 free (o);
118 }
119 out = NULL;
120 output_files = NULL;
121 return (1);
122 }
124 bool open_pdf_output_file (char *name,
125 pdf_file_attributes_t *attributes)
126 {
127 output_file_t *o;
129 if (out && (strcmp (name, out->name) == 0))
130 return (1);
131 for (o = output_files; o; o = o->next)
132 if (strcmp (name, o->name) == 0)
133 {
134 out = o;
135 return (1);
136 }
137 o = calloc (1, sizeof (output_file_t));
138 if (! o)
139 {
140 fprintf (stderr, "can't calloc output file struct for '%s'\n", name);
141 return (0);
142 }
144 o->name = strdup (name);
145 if (! o->name)
146 {
147 fprintf (stderr, "can't strdup output filename '%s'\n", name);
148 free (o);
149 return (0);
150 }
152 o->pdf = pdf_create (name);
153 if (! o->pdf)
154 {
155 fprintf (stderr, "can't open output file '%s'\n", name);
156 free (o->name);
157 free (o);
158 return (0);
159 }
161 if (attributes->author)
162 pdf_set_author (o->pdf, attributes->author);
163 if (attributes->creator)
164 pdf_set_creator (o->pdf, attributes->creator);
165 if (attributes->title)
166 pdf_set_title (o->pdf, attributes->title);
167 if (attributes->subject)
168 pdf_set_subject (o->pdf, attributes->subject);
169 if (attributes->keywords)
170 pdf_set_keywords (o->pdf, attributes->keywords);
172 /* prepend new output file onto list */
173 o->next = output_files;
174 output_files = o;
176 out = o;
177 return (1);
178 }
181 #define MAX_BOOKMARK_LEVEL 20
182 static pdf_bookmark_handle bookmark_vector [MAX_BOOKMARK_LEVEL + 1] = { NULL };
185 bool process_page (int image, /* range 1 .. n */
186 input_attributes_t input_attributes,
187 bookmark_t *bookmarks,
188 page_label_t *page_label)
189 {
190 pdf_page_handle page;
191 image_info_t image_info;
193 if (! get_image_info (image, input_attributes, & image_info))
194 return (0);
196 page = pdf_new_page (out->pdf,
197 image_info.width_points,
198 image_info.height_points);
200 if (! process_image (image, input_attributes, & image_info, page))
201 return (0);
203 while (bookmarks)
204 {
205 if (bookmarks->level <= MAX_BOOKMARK_LEVEL)
206 {
207 pdf_bookmark_handle parent = bookmark_vector [bookmarks->level - 1];
208 bookmark_vector [bookmarks->level] = pdf_new_bookmark (parent,
209 bookmarks->name,
210 0,
211 page);
212 }
213 else
214 {
215 (void) pdf_new_bookmark (bookmark_vector [MAX_BOOKMARK_LEVEL],
216 bookmarks->name,
217 0,
218 page);
219 }
220 bookmarks = bookmarks->next;
221 }
223 if (page_label)
224 pdf_new_page_label (out->pdf,
225 page_label->page_index,
226 page_label->base,
227 page_label->count,
228 page_label->style,
229 page_label->prefix);
231 return (page != NULL);
232 }
235 #define MAX_BOOKMARK_NAME_LEN 500
238 static int filename_length_without_suffix (char *in_fn)
239 {
240 char *p;
241 int len = strlen (in_fn);
243 p = strrchr (in_fn, '.');
244 if (p && match_input_suffix (p))
245 return (p - in_fn);
246 return (len);
247 }
250 /* $$$ this function should ensure that it doesn't overflow the name string! */
251 static void generate_bookmark_name (char *name,
252 char *bookmark_fmt,
253 char *in_fn,
254 int page)
255 {
256 bool meta = 0;
257 int len;
259 while (*bookmark_fmt)
260 {
261 if (meta)
262 {
263 meta = 0;
264 switch (*bookmark_fmt)
265 {
266 case '%':
267 *(name++) = '%';
268 break;
269 case 'F':
270 len = filename_length_without_suffix (in_fn);
271 strncpy (name, in_fn, len);
272 name += len;
273 break;
274 case 'p':
275 sprintf (name, "%d", page);
276 name += strlen (name);
277 break;
278 default:
279 break;
280 }
281 }
282 else
283 switch (*bookmark_fmt)
284 {
285 case '%':
286 meta = 1;
287 break;
288 default:
289 *(name++) = *bookmark_fmt;
290 }
291 bookmark_fmt++;
292 }
293 *name = '\0';
294 }
297 void main_args (char *out_fn,
298 int inf_count,
299 char **in_fn,
300 char *bookmark_fmt)
301 {
302 int i, ip;
303 input_attributes_t input_attributes;
304 pdf_file_attributes_t output_attributes;
305 bookmark_t bookmark;
306 char bookmark_name [MAX_BOOKMARK_NAME_LEN];
308 bookmark.next = NULL;
309 bookmark.level = 1;
310 bookmark.name = & bookmark_name [0];
312 memset (& input_attributes, 0, sizeof (input_attributes));
313 memset (& output_attributes, 0, sizeof (output_attributes));
315 if (! open_pdf_output_file (out_fn, & output_attributes))
316 fatal (3, "error opening output file \"%s\"\n", out_fn);
317 for (i = 0; i < inf_count; i++)
318 {
319 if (! open_input_file (in_fn [i]))
320 fatal (3, "error opening input file \"%s\"\n", in_fn [i]);
321 for (ip = 1;; ip++)
322 {
323 fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
324 if (bookmark_fmt)
325 generate_bookmark_name (& bookmark_name [0],
326 bookmark_fmt,
327 in_fn [i],
328 ip);
329 if (! process_page (ip, input_attributes,
330 bookmark_fmt ? & bookmark : NULL,
331 NULL))
332 fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
333 if (last_input_page ())
334 break;
335 }
336 if (verbose)
337 fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]);
338 if (! close_input_file ())
339 fatal (3, "error closing input file \"%s\"\n", in_fn [i]);
340 }
341 if (! close_pdf_output_files ())
342 fatal (3, "error closing output file \"%s\"\n", out_fn);
343 }
346 void main_control (char *control_fn)
347 {
348 if (! parse_control_file (control_fn))
349 fatal (2, "error parsing control file\n");
350 if (! process_controls ())
351 fatal (3, "error processing control file\n");
352 }
355 int main (int argc, char *argv[])
356 {
357 char *control_fn = NULL;
358 char *out_fn = NULL;
359 char *bookmark_fmt = NULL;
360 int inf_count = 0;
361 char *in_fn [MAX_INPUT_FILES];
363 progname = argv [0];
365 pdf_init ();
367 init_tiff_handler ();
368 init_jpeg_handler ();
370 while (--argc)
371 {
372 if (argv [1][0] == '-')
373 {
374 if (strcmp (argv [1], "-v") == 0)
375 verbose++;
376 else if (strcmp (argv [1], "-o") == 0)
377 {
378 if (argc)
379 {
380 argc--;
381 argv++;
382 out_fn = argv [1];
383 }
384 else
385 fatal (1, "missing filename after \"-o\" option\n");
386 }
387 else if (strcmp (argv [1], "-c") == 0)
388 {
389 if (argc)
390 {
391 argc--;
392 argv++;
393 control_fn = argv [1];
394 }
395 else
396 fatal (1, "missing filename after \"-s\" option\n");
397 }
398 else if (strcmp (argv [1], "-b") == 0)
399 {
400 if (argc)
401 {
402 argc--;
403 argv++;
404 bookmark_fmt = argv [1];
405 }
406 else
407 fatal (1, "missing format string after \"-b\" option\n");
408 }
409 else
410 fatal (1, "unrecognized option \"%s\"\n", argv [1]);
411 }
412 else if (inf_count < MAX_INPUT_FILES)
413 in_fn [inf_count++] = argv [1];
414 else
415 fatal (1, "exceeded maximum of %d input files\n", MAX_INPUT_FILES);
416 argv++;
417 }
419 if (! ((! out_fn) ^ (! control_fn)))
420 fatal (1, "either a control file or an output file (but not both) must be specified\n");
422 if (out_fn && ! inf_count)
423 fatal (1, "no input files specified\n");
425 if (control_fn && inf_count)
426 fatal (1, "if control file is provided, input files can't be specified as arguments\n");
428 if (control_fn)
429 main_control (control_fn);
430 else
431 main_args (out_fn, inf_count, in_fn, bookmark_fmt);
433 close_input_file ();
434 close_pdf_output_files ();
435 exit (0);
436 }