Wed, 12 Mar 2003 06:02:46 +0000
removed get_row_run_lengths().
1 /*
2 * t2p: Create a PDF file from the contents of one or more TIFF
3 * bilevel image files. The images in the resulting PDF file
4 * will be compressed using ITU-T T.6 (G4) fax encoding.
5 *
6 * Semantic routines for spec file parser
7 * $Id: semantics.c,v 1.17 2003/02/19 02:20:05 eric Exp $
8 * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation. Note that permission is
13 * not granted to redistribute this program under the terms of any
14 * other version of the General Public License.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA */
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
32 #include "semantics.h"
33 #include "parser.tab.h"
34 #include "t2p.h"
37 typedef struct
38 {
39 bool has_page_size;
40 page_size_t page_size;
42 bool has_rotation;
43 int rotation;
45 bool has_crop;
46 crop_t crop;
47 } input_modifiers_t;
50 typedef struct input_context_t
51 {
52 struct input_context_t *parent;
53 struct input_context_t *next;
55 int image_count; /* how many pages reference this context,
56 including those from subcontexts */
58 char *input_file;
60 input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT];
61 } input_context_t;
64 typedef struct input_image_t
65 {
66 struct input_image_t *next;
67 input_context_t *input_context;
68 range_t range;
69 } input_image_t;
72 typedef struct output_context_t
73 {
74 struct output_context_t *parent;
75 struct output_context_t *next;
77 int page_count; /* how many pages reference this context,
78 including those from subcontexts */
80 char *output_file;
81 pdf_file_attributes_t file_attributes;
83 bookmark_t *first_bookmark;
84 bookmark_t *last_bookmark;
86 bool has_page_label;
87 page_label_t page_label;
88 } output_context_t;
91 typedef struct output_page_t
92 {
93 struct output_page_t *next;
94 output_context_t *output_context;
95 range_t range;
96 bookmark_t *bookmark_list;
97 } output_page_t;
100 #undef SEMANTIC_DEBUG
102 #ifdef SEMANTIC_DEBUG
103 #define SDBG(x) printf x
104 #else
105 #define SDBG(x)
106 #endif
109 FILE *yyin;
110 int line; /* line number in spec file */
112 int bookmark_level;
114 input_context_t *first_input_context;
115 input_context_t *last_input_context;
117 input_modifier_type_t current_modifier_context;
119 input_image_t *first_input_image;
120 input_image_t *last_input_image;
122 output_context_t *first_output_context;
123 output_context_t *last_output_context;
125 output_page_t *first_output_page;
126 output_page_t *last_output_page;
129 void input_push_context (void)
130 {
131 input_context_t *new_input_context;
133 new_input_context = malloc (sizeof (input_context_t));
134 if (! new_input_context)
135 {
136 fprintf (stderr, "failed to malloc an input context\n");
137 return;
138 }
140 if (last_input_context)
141 {
142 memcpy (new_input_context, last_input_context, sizeof (input_context_t));
143 new_input_context->image_count = 0;
144 }
145 else
146 {
147 memset (new_input_context, 0, sizeof (input_context_t));
148 first_input_context = new_input_context;
149 }
151 new_input_context->parent = last_input_context;
152 last_input_context = new_input_context;
153 };
155 void input_pop_context (void)
156 {
157 if (! last_input_context)
158 {
159 fprintf (stderr, "failed to pop an input context\n");
160 return;
161 }
163 last_input_context = last_input_context->parent;
164 };
166 void input_set_modifier_context (input_modifier_type_t type)
167 {
168 current_modifier_context = type;
169 #ifdef SEMANTIC_DEBUG
170 SDBG(("modifier type "));
171 switch (type)
172 {
173 case INPUT_MODIFIER_ALL: SDBG(("all")); break;
174 case INPUT_MODIFIER_ODD: SDBG(("odd")); break;
175 case INPUT_MODIFIER_EVEN: SDBG(("even")); break;
176 default: SDBG(("unknown %d", type));
177 }
178 SDBG(("\n"));
179 #endif /* SEMANTIC_DEBUG */
180 }
182 static void input_clone (void)
183 {
184 input_context_t *new_input_context;
186 if (! last_input_context->image_count)
187 return;
189 new_input_context = malloc (sizeof (input_context_t));
190 if (! new_input_context)
191 {
192 fprintf (stderr, "failed to malloc an input context\n");
193 return;
194 }
196 memcpy (new_input_context, last_input_context, sizeof (input_context_t));
197 new_input_context->image_count = 0;
198 last_input_context->next = new_input_context;
199 last_input_context = new_input_context;
200 }
202 void input_set_file (char *name)
203 {
204 input_clone ();
205 last_input_context->input_file = name;
206 };
208 void input_set_rotation (int rotation)
209 {
210 last_input_context->modifiers [current_modifier_context].has_rotation = 1;
211 last_input_context->modifiers [current_modifier_context].rotation = rotation;
212 SDBG(("rotation %d\n", rotation));
213 }
215 void input_set_page_size (page_size_t size)
216 {
217 last_input_context->modifiers [current_modifier_context].has_page_size = 1;
218 last_input_context->modifiers [current_modifier_context].page_size = size;
219 SDBG(("page size %f, %f\n", size.width, size.height));
220 }
222 static void increment_input_image_count (int count)
223 {
224 input_context_t *context;
226 for (context = last_input_context; context; context = context->parent)
227 context->image_count += count;
228 }
230 void input_images (range_t range)
231 {
232 input_image_t *new_image;
233 int count = ((range.last - range.first) + 1);
235 #ifdef SEMANTIC_DEBUG
236 if (range.first == range.last)
237 SDBG(("image %d\n", range.first));
238 else
239 SDBG(("images %d..%d\n", range.first, range.last));
240 #endif /* SEMANTIC_DEBUG */
242 new_image = calloc (1, sizeof (input_image_t));
243 if (! new_image)
244 {
245 fprintf (stderr, "failed to malloc an input image struct\n");
246 return;
247 }
248 if (first_input_image)
249 {
250 last_input_image->next = new_image;
251 last_input_image = new_image;
252 }
253 else
254 {
255 first_input_image = last_input_image = new_image;
256 }
257 new_image->range = range;
258 new_image->input_context = last_input_context;
259 increment_input_image_count (count);
260 }
263 void output_push_context (void)
264 {
265 output_context_t *new_output_context;
267 new_output_context = malloc (sizeof (output_context_t));
268 if (! new_output_context)
269 {
270 fprintf (stderr, "failed to malloc an output context\n");
271 return;
272 }
274 if (last_output_context)
275 {
276 memcpy (new_output_context, last_output_context, sizeof (output_context_t));
277 new_output_context->page_count = 0;
278 new_output_context->first_bookmark = NULL;
279 new_output_context->last_bookmark = NULL;
280 }
281 else
282 {
283 memset (new_output_context, 0, sizeof (output_context_t));
284 first_output_context = new_output_context;
285 }
287 new_output_context->parent = last_output_context;
288 last_output_context = new_output_context;
289 };
291 void output_pop_context (void)
292 {
293 if (! last_output_context)
294 {
295 fprintf (stderr, "failed to pop an output context\n");
296 return;
297 }
299 last_output_context = last_output_context->parent;
300 };
302 static void output_clone (void)
303 {
304 output_context_t *new_output_context;
306 if (! last_output_context->page_count)
307 return;
309 new_output_context = malloc (sizeof (output_context_t));
310 if (! new_output_context)
311 {
312 fprintf (stderr, "failed to malloc an output context\n");
313 return;
314 }
316 memcpy (new_output_context, last_output_context, sizeof (output_context_t));
317 new_output_context->page_count = 0;
318 last_output_context->next = new_output_context;
319 }
321 void output_set_file (char *name)
322 {
323 output_clone ();
324 last_output_context->output_file = name;
325 last_output_context->file_attributes.author = NULL;
326 last_output_context->file_attributes.creator = NULL;
327 last_output_context->file_attributes.title = NULL;
328 last_output_context->file_attributes.subject = NULL;
329 last_output_context->file_attributes.keywords = NULL;
330 };
332 void output_set_author (char *author)
333 {
334 last_output_context->file_attributes.author = author;
335 }
337 void output_set_creator (char *creator)
338 {
339 last_output_context->file_attributes.creator = creator;
340 }
342 void output_set_title (char *title)
343 {
344 last_output_context->file_attributes.title = title;
345 }
347 void output_set_subject (char *subject)
348 {
349 last_output_context->file_attributes.subject = subject;
350 }
352 void output_set_keywords (char *keywords)
353 {
354 last_output_context->file_attributes.keywords = keywords;
355 }
357 void output_set_bookmark (char *name)
358 {
359 bookmark_t *new_bookmark;
361 /* As the language is defined (parser.y), a bookmark can only appear
362 at the beginning of a context! */
363 if (last_output_context->page_count)
364 {
365 fprintf (stderr, "internal error, bookmark not at beginning of context\n");
366 exit (2);
367 }
369 new_bookmark = calloc (1, sizeof (bookmark_t));
370 if (! new_bookmark)
371 {
372 fprintf (stderr, "failed to calloc a bookmark\n");
373 return;
374 }
376 new_bookmark->level = bookmark_level;
377 new_bookmark->name = name;
378 if (last_output_context->first_bookmark)
379 last_output_context->last_bookmark->next = new_bookmark;
380 else
381 last_output_context->first_bookmark = new_bookmark;
382 last_output_context->last_bookmark = new_bookmark;
383 }
385 void output_set_page_label (page_label_t label)
386 {
387 output_clone ();
388 last_output_context->has_page_label = 1;
389 last_output_context->page_label = label;
390 }
392 static void increment_output_page_count (int count)
393 {
394 output_context_t *context;
396 for (context = last_output_context; context; context = context->parent)
397 context->page_count += count;
398 }
401 void output_pages (range_t range)
402 {
403 output_page_t *new_page;
404 output_context_t *context;
405 int count = ((range.last - range.first) + 1);
407 #ifdef SEMANTIC_DEBUG
408 if (range.first == range.last)
409 SDBG(("page %d\n", range.first));
410 else
411 SDBG(("pages %d..%d\n", range.first, range.last));
412 #endif /* SEMANTIC_DEBUG */
414 new_page = calloc (1, sizeof (output_page_t));
415 if (! new_page)
416 {
417 fprintf (stderr, "failed to malloc an output page struct\n");
418 return;
419 }
420 if (first_output_page)
421 {
422 last_output_page->next = new_page;
423 last_output_page = new_page;
424 }
425 else
426 {
427 first_output_page = last_output_page = new_page;
428 }
429 new_page->range = range;
430 new_page->output_context = last_output_context;
432 /* transfer bookmarks from context(s) to page */
433 for (context = last_output_context; context; context = context->parent)
434 if (context->first_bookmark)
435 {
436 context->last_bookmark->next = new_page->bookmark_list;
437 new_page->bookmark_list = context->first_bookmark;
438 context->first_bookmark = NULL;
439 context->last_bookmark = NULL;
440 }
442 increment_output_page_count (count);
443 }
446 void yyerror (char *s)
447 {
448 fprintf (stderr, "%d: %s\n", line, s);
449 }
452 static char *get_input_filename (input_context_t *context)
453 {
454 for (; context; context = context->parent)
455 if (context->input_file)
456 return (context->input_file);
457 fprintf (stderr, "no input file name found\n");
458 exit (2);
459 }
461 static bool get_input_rotation (input_context_t *context,
462 input_modifier_type_t type,
463 int *rotation)
464 {
465 for (; context; context = context->parent)
466 {
467 if (context->modifiers [type].has_rotation)
468 {
469 * rotation = context->modifiers [type].rotation;
470 return (1);
471 }
472 if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation)
473 {
474 * rotation = context->modifiers [INPUT_MODIFIER_ALL].rotation;
475 return (1);
476 }
477 }
478 return (0); /* default */
479 }
481 static bool get_input_page_size (input_context_t *context,
482 input_modifier_type_t type,
483 page_size_t *page_size)
484 {
485 for (; context; context = context->parent)
486 {
487 if (context->modifiers [type].has_page_size)
488 {
489 * page_size = context->modifiers [type].page_size;
490 return (1);
491 }
492 if (context->modifiers [INPUT_MODIFIER_ALL].has_page_size)
493 {
494 * page_size = context->modifiers [INPUT_MODIFIER_ALL].page_size;
495 return (1);
496 }
497 }
498 return (0); /* default */
499 }
501 static char *get_output_filename (output_context_t *context)
502 {
503 for (; context; context = context->parent)
504 if (context->output_file)
505 return (context->output_file);
506 fprintf (stderr, "no output file found\n");
507 exit (2);
508 }
510 static pdf_file_attributes_t *get_output_file_attributes (output_context_t *context)
511 {
512 for (; context; context = context->parent)
513 if (context->output_file)
514 return (& context->file_attributes);
515 fprintf (stderr, "no output file found\n");
516 exit (2);
517 }
519 static page_label_t *get_output_page_label (output_context_t *context)
520 {
521 for (; context; context = context->parent)
522 if (context->has_page_label)
523 return (& context->page_label);
524 return (NULL); /* default */
525 }
528 #ifdef SEMANTIC_DEBUG
529 void dump_input_tree (void)
530 {
531 input_image_t *image;
532 int i;
534 printf ("input images:\n");
535 for (image = first_input_image; image; image = image->next)
536 for (i = image->range.first; i <= image->range.last; i++)
537 {
538 input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
539 bool has_rotation, has_page_size;
540 int rotation;
541 page_size_t page_size;
543 has_rotation = get_input_rotation (image->input_context,
544 parity,
545 & rotation);
546 has_page_size = get_input_page_size (image->input_context,
547 parity,
548 & page_size);
549 printf ("file '%s' image %d",
550 get_input_filename (image->input_context),
551 i);
552 if (has_rotation)
553 printf (" rotation %d", rotation);
554 if (has_page_size)
555 printf (" size %f, %f", page_size.width, page_size.height);
556 printf ("\n");
557 printf ("context: %08x\n", image->input_context);
558 }
559 }
561 void dump_output_tree (void)
562 {
563 int i;
564 output_page_t *page;
565 bookmark_t *bookmark;
567 printf ("output pages:\n");
568 for (page = first_output_page; page; page = page->next)
569 {
570 if (page->bookmark_list)
571 {
572 for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next)
573 printf ("bookmark %d \"%s\"\n", bookmark->level, bookmark->name);
574 }
575 for (i = page->range.first; i <= page->range.last; i++)
576 {
577 page_label_t *label = get_output_page_label (page->output_context);
578 printf ("file \"%s\" ", get_output_filename (page->output_context));
579 if (label)
580 {
581 printf ("label ");
582 if (label->prefix)
583 printf ("\"%s\" ", label->prefix);
584 if (label->style)
585 printf ("'%c' ", label->style);
586 }
587 printf ("page %d\n", i);
588 }
589 }
590 }
591 #endif /* SEMANTIC_DEBUG */
594 static inline int range_count (range_t range)
595 {
596 return ((range.last - range.first) + 1);
597 }
600 bool parse_spec_file (char *fn)
601 {
602 bool result = 0;
604 yyin = fopen (fn, "r");
605 if (! yyin)
606 {
607 fprintf (stderr, "can't open spec file '%s'\n", fn);
608 goto fail;
609 }
611 line = 1;
613 input_push_context (); /* create root input context */
614 input_push_context (); /* create inital input context */
616 output_push_context (); /* create root output context */
617 output_push_context (); /* create initial output context */
619 yyparse ();
621 if (first_input_context->image_count != first_output_context->page_count)
622 {
623 fprintf (stderr, "input image count %d != output page count %d\n",
624 first_input_context->image_count,
625 first_output_context->page_count);
626 goto fail;
627 }
629 fprintf (stderr, "%d pages specified\n", first_input_context->image_count);
631 result = 1;
633 #ifdef SEMANTIC_DEBUG
634 dump_input_tree ();
635 dump_output_tree ();
636 #endif /* SEMANTIC_DEBUG */
638 fail:
639 if (yyin)
640 fclose (yyin);
642 return (result);
643 }
646 bool process_specs (void)
647 {
648 input_image_t *image = NULL;
649 output_page_t *page = NULL;
650 int i = 0;
651 int p = 0;
652 int page_index = 0;
653 input_attributes_t input_attributes;
654 input_modifier_type_t parity;
655 page_label_t *page_label;
657 for (;;)
658 {
659 if ((! image) || (i >= range_count (image->range)))
660 {
661 char *input_fn;
662 if (image)
663 image = image->next;
664 else
665 image = first_input_image;
666 if (! image)
667 return (1); /* done */
668 i = 0;
669 input_fn = get_input_filename (image->input_context);
670 if (verbose)
671 fprintf (stderr, "opening TIFF file '%s'\n", input_fn);
672 if (! open_tiff_input_file (input_fn))
673 {
674 fprintf (stderr, "error opening TIFF file '%s'\n", input_fn);
675 return (0);
676 }
677 }
679 if ((! page) || (p >= range_count (page->range)))
680 {
681 char *output_fn;
682 if (page)
683 page = page->next;
684 else
685 page = first_output_page;
686 p = 0;
687 output_fn = get_output_filename (page->output_context);
688 if (verbose)
689 fprintf (stderr, "opening PDF file '%s'\n", output_fn);
690 if (! open_pdf_output_file (output_fn,
691 get_output_file_attributes (page->output_context)))
692 {
693 fprintf (stderr, "error opening PDF file '%s'\n", output_fn);
694 return (0);
695 }
696 page_label = get_output_page_label (page->output_context);
697 process_page_numbers (page_index,
698 range_count (page->range),
699 page->range.first,
700 page_label);
701 }
703 parity = ((image->range.first + i) % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
705 memset (& input_attributes, 0, sizeof (input_attributes));
707 input_attributes.rotation = 0;
708 input_attributes.has_rotation = get_input_rotation (image->input_context,
709 parity,
710 & input_attributes.rotation);
712 input_attributes.has_page_size = get_input_page_size (image->input_context,
713 parity,
714 & input_attributes.page_size);
716 if (verbose)
717 fprintf (stderr, "processing image %d\n", image->range.first + i);
718 if (! process_page (image->range.first + i,
719 input_attributes,
720 page->bookmark_list))
721 {
722 fprintf (stderr, "error processing image %d\n", image->range.first + i);
723 return (0);
724 }
725 i++;
726 p++;
727 page_index++;
728 }
729 }