tumble.c

Fri, 14 Mar 2003 08:24:37 +0000

author
eric
date
Fri, 14 Mar 2003 08:24:37 +0000
changeset 131
4b8c80d77f76
parent 127
9fca72858fcd
child 133
76c197fe2eeb
permissions
-rw-r--r--

finished implementing page labels.

eric@10 1 /*
eric@125 2 * tumble: build a PDF file from image files
eric@29 3 *
eric@10 4 * Main program
eric@131 5 * $Id: tumble.c,v 1.34 2003/03/14 00:24:37 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@10 33 #include <tiffio.h>
eric@47 34 #define TIFF_REVERSE_BITS
eric@47 35
eric@10 36 #include "bitblt.h"
eric@18 37 #include "semantics.h"
eric@10 38 #include "parser.tab.h"
eric@125 39 #include "tumble.h"
eric@62 40 #include "pdf.h"
eric@10 41
eric@10 42
eric@49 43 #define MAX_INPUT_FILES 5000
eric@49 44
eric@28 45 #define POINTS_PER_INCH 72
eric@28 46
eric@28 47 /* page size limited by Acrobat Reader to 45 inches on a side */
eric@28 48 #define PAGE_MAX_INCHES 45
eric@28 49 #define PAGE_MAX_POINTS (PAGE_MAX_INCHES * POINTS_PER_INCH)
eric@28 50
eric@28 51
eric@26 52 typedef struct output_file_t
eric@26 53 {
eric@26 54 struct output_file_t *next;
eric@26 55 char *name;
eric@62 56 pdf_file_handle pdf;
eric@26 57 } output_file_t;
eric@26 58
eric@26 59
eric@49 60 int verbose;
eric@49 61
eric@49 62
eric@26 63 char *in_filename;
eric@10 64 TIFF *in;
eric@26 65 output_file_t *output_files;
eric@26 66 output_file_t *out;
eric@10 67
eric@10 68
eric@49 69 char *progname;
eric@49 70
eric@49 71
eric@49 72 bool close_tiff_input_file (void);
eric@49 73 bool close_pdf_output_files (void);
eric@49 74
eric@49 75
eric@49 76 void usage (void)
eric@49 77 {
eric@50 78 fprintf (stderr, "\n");
eric@125 79 fprintf (stderr, "tumble - Copyright 2001-2003 Eric Smith <eric@brouhaha.com>\n");
eric@127 80 fprintf (stderr, "http://tumble.brouhaha.com/\n");
eric@50 81 fprintf (stderr, "\n");
eric@49 82 fprintf (stderr, "usage:\n");
eric@49 83 fprintf (stderr, " %s [options] -s spec\n", progname);
eric@49 84 fprintf (stderr, " %s [options] <input.tif>... -o <output.pdf>\n", progname);
eric@49 85 fprintf (stderr, "options:\n");
eric@49 86 fprintf (stderr, " -v verbose\n");
eric@62 87 fprintf (stderr, " -b fmt create bookmarks\n");
eric@62 88 fprintf (stderr, "bookmark format:\n");
eric@74 89 fprintf (stderr, " %%F file name (sans suffix)\n");
eric@62 90 fprintf (stderr, " %%p page number\n");
eric@49 91 }
eric@49 92
eric@49 93
eric@49 94 /* generate fatal error message to stderr, doesn't return */
eric@49 95 void fatal (int ret, char *format, ...)
eric@49 96 {
eric@49 97 va_list ap;
eric@49 98
eric@49 99 fprintf (stderr, "fatal error");
eric@49 100 if (format)
eric@49 101 {
eric@49 102 fprintf (stderr, ": ");
eric@49 103 va_start (ap, format);
eric@49 104 vfprintf (stderr, format, ap);
eric@49 105 va_end (ap);
eric@49 106 }
eric@49 107 else
eric@49 108 fprintf (stderr, "\n");
eric@49 109 if (ret == 1)
eric@49 110 usage ();
eric@49 111 close_tiff_input_file ();
eric@49 112 close_pdf_output_files ();
eric@49 113 exit (ret);
eric@49 114 }
eric@49 115
eric@49 116
eric@48 117 bool close_tiff_input_file (void)
eric@10 118 {
eric@10 119 if (in)
eric@26 120 {
eric@26 121 free (in_filename);
eric@26 122 TIFFClose (in);
eric@26 123 }
eric@10 124 in = NULL;
eric@26 125 in_filename = NULL;
eric@10 126 return (1);
eric@10 127 }
eric@10 128
eric@49 129
eric@48 130 bool open_tiff_input_file (char *name)
eric@10 131 {
eric@10 132 if (in)
eric@26 133 {
eric@26 134 if (strcmp (name, in_filename) == 0)
eric@26 135 return (1);
eric@26 136 close_tiff_input_file ();
eric@26 137 }
eric@26 138 in_filename = strdup (name);
eric@26 139 if (! in_filename)
eric@26 140 {
eric@26 141 fprintf (stderr, "can't strdup input filename '%s'\n", name);
eric@26 142 return (0);
eric@26 143 }
eric@10 144 in = TIFFOpen (name, "r");
eric@10 145 if (! in)
eric@10 146 {
eric@10 147 fprintf (stderr, "can't open input file '%s'\n", name);
eric@26 148 free (in_filename);
eric@10 149 return (0);
eric@10 150 }
eric@10 151 return (1);
eric@10 152 }
eric@10 153
eric@10 154
eric@48 155 bool close_pdf_output_files (void)
eric@10 156 {
eric@26 157 output_file_t *o, *n;
eric@26 158
eric@26 159 for (o = output_files; o; o = n)
eric@26 160 {
eric@26 161 n = o->next;
eric@62 162 pdf_close (o->pdf);
eric@26 163 free (o->name);
eric@26 164 free (o);
eric@26 165 }
eric@10 166 out = NULL;
eric@26 167 output_files = NULL;
eric@10 168 return (1);
eric@10 169 }
eric@10 170
eric@48 171 bool open_pdf_output_file (char *name,
eric@48 172 pdf_file_attributes_t *attributes)
eric@10 173 {
eric@26 174 output_file_t *o;
eric@26 175
eric@26 176 if (out && (strcmp (name, out->name) == 0))
eric@26 177 return (1);
eric@26 178 for (o = output_files; o; o = o->next)
eric@26 179 if (strcmp (name, o->name) == 0)
eric@26 180 {
eric@26 181 out = o;
eric@26 182 return (1);
eric@26 183 }
eric@26 184 o = calloc (1, sizeof (output_file_t));
eric@29 185 if (! o)
eric@10 186 {
eric@26 187 fprintf (stderr, "can't calloc output file struct for '%s'\n", name);
eric@26 188 return (0);
eric@26 189 }
eric@26 190
eric@26 191 o->name = strdup (name);
eric@26 192 if (! o->name)
eric@26 193 {
eric@26 194 fprintf (stderr, "can't strdup output filename '%s'\n", name);
eric@26 195 free (o);
eric@10 196 return (0);
eric@10 197 }
eric@26 198
eric@121 199 o->pdf = pdf_create (name, (attributes->has_bookmarks ?
eric@121 200 PDF_PAGE_MODE_USE_OUTLINES :
eric@121 201 PDF_PAGE_MODE_USE_NONE));
eric@26 202 if (! o->pdf)
eric@26 203 {
eric@26 204 fprintf (stderr, "can't open output file '%s'\n", name);
eric@26 205 free (o->name);
eric@26 206 free (o);
eric@26 207 return (0);
eric@26 208 }
eric@26 209
eric@30 210 if (attributes->author)
eric@62 211 pdf_set_author (o->pdf, attributes->author);
eric@30 212 if (attributes->creator)
eric@62 213 pdf_set_creator (o->pdf, attributes->creator);
eric@30 214 if (attributes->title)
eric@62 215 pdf_set_title (o->pdf, attributes->title);
eric@30 216 if (attributes->subject)
eric@62 217 pdf_set_subject (o->pdf, attributes->subject);
eric@30 218 if (attributes->keywords)
eric@62 219 pdf_set_keywords (o->pdf, attributes->keywords);
eric@30 220
eric@26 221 /* prepend new output file onto list */
eric@26 222 o->next = output_files;
eric@26 223 output_files = o;
eric@26 224
eric@26 225 out = o;
eric@10 226 return (1);
eric@10 227 }
eric@10 228
eric@10 229
eric@42 230 /* frees original! */
eric@42 231 static Bitmap *resize_bitmap (Bitmap *src,
eric@92 232 double x_resolution,
eric@92 233 double y_resolution,
eric@36 234 input_attributes_t input_attributes)
eric@32 235 {
eric@32 236 Rect src_rect;
eric@42 237 Point dest_min;
eric@42 238 Bitmap *dest;
eric@32 239
eric@42 240 int width_pixels = input_attributes.page_size.width * x_resolution;
eric@42 241 int height_pixels = input_attributes.page_size.height * y_resolution;
eric@42 242
eric@42 243 src_rect.min.x = (rect_width (& src->rect) - width_pixels) / 2;
eric@42 244 src_rect.min.y = (rect_height (& src->rect) - height_pixels) / 2;
eric@42 245 src_rect.max.x = src_rect.min.x + width_pixels;
eric@42 246 src_rect.max.y = src_rect.min.y + height_pixels;
eric@36 247
eric@42 248 dest_min.x = 0;
eric@42 249 dest_min.y = 0;
eric@32 250
eric@43 251 dest = bitblt (src, & src_rect, NULL, & dest_min, TF_SRC, 0);
eric@42 252 free_bitmap (src);
eric@42 253 return (dest);
eric@42 254 }
eric@32 255
eric@42 256
eric@42 257 /* "in place" rotation */
eric@42 258 static void rotate_bitmap (Bitmap *src,
eric@42 259 input_attributes_t input_attributes)
eric@42 260 {
eric@36 261 switch (input_attributes.rotation)
eric@32 262 {
eric@42 263 case 0: break;
eric@42 264 case 90: rot_90 (src); break;
eric@42 265 case 180: rot_180 (src); break;
eric@42 266 case 270: rot_270 (src); break;
eric@32 267 default:
eric@32 268 fprintf (stderr, "rotation must be 0, 90, 180, or 270\n");
eric@32 269 }
eric@32 270 }
eric@32 271
eric@32 272
eric@32 273 #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
eric@32 274
eric@49 275
eric@49 276 bool last_tiff_page (void)
eric@49 277 {
eric@49 278 return (TIFFLastDirectory (in));
eric@49 279 }
eric@49 280
eric@49 281
eric@131 282 static pdf_page_handle process_tiff_page (int image, /* range 1 .. n */
eric@131 283 input_attributes_t input_attributes)
eric@10 284 {
eric@48 285 uint32_t image_length, image_width;
eric@48 286 uint32_t dest_image_length, dest_image_width;
eric@10 287 #ifdef CHECK_DEPTH
eric@48 288 uint32_t image_depth;
eric@10 289 #endif
eric@29 290
eric@48 291 uint16_t samples_per_pixel;
eric@48 292 uint16_t bits_per_sample;
eric@48 293 uint16_t planar_config;
eric@32 294
eric@48 295 uint16_t resolution_unit;
eric@94 296 float x_resolution, y_resolution;
eric@92 297 double dest_x_resolution, dest_y_resolution;
eric@32 298
eric@62 299 double width_points, height_points; /* really 1/72 inch units rather than
eric@62 300 points */
eric@28 301
eric@42 302 Rect rect;
eric@74 303 Bitmap *bitmap = NULL;
eric@42 304
eric@32 305 int row;
eric@10 306
eric@131 307 pdf_page_handle page = NULL;
eric@28 308
eric@10 309 if (! TIFFSetDirectory (in, image - 1))
eric@10 310 {
eric@10 311 fprintf (stderr, "can't find page %d of input file\n", image);
eric@10 312 goto fail;
eric@10 313 }
eric@10 314 if (1 != TIFFGetField (in, TIFFTAG_IMAGELENGTH, & image_length))
eric@10 315 {
eric@10 316 fprintf (stderr, "can't get image length\n");
eric@10 317 goto fail;
eric@10 318 }
eric@10 319 if (1 != TIFFGetField (in, TIFFTAG_IMAGEWIDTH, & image_width))
eric@10 320 {
eric@10 321 fprintf (stderr, "can't get image width\n");
eric@10 322 goto fail;
eric@10 323 }
eric@29 324
eric@29 325 if (1 != TIFFGetField (in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
eric@29 326 {
eric@29 327 fprintf (stderr, "can't get samples per pixel\n");
eric@29 328 goto fail;
eric@29 329 }
eric@29 330
eric@10 331 #ifdef CHECK_DEPTH
eric@10 332 if (1 != TIFFGetField (in, TIFFTAG_IMAGEDEPTH, & image_depth))
eric@10 333 {
eric@10 334 fprintf (stderr, "can't get image depth\n");
eric@10 335 goto fail;
eric@10 336 }
eric@10 337 #endif
eric@10 338
eric@10 339 if (1 != TIFFGetField (in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
eric@10 340 {
eric@10 341 fprintf (stderr, "can't get bits per sample\n");
eric@10 342 goto fail;
eric@10 343 }
eric@10 344
eric@10 345 if (1 != TIFFGetField (in, TIFFTAG_PLANARCONFIG, & planar_config))
eric@10 346 planar_config = 1;
eric@10 347
eric@10 348 if (1 != TIFFGetField (in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
eric@10 349 resolution_unit = 2;
eric@10 350 if (1 != TIFFGetField (in, TIFFTAG_XRESOLUTION, & x_resolution))
eric@10 351 x_resolution = 300;
eric@10 352 if (1 != TIFFGetField (in, TIFFTAG_YRESOLUTION, & y_resolution))
eric@10 353 y_resolution = 300;
eric@10 354
eric@29 355 if (samples_per_pixel != 1)
eric@29 356 {
eric@29 357 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
eric@29 358 goto fail;
eric@29 359 }
eric@29 360
eric@10 361 #ifdef CHECK_DEPTH
eric@10 362 if (image_depth != 1)
eric@10 363 {
eric@10 364 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
eric@10 365 goto fail;
eric@10 366 }
eric@10 367 #endif
eric@10 368
eric@10 369 if (bits_per_sample != 1)
eric@10 370 {
eric@10 371 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
eric@10 372 goto fail;
eric@10 373 }
eric@10 374
eric@10 375 if (planar_config != 1)
eric@10 376 {
eric@10 377 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
eric@10 378 goto fail;
eric@10 379 }
eric@10 380
eric@36 381 if (input_attributes.has_resolution)
eric@32 382 {
eric@36 383 x_resolution = input_attributes.x_resolution;
eric@36 384 y_resolution = input_attributes.y_resolution;
eric@32 385 }
eric@32 386
eric@32 387 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
eric@32 388 {
eric@32 389 dest_image_width = image_length;
eric@32 390 dest_image_length = image_width;
eric@32 391 dest_x_resolution = y_resolution;
eric@32 392 dest_y_resolution = x_resolution;
eric@62 393 SWAP (double, width_points, height_points); /* $$$ not yet set!!! */
eric@32 394 }
eric@32 395 else
eric@32 396 {
eric@32 397 dest_image_width = image_width;
eric@32 398 dest_image_length = image_length;
eric@32 399 dest_x_resolution = x_resolution;
eric@32 400 dest_y_resolution = y_resolution;
eric@32 401 }
eric@32 402
eric@42 403 rect.min.x = 0;
eric@42 404 rect.min.y = 0;
eric@42 405 rect.max.x = image_width;
eric@42 406 rect.max.y = image_length;
eric@42 407
eric@42 408 bitmap = create_bitmap (& rect);
eric@42 409
eric@42 410 if (! bitmap)
eric@10 411 {
eric@32 412 fprintf (stderr, "can't allocate bitmap\n");
eric@10 413 goto fail;
eric@10 414 }
eric@10 415
eric@10 416 for (row = 0; row < image_length; row++)
eric@32 417 if (1 != TIFFReadScanline (in,
eric@43 418 bitmap->bits + row * bitmap->row_words,
eric@32 419 row,
eric@32 420 0))
eric@32 421 {
eric@32 422 fprintf (stderr, "can't read TIFF scanline\n");
eric@32 423 goto fail;
eric@32 424 }
eric@28 425
eric@47 426 #ifdef TIFF_REVERSE_BITS
eric@48 427 reverse_bits ((uint8_t *) bitmap->bits,
eric@108 428 image_length * bitmap->row_words * sizeof (word_t));
eric@47 429 #endif /* TIFF_REVERSE_BITS */
eric@47 430
eric@94 431 #if 0
eric@46 432 if (input_attributes.has_page_size)
eric@46 433 bitmap = resize_bitmap (bitmap,
eric@46 434 x_resolution,
eric@46 435 y_resolution,
eric@46 436 input_attributes);
eric@94 437 #endif
eric@42 438
eric@42 439 rotate_bitmap (bitmap,
eric@42 440 input_attributes);
eric@28 441
eric@42 442 width_points = (rect_width (& bitmap->rect) / dest_x_resolution) * POINTS_PER_INCH;
eric@42 443 height_points = (rect_height (& bitmap->rect) / dest_y_resolution) * POINTS_PER_INCH;
eric@36 444
eric@36 445 if ((height_points > PAGE_MAX_POINTS) || (width_points > PAGE_MAX_POINTS))
eric@36 446 {
eric@36 447 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
eric@36 448 goto fail;
eric@36 449 }
eric@36 450
eric@62 451 page = pdf_new_page (out->pdf, width_points, height_points);
eric@28 452
eric@121 453 #if 0
eric@121 454 pdf_write_text (page);
eric@121 455 #else
eric@62 456 pdf_write_g4_fax_image (page,
eric@66 457 0, 0, /* x, y */
eric@66 458 width_points, height_points,
eric@62 459 bitmap,
eric@62 460 0, /* ImageMask */
eric@66 461 0, 0, 0, /* r, g, b */
eric@62 462 0); /* BlackIs1 */
eric@121 463 #endif
eric@62 464
eric@131 465 if (bitmap)
eric@131 466 free_bitmap (bitmap);
eric@131 467 return (page);
eric@10 468
eric@10 469 fail:
eric@74 470 if (bitmap)
eric@74 471 free_bitmap (bitmap);
eric@74 472
eric@131 473 return (NULL);
eric@10 474 }
eric@10 475
eric@10 476
eric@108 477 #if 0
eric@131 478 pdf_page_handle process_jpeg_page (int image, /* range 1 .. n */
eric@131 479 input_attributes_t input_attributes)
eric@108 480 {
eric@108 481 FILE *f;
eric@108 482 pdf_page_handle page;
eric@108 483
eric@108 484 f = fopen (filename, "rb");
eric@108 485 if (! f)
eric@108 486 fatal ("error opening input file '%s'\n", filename);
eric@108 487
eric@108 488 page = pdf_new_page (out->pdf, width_points, height_points);
eric@108 489
eric@108 490 pdf_write_jpeg_image (page,
eric@108 491 0, 0, /* x, y */
eric@108 492 width_points, height_points,
eric@108 493 f);
eric@108 494
eric@131 495 return (page);
eric@108 496 }
eric@108 497 #endif
eric@108 498
eric@108 499
eric@108 500 bool process_page (int image, /* range 1 .. n */
eric@108 501 input_attributes_t input_attributes,
eric@131 502 bookmark_t *bookmarks,
eric@131 503 page_label_t *page_label)
eric@108 504 {
eric@131 505 pdf_page_handle page;
eric@131 506
eric@131 507 page = process_tiff_page (image, input_attributes);
eric@108 508
eric@131 509 while (bookmarks)
eric@131 510 {
eric@131 511 /* $$$ need to handle level here */
eric@131 512 pdf_new_bookmark (NULL, bookmarks->name, 0, page);
eric@131 513 bookmarks = bookmarks->next;
eric@131 514 }
eric@108 515
eric@131 516 if (page_label)
eric@131 517 pdf_new_page_label (out->pdf,
eric@131 518 page_label->page_index,
eric@131 519 page_label->base,
eric@131 520 page_label->count,
eric@131 521 page_label->style,
eric@131 522 page_label->prefix);
eric@131 523
eric@131 524 return (page != NULL);
eric@108 525 }
eric@108 526
eric@108 527
eric@74 528 #define MAX_BOOKMARK_NAME_LEN 500
eric@74 529
eric@74 530
eric@74 531 static int filename_length_without_suffix (char *in_fn)
eric@74 532 {
eric@74 533 char *p;
eric@74 534 int len = strlen (in_fn);
eric@74 535
eric@74 536 p = strrchr (in_fn, '.');
eric@74 537 if (p && ((strcasecmp (p, ".tif") == 0) ||
eric@74 538 (strcasecmp (p, ".tiff") == 0)))
eric@74 539 return (p - in_fn);
eric@74 540 return (len);
eric@74 541 }
eric@74 542
eric@74 543
eric@74 544 /* $$$ this function should ensure that it doesn't overflow the name string! */
eric@74 545 static void generate_bookmark_name (char *name,
eric@74 546 char *bookmark_fmt,
eric@74 547 char *in_fn,
eric@74 548 int page)
eric@74 549 {
eric@74 550 bool meta = 0;
eric@74 551 int len;
eric@74 552
eric@74 553 while (*bookmark_fmt)
eric@74 554 {
eric@74 555 if (meta)
eric@74 556 {
eric@74 557 meta = 0;
eric@74 558 switch (*bookmark_fmt)
eric@74 559 {
eric@74 560 case '%':
eric@74 561 *(name++) = '%';
eric@74 562 break;
eric@74 563 case 'F':
eric@74 564 len = filename_length_without_suffix (in_fn);
eric@74 565 strncpy (name, in_fn, len);
eric@74 566 name += len;
eric@74 567 break;
eric@74 568 case 'p':
eric@74 569 sprintf (name, "%d", page);
eric@74 570 name += strlen (name);
eric@74 571 break;
eric@74 572 default:
eric@74 573 break;
eric@74 574 }
eric@74 575 }
eric@74 576 else
eric@74 577 switch (*bookmark_fmt)
eric@74 578 {
eric@74 579 case '%':
eric@74 580 meta = 1;
eric@74 581 break;
eric@74 582 default:
eric@74 583 *(name++) = *bookmark_fmt;
eric@74 584 }
eric@74 585 bookmark_fmt++;
eric@74 586 }
eric@116 587 *name = '\0';
eric@74 588 }
eric@74 589
eric@74 590
eric@74 591 void main_args (char *out_fn,
eric@74 592 int inf_count,
eric@74 593 char **in_fn,
eric@74 594 char *bookmark_fmt)
eric@49 595 {
eric@49 596 int i, ip;
eric@49 597 input_attributes_t input_attributes;
eric@49 598 pdf_file_attributes_t output_attributes;
eric@74 599 bookmark_t bookmark;
eric@74 600 char bookmark_name [MAX_BOOKMARK_NAME_LEN];
eric@74 601
eric@74 602 bookmark.next = NULL;
eric@74 603 bookmark.level = 1;
eric@74 604 bookmark.name = & bookmark_name [0];
eric@49 605
eric@49 606 memset (& input_attributes, 0, sizeof (input_attributes));
eric@49 607 memset (& output_attributes, 0, sizeof (output_attributes));
eric@49 608
eric@121 609 output_attributes.has_bookmarks = (bookmark_fmt != NULL);
eric@121 610
eric@49 611 if (! open_pdf_output_file (out_fn, & output_attributes))
eric@49 612 fatal (3, "error opening output file \"%s\"\n", out_fn);
eric@49 613 for (i = 0; i < inf_count; i++)
eric@49 614 {
eric@49 615 if (! open_tiff_input_file (in_fn [i]))
eric@49 616 fatal (3, "error opening input file \"%s\"\n", in_fn [i]);
eric@49 617 for (ip = 1;; ip++)
eric@49 618 {
eric@62 619 fprintf (stderr, "processing page %d of file \"%s\"\r", ip, in_fn [i]);
eric@74 620 if (bookmark_fmt)
eric@74 621 generate_bookmark_name (& bookmark_name [0],
eric@74 622 bookmark_fmt,
eric@74 623 in_fn [i],
eric@74 624 ip);
eric@74 625 if (! process_page (ip, input_attributes,
eric@131 626 bookmark_fmt ? & bookmark : NULL,
eric@131 627 NULL))
eric@49 628 fatal (3, "error processing page %d of input file \"%s\"\n", ip, in_fn [i]);
eric@49 629 if (last_tiff_page ())
eric@49 630 break;
eric@49 631 }
eric@49 632 if (verbose)
eric@49 633 fprintf (stderr, "processed %d pages of input file \"%s\"\n", ip, in_fn [i]);
eric@49 634 if (! close_tiff_input_file ())
eric@49 635 fatal (3, "error closing input file \"%s\"\n", in_fn [i]);
eric@49 636 }
eric@49 637 if (! close_pdf_output_files ())
eric@49 638 fatal (3, "error closing output file \"%s\"\n", out_fn);
eric@49 639 }
eric@49 640
eric@49 641
eric@49 642 void main_spec (char *spec_fn)
eric@49 643 {
eric@49 644 if (! parse_spec_file (spec_fn))
eric@49 645 fatal (2, "error parsing spec file\n");
eric@49 646 if (! process_specs ())
eric@49 647 fatal (3, "error processing spec file\n");
eric@49 648 }
eric@49 649
eric@49 650
eric@10 651 int main (int argc, char *argv[])
eric@10 652 {
eric@49 653 char *spec_fn = NULL;
eric@49 654 char *out_fn = NULL;
eric@62 655 char *bookmark_fmt = NULL;
eric@49 656 int inf_count = 0;
eric@49 657 char *in_fn [MAX_INPUT_FILES];
eric@49 658
eric@49 659 progname = argv [0];
eric@10 660
eric@62 661 pdf_init ();
eric@10 662
eric@49 663 while (--argc)
eric@10 664 {
eric@49 665 if (argv [1][0] == '-')
eric@49 666 {
eric@49 667 if (strcmp (argv [1], "-v") == 0)
eric@49 668 verbose++;
eric@49 669 else if (strcmp (argv [1], "-o") == 0)
eric@49 670 {
eric@49 671 if (argc)
eric@49 672 {
eric@49 673 argc--;
eric@49 674 argv++;
eric@49 675 out_fn = argv [1];
eric@49 676 }
eric@49 677 else
eric@49 678 fatal (1, "missing filename after \"-o\" option\n");
eric@49 679 }
eric@49 680 else if (strcmp (argv [1], "-s") == 0)
eric@49 681 {
eric@49 682 if (argc)
eric@49 683 {
eric@49 684 argc--;
eric@49 685 argv++;
eric@49 686 spec_fn = argv [1];
eric@49 687 }
eric@49 688 else
eric@49 689 fatal (1, "missing filename after \"-s\" option\n");
eric@49 690 }
eric@62 691 else if (strcmp (argv [1], "-b") == 0)
eric@62 692 {
eric@62 693 if (argc)
eric@62 694 {
eric@62 695 argc--;
eric@62 696 argv++;
eric@62 697 bookmark_fmt = argv [1];
eric@62 698 }
eric@62 699 else
eric@62 700 fatal (1, "missing format string after \"-b\" option\n");
eric@62 701 }
eric@49 702 else
eric@49 703 fatal (1, "unrecognized option \"%s\"\n", argv [1]);
eric@49 704 }
eric@49 705 else if (inf_count < MAX_INPUT_FILES)
eric@49 706 in_fn [inf_count++] = argv [1];
eric@49 707 else
eric@49 708 fatal (1, "exceeded maximum of %d input files\n", MAX_INPUT_FILES);
eric@49 709 argv++;
eric@10 710 }
eric@10 711
eric@49 712 if (! ((! out_fn) ^ (! spec_fn)))
eric@49 713 fatal (1, "either a spec file or an output file (but not both) must be specified\n");
eric@49 714
eric@49 715 if (out_fn && ! inf_count)
eric@49 716 fatal (1, "no input files specified\n");
eric@26 717
eric@49 718 if (spec_fn && inf_count)
eric@49 719 fatal (1, "if spec file is provided, input files can't be specified as arguments\n");
eric@49 720
eric@49 721 if (spec_fn)
eric@49 722 main_spec (spec_fn);
eric@49 723 else
eric@74 724 main_args (out_fn, inf_count, in_fn, bookmark_fmt);
eric@17 725
eric@10 726 close_tiff_input_file ();
eric@26 727 close_pdf_output_files ();
eric@49 728 exit (0);
eric@10 729 }