tumble.c

Thu, 20 Mar 2003 06:54:08 +0000

author
eric
date
Thu, 20 Mar 2003 06:54:08 +0000
changeset 141
752599b50ff3
parent 139
ec2a06d8a2a6
child 149
460c336ec8d7
permissions
-rw-r--r--

more JPEG support. added input file handler API.

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