1 /*
2  * tumble: build a PDF file from image files
3  *
4  * Semantic routines for spec file parser
5  * Copyright 2001, 2002, 2003, 2017 Eric Smith <spacewar@gmail.com>
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 version 2 as
9  * published by the Free Software Foundation.  Note that permission is
10  * not granted to redistribute this program under the terms of any
11  * other version of the General Public License.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
21  *
22  *  2009-03-13 [JDB] Add support for blank pages, overlay images, color
23  *                   mapping, color-key masking, and push/pop of input
24  *                   contexts.
25  */
26 
27 
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdio.h>
33 
34 #include "semantics.h"
35 
36 #ifdef CTL_LANG
37 #include "parser.tab.h"
38 #endif
39 
40 #include "tumble.h"
41 
42 
43 typedef struct
44 {
45   bool has_page_size;
46   page_size_t page_size;
47 
48   bool has_rotation;
49   int rotation;
50 
51   bool has_crop;
52   crop_t crop;
53 
54   bool has_transparency;
55   rgb_range_t transparency;
56 } input_modifiers_t;
57 
58 
59 typedef struct input_context_t
60 {
61   struct input_context_t *parent;
62   struct input_context_t *next;
63 
64   int image_count;  /* how many pages reference this context,
65 		      including those from subcontexts */
66 
67   char *input_file;
68   bool is_blank;
69 
70   input_modifiers_t modifiers [INPUT_MODIFIER_TYPE_COUNT];
71 } input_context_t;
72 
73 
74 typedef struct input_image_t
75 {
76   struct input_image_t *next;
77   input_context_t *input_context;
78   range_t range;
79 } input_image_t;
80 
81 
82 typedef struct output_context_t
83 {
84   struct output_context_t *parent;
85   struct output_context_t *next;
86 
87   int page_count;  /* how many pages reference this context,
88 		      including those from subcontexts */
89 
90   char *output_file;
91   pdf_file_attributes_t file_attributes;
92 
93   bookmark_t *first_bookmark;
94   bookmark_t *last_bookmark;
95 
96   bool has_page_label;
97   page_label_t page_label;
98 
99   bool has_colormap;
100   colormap_t colormap;
101 } output_context_t;
102 
103 
104 typedef struct output_page_t
105 {
106   struct output_page_t *next;
107   output_context_t *output_context;
108   range_t range;
109   bookmark_t *bookmark_list;
110   bool has_overlay;
111   overlay_t overlay;
112 } output_page_t;
113 
114 
115 #ifdef SEMANTIC_DEBUG
116 #define SDBG(x) printf x
117 #else
118 #define SDBG(x)
119 #endif
120 
121 
122 extern FILE *yyin;
123 int line;  /* line number in spec file */
124 
125 int bookmark_level;
126 
127 input_context_t *first_input_context;
128 input_context_t *last_input_context;
129 
130 input_modifier_type_t current_modifier_context = INPUT_MODIFIER_ALL;
131 
132 input_image_t *first_input_image;
133 input_image_t *last_input_image;
134 
135 output_context_t *first_output_context;
136 output_context_t *last_output_context;
137 
138 output_page_t *first_output_page;
139 output_page_t *last_output_page;
140 
141 
input_push_context(void)142 void input_push_context (void)
143 {
144   input_context_t *new_input_context;
145 
146   new_input_context = malloc (sizeof (input_context_t));
147   if (! new_input_context)
148     {
149       fprintf (stderr, "failed to malloc an input context\n");
150       return;
151     }
152 
153   if (last_input_context)
154     {
155       memcpy (new_input_context, last_input_context, sizeof (input_context_t));
156       new_input_context->image_count = 0;
157     }
158   else
159     {
160       memset (new_input_context, 0, sizeof (input_context_t));
161       first_input_context = new_input_context;
162     }
163 
164   new_input_context->parent = last_input_context;
165   last_input_context = new_input_context;
166 };
167 
input_pop_context(void)168 void input_pop_context (void)
169 {
170   if (! last_input_context)
171     {
172       fprintf (stderr, "failed to pop an input context\n");
173       return;
174     }
175 
176   last_input_context = last_input_context->parent;
177 };
178 
input_set_modifier_context(input_modifier_type_t type)179 void input_set_modifier_context (input_modifier_type_t type)
180 {
181   current_modifier_context = type;
182 #ifdef SEMANTIC_DEBUG
183   SDBG(("modifier type "));
184   switch (type)
185     {
186     case INPUT_MODIFIER_ALL: SDBG(("all")); break;
187     case INPUT_MODIFIER_ODD: SDBG(("odd")); break;
188     case INPUT_MODIFIER_EVEN: SDBG(("even")); break;
189     default: SDBG(("unknown %d", type));
190     }
191   SDBG(("\n"));
192 #endif /* SEMANTIC_DEBUG */
193 }
194 
input_clone(void)195 static void input_clone (void)
196 {
197   input_context_t *new_input_context;
198 
199   if (! last_input_context->image_count)
200     return;
201 
202   new_input_context = malloc (sizeof (input_context_t));
203   if (! new_input_context)
204     {
205       fprintf (stderr, "failed to malloc an input context\n");
206       return;
207     }
208 
209   memcpy (new_input_context, last_input_context, sizeof (input_context_t));
210   new_input_context->image_count = 0;
211   last_input_context->next = new_input_context;
212   last_input_context = new_input_context;
213 }
214 
input_set_file(char * name)215 void input_set_file (char *name)
216 {
217   input_clone ();
218   last_input_context->input_file = name;
219   last_input_context->is_blank = (name == NULL);
220 };
221 
input_set_rotation(int rotation)222 void input_set_rotation (int rotation)
223 {
224   last_input_context->modifiers [current_modifier_context].has_rotation = 1;
225   last_input_context->modifiers [current_modifier_context].rotation = rotation;
226   SDBG(("rotation %d\n", rotation));
227 }
228 
input_set_page_size(page_size_t size)229 void input_set_page_size (page_size_t size)
230 {
231   last_input_context->modifiers [current_modifier_context].has_page_size = 1;
232   last_input_context->modifiers [current_modifier_context].page_size = size;
233   SDBG(("page size %f, %f\n", size.width, size.height));
234 }
235 
input_set_transparency(rgb_range_t rgb_range)236 void input_set_transparency (rgb_range_t rgb_range)
237 {
238   last_input_context->modifiers [current_modifier_context].has_transparency = 1;
239   last_input_context->modifiers [current_modifier_context].transparency = rgb_range;
240 }
241 
increment_input_image_count(int count)242 static void increment_input_image_count (int count)
243 {
244   input_context_t *context;
245 
246   for (context = last_input_context; context; context = context->parent)
247     context->image_count += count;
248 }
249 
input_images(range_t range)250 void input_images (range_t range)
251 {
252   input_image_t *new_image;
253   int count = ((range.last - range.first) + 1);
254 
255 #ifdef SEMANTIC_DEBUG
256   if (range.first == range.last)
257     SDBG(("image %d\n", range.first));
258   else
259     SDBG(("images %d..%d\n", range.first, range.last));
260 #endif /* SEMANTIC_DEBUG */
261 
262   new_image = calloc (1, sizeof (input_image_t));
263   if (! new_image)
264     {
265       fprintf (stderr, "failed to malloc an input image struct\n");
266       return;
267     }
268   if (first_input_image)
269     {
270       last_input_image->next = new_image;
271       last_input_image = new_image;
272     }
273   else
274     {
275       first_input_image = last_input_image = new_image;
276     }
277   new_image->range = range;
278   new_image->input_context = last_input_context;
279   increment_input_image_count (count);
280 }
281 
282 
output_push_context(void)283 void output_push_context (void)
284 {
285   output_context_t *new_output_context;
286 
287   new_output_context = malloc (sizeof (output_context_t));
288   if (! new_output_context)
289     {
290       fprintf (stderr, "failed to malloc an output context\n");
291       return;
292     }
293 
294   if (last_output_context)
295     {
296       memcpy (new_output_context, last_output_context, sizeof (output_context_t));
297       new_output_context->page_count = 0;
298       new_output_context->first_bookmark = NULL;
299       new_output_context->last_bookmark = NULL;
300     }
301   else
302     {
303       memset (new_output_context, 0, sizeof (output_context_t));
304       first_output_context = new_output_context;
305     }
306 
307   new_output_context->parent = last_output_context;
308   last_output_context = new_output_context;
309 };
310 
output_pop_context(void)311 void output_pop_context (void)
312 {
313   if (! last_output_context)
314     {
315       fprintf (stderr, "failed to pop an output context\n");
316       return;
317     }
318 
319   last_output_context = last_output_context->parent;
320 };
321 
output_clone(void)322 static void output_clone (void)
323 {
324   output_context_t *new_output_context;
325 
326   if (! last_output_context->page_count)
327     return;
328 
329   new_output_context = malloc (sizeof (output_context_t));
330   if (! new_output_context)
331     {
332       fprintf (stderr, "failed to malloc an output context\n");
333       return;
334     }
335 
336   memcpy (new_output_context, last_output_context, sizeof (output_context_t));
337   new_output_context->page_count = 0;
338   last_output_context->next = new_output_context;
339 }
340 
output_set_file(char * name)341 void output_set_file (char *name)
342 {
343   output_clone ();
344   last_output_context->output_file = name;
345   last_output_context->file_attributes.author = NULL;
346   last_output_context->file_attributes.creator = NULL;
347   last_output_context->file_attributes.title = NULL;
348   last_output_context->file_attributes.subject = NULL;
349   last_output_context->file_attributes.keywords = NULL;
350 };
351 
output_set_author(char * author)352 void output_set_author (char *author)
353 {
354   last_output_context->file_attributes.author = author;
355 }
356 
output_set_creator(char * creator)357 void output_set_creator (char *creator)
358 {
359   last_output_context->file_attributes.creator = creator;
360 }
361 
output_set_title(char * title)362 void output_set_title (char *title)
363 {
364   last_output_context->file_attributes.title = title;
365 }
366 
output_set_subject(char * subject)367 void output_set_subject (char *subject)
368 {
369   last_output_context->file_attributes.subject = subject;
370 }
371 
output_set_keywords(char * keywords)372 void output_set_keywords (char *keywords)
373 {
374   last_output_context->file_attributes.keywords = keywords;
375 }
376 
output_set_bookmark(char * name)377 void output_set_bookmark (char *name)
378 {
379   bookmark_t *new_bookmark;
380 
381   /* As the language is defined (parser.y), a bookmark can only appear
382      at the beginning of a context! */
383   if (last_output_context->page_count)
384     {
385       fprintf (stderr, "internal error, bookmark not at beginning of context\n");
386       exit (2);
387     }
388 
389   new_bookmark = calloc (1, sizeof (bookmark_t));
390   if (! new_bookmark)
391     {
392       fprintf (stderr, "failed to calloc a bookmark\n");
393       return;
394     }
395 
396   new_bookmark->level = bookmark_level;
397   new_bookmark->name = name;
398   if (last_output_context->first_bookmark)
399     last_output_context->last_bookmark->next = new_bookmark;
400   else
401     last_output_context->first_bookmark = new_bookmark;
402   last_output_context->last_bookmark = new_bookmark;
403 }
404 
output_set_page_label(page_label_t label)405 void output_set_page_label (page_label_t label)
406 {
407   output_clone ();
408   last_output_context->has_page_label = 1;
409   last_output_context->page_label = label;
410 }
411 
increment_output_page_count(int count)412 static void increment_output_page_count (int count)
413 {
414   output_context_t *context;
415 
416   for (context = last_output_context; context; context = context->parent)
417     context->page_count += count;
418 }
419 
420 
output_pages(range_t range)421 void output_pages (range_t range)
422 {
423   output_page_t *new_page;
424   output_context_t *context;
425   int count = ((range.last - range.first) + 1);
426 
427 #ifdef SEMANTIC_DEBUG
428   if (range.first == range.last)
429     SDBG(("page %d\n", range.first));
430   else
431     SDBG(("pages %d..%d\n", range.first, range.last));
432 #endif /* SEMANTIC_DEBUG */
433 
434   new_page = calloc (1, sizeof (output_page_t));
435   if (! new_page)
436     {
437       fprintf (stderr, "failed to malloc an output page struct\n");
438       return;
439     }
440   if (first_output_page)
441     {
442       last_output_page->next = new_page;
443       last_output_page = new_page;
444     }
445   else
446     {
447       first_output_page = last_output_page = new_page;
448     }
449   new_page->range = range;
450   new_page->output_context = last_output_context;
451 
452   /* transfer bookmarks from context(s) to page */
453   for (context = last_output_context; context; context = context->parent)
454     if (context->first_bookmark)
455       {
456 	context->last_bookmark->next = new_page->bookmark_list;
457 	new_page->bookmark_list = context->first_bookmark;
458 	context->first_bookmark = NULL;
459 	context->last_bookmark = NULL;
460       }
461 
462   increment_output_page_count (count);
463 }
464 
465 
output_overlay(overlay_t overlay)466 void output_overlay (overlay_t overlay)
467 {
468   output_pages (last_output_page->range);
469   last_output_page->has_overlay = 1;
470   last_output_page->overlay.left = overlay.left;
471   last_output_page->overlay.top  = overlay.top;
472 }
473 
output_set_colormap(rgb_t black_color,rgb_t white_color)474 void output_set_colormap (rgb_t black_color, rgb_t white_color)
475 {
476   output_clone ();
477   last_output_context->has_colormap = 1;
478   last_output_context->colormap.black_map = black_color;
479   last_output_context->colormap.white_map = white_color;
480 }
481 
yyerror(const char * s)482 void yyerror (const char *s)
483 {
484   fprintf (stderr, "%d: %s\n", line, s);
485 }
486 
get_input_filename(input_context_t * context)487 static char *get_input_filename (input_context_t *context)
488 {
489   for (; context; context = context->parent)
490     if ((context->input_file) || (context->is_blank))
491       return (context->input_file);
492   fprintf (stderr, "no input file name found\n");
493   exit (2);
494 }
495 
get_input_rotation(input_context_t * context,input_modifier_type_t type,int * rotation)496 static bool get_input_rotation (input_context_t *context,
497 				input_modifier_type_t type,
498 				int *rotation)
499 {
500   for (; context; context = context->parent)
501     {
502       if (context->modifiers [type].has_rotation)
503 	{
504 	  * rotation = context->modifiers [type].rotation;
505 	  return (1);
506 	}
507       if (context->modifiers [INPUT_MODIFIER_ALL].has_rotation)
508 	{
509 	  * rotation = context->modifiers [INPUT_MODIFIER_ALL].rotation;
510 	  return (1);
511 	}
512     }
513   return (0);  /* default */
514 }
515 
get_input_transparency(input_context_t * context,input_modifier_type_t type)516 static rgb_range_t *get_input_transparency (input_context_t *context,
517 					    input_modifier_type_t type)
518 {
519   for (; context; context = context->parent)
520     {
521       if (context->modifiers [type].has_transparency)
522 	{
523 	  return & (context->modifiers [type].transparency);
524 	}
525       if (context->modifiers [INPUT_MODIFIER_ALL].has_transparency)
526 	{
527 	  return & (context->modifiers [INPUT_MODIFIER_ALL].transparency);
528 	}
529     }
530   return NULL;  /* default */
531 }
532 
get_input_page_size(input_context_t * context,input_modifier_type_t type,page_size_t * page_size)533 static bool get_input_page_size (input_context_t *context,
534 				 input_modifier_type_t type,
535 				 page_size_t *page_size)
536 {
537   for (; context; context = context->parent)
538     {
539       if (context->modifiers [type].has_page_size)
540 	{
541 	  * page_size = context->modifiers [type].page_size;
542 	  return (1);
543 	}
544       if (context->modifiers [INPUT_MODIFIER_ALL].has_page_size)
545 	{
546 	  * page_size = context->modifiers [INPUT_MODIFIER_ALL].page_size;
547 	  return (1);
548 	}
549     }
550   return (0);  /* default */
551 }
552 
get_output_filename(output_context_t * context)553 static char *get_output_filename (output_context_t *context)
554 {
555   for (; context; context = context->parent)
556     if (context->output_file)
557       return (context->output_file);
558   fprintf (stderr, "no output file found\n");
559   exit (2);
560 }
561 
get_output_file_attributes(output_context_t * context)562 static pdf_file_attributes_t *get_output_file_attributes (output_context_t *context)
563 {
564   for (; context; context = context->parent)
565     if (context->output_file)
566       return (& context->file_attributes);
567   fprintf (stderr, "no output file found\n");
568   exit (2);
569 }
570 
get_output_page_label(output_context_t * context)571 static page_label_t *get_output_page_label (output_context_t *context)
572 {
573   for (; context; context = context->parent)
574     if (context->has_page_label)
575       return (& context->page_label);
576   return (NULL);  /* default */
577 }
578 
get_output_colormap(output_context_t * context)579 static colormap_t *get_output_colormap (output_context_t *context)
580 {
581   for (; context; context = context->parent)
582     if (context->has_colormap)
583       return (& context->colormap);
584   return (NULL);  /* default */
585 }
586 
587 
588 #ifdef SEMANTIC_DEBUG
dump_input_tree(void)589 void dump_input_tree (void)
590 {
591   input_image_t *image;
592   int i;
593   char *fn;
594 
595   printf ("input images:\n");
596   for (image = first_input_image; image; image = image->next)
597     for (i = image->range.first; i <= image->range.last; i++)
598       {
599 	input_modifier_type_t parity = (i % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
600 	bool has_rotation, has_page_size;
601 	int rotation;
602 	page_size_t page_size;
603 	rgb_range_t *transparency;
604 
605 	has_rotation = get_input_rotation (image->input_context,
606 					   parity,
607 					   & rotation);
608 	has_page_size = get_input_page_size (image->input_context,
609 					     parity,
610 					     & page_size);
611 	transparency = get_input_transparency (image->input_context, parity);
612 	fn = get_input_filename (image->input_context);
613 	if (fn)
614 	  printf ("file '%s' image %d", fn, i);
615 	else
616 	  printf ("blank image %d", i);
617 	if (has_rotation)
618 	  printf (" rotation %d", rotation);
619 	if (transparency)
620 	  printf (" transparency %d..%d, %d..%d, %d..%d",
621 		  transparency->red.first,   transparency->red.last,
622 		  transparency->green.first, transparency->green.last,
623 		  transparency->blue.first,  transparency->blue.last);
624 	if (has_page_size)
625 	  printf (" size %f, %f", page_size.width, page_size.height);
626 	printf ("\n");
627 	printf ("context: %08x\n", image->input_context);
628       }
629 }
630 
dump_output_tree(void)631 void dump_output_tree (void)
632 {
633   int i;
634   output_page_t *page;
635   bookmark_t *bookmark;
636 
637   printf ("output pages:\n");
638   for (page = first_output_page; page; page = page->next)
639     {
640       if (page->bookmark_list)
641 	{
642 	  for (bookmark = page->bookmark_list; bookmark; bookmark = bookmark->next)
643 	    printf ("bookmark %d \"%s\"\n", bookmark->level, bookmark->name);
644 	}
645       for (i = page->range.first; i <= page->range.last; i++)
646 	{
647 	  page_label_t *label = get_output_page_label (page->output_context);
648 	  colormap_t *colormap = get_output_colormap (page->output_context);
649 	  printf ("file \"%s\" ", get_output_filename (page->output_context));
650 	  if (label)
651 	    {
652 	      printf ("label ");
653 	      if (label->prefix)
654 		printf ("\"%s\" ", label->prefix);
655 	      if (label->style)
656 		printf ("'%c' ", label->style);
657 	    }
658 	  if (colormap)
659 	    printf ("colormap (%d %d %d) (%d %d %d) ",
660 		    colormap->black_map.red, colormap->black_map.green, colormap->black_map.blue,
661 		    colormap->white_map.red, colormap->white_map.green, colormap->white_map.blue);
662 	  printf ("page %d\n", i);
663 	}
664     }
665 }
666 #endif /* SEMANTIC_DEBUG */
667 
668 
range_count(range_t range)669 static inline int range_count (range_t range)
670 {
671   return ((range.last - range.first) + 1);
672 }
673 
674 
675 #ifdef CTL_LANG
parse_control_file(char * fn)676 bool parse_control_file (char *fn)
677 {
678   bool result = 0;
679 
680   yyin = fopen (fn, "r");
681   if (! yyin)
682     {
683       fprintf (stderr, "can't open spec file '%s'\n", fn);
684       goto fail;
685     }
686 
687   line = 1;
688 
689   input_push_context ();  /* create root input context */
690   input_push_context ();  /* create inital input context */
691 
692   output_push_context ();  /* create root output context */
693   output_push_context ();  /* create initial output context */
694 
695   yyparse ();
696 
697   if (first_input_context->image_count != first_output_context->page_count)
698     {
699       fprintf (stderr, "input image count %d != output page count %d\n",
700 	       first_input_context->image_count,
701 	       first_output_context->page_count);
702       goto fail;
703     }
704 
705   fprintf (stderr, "%d images specified\n", first_input_context->image_count);
706 
707   result = 1;
708 
709 #ifdef SEMANTIC_DEBUG
710   dump_input_tree ();
711   dump_output_tree ();
712 #endif /* SEMANTIC_DEBUG */
713 
714  fail:
715   if (yyin)
716     fclose (yyin);
717 
718   return (result);
719 }
720 
omit_label(page_label_t * page_label)721 bool omit_label (page_label_t *page_label)
722 {
723   static page_label_t *last_page_label;
724   bool unneeded;
725 
726   unneeded = ( (last_page_label != NULL) &&
727 	       page_label->prefix &&
728 	       last_page_label->prefix &&
729 	       (strcmp (page_label->prefix, last_page_label->prefix) == 0) &&
730 	       (page_label->style == last_page_label->style) &&
731 	       (page_label->base == last_page_label->base + 1) );
732 
733   last_page_label = page_label;
734 
735   return unneeded;
736 }
737 
process_controls(void)738 bool process_controls (void)
739 {
740   input_image_t *image = NULL;
741   output_page_t *page = NULL;
742   int i = 0;
743   int p = 0;
744   int page_index = 0;
745   input_attributes_t input_attributes;
746   input_modifier_type_t parity;
747   page_label_t *page_label;
748 
749   for (;;)
750     {
751       if ((! image) || (i >= range_count (image->range)))
752 	{
753 	  char *input_fn;
754 	  if (image)
755 	    image = image->next;
756 	  else
757 	    image = first_input_image;
758 	  if (! image)
759 	    return (1);  /* done */
760 	  i = 0;
761 	  input_fn = get_input_filename (image->input_context);
762 	  if (verbose)
763 	    {
764 	      if (input_fn)
765 		fprintf (stderr, "opening input file '%s'\n", input_fn);
766 	      else
767 		fprintf (stderr, "generating blank image\n");
768 	    }
769 	  if (! open_input_file (input_fn))
770 	    {
771 	      fprintf (stderr, "error opening input file '%s'\n", input_fn);
772 	      return (0);
773 	    }
774 	}
775 
776       if ((! page) || (p >= range_count (page->range)))
777 	{
778 	  char *output_fn;
779 	  if (page)
780 	    page = page->next;
781 	  else
782 	    page = first_output_page;
783 	  p = 0;
784 	  output_fn = get_output_filename (page->output_context);
785 	  if (verbose)
786 	    fprintf (stderr, "opening PDF file '%s'\n", output_fn);
787 	  if (! open_pdf_output_file (output_fn,
788 				      get_output_file_attributes (page->output_context)))
789 	    {
790 	      fprintf (stderr, "error opening PDF file '%s'\n", output_fn);
791 	      return (0);
792 	    }
793 	}
794 
795       parity = ((image->range.first + i) % 2) ? INPUT_MODIFIER_ODD : INPUT_MODIFIER_EVEN;
796 
797       memset (& input_attributes, 0, sizeof (input_attributes));
798 
799       input_attributes.rotation = 0;
800       input_attributes.has_rotation = get_input_rotation (image->input_context,
801 							  parity,
802 							  & input_attributes.rotation);
803 
804       input_attributes.has_page_size = get_input_page_size (image->input_context,
805 							    parity,
806 							    & input_attributes.page_size);
807 
808       input_attributes.transparency = get_input_transparency (image->input_context, parity);
809 
810 
811       // really an output attribute, but we don't have such an thing
812       input_attributes.colormap = get_output_colormap (page->output_context);
813 
814       if (verbose)
815 	fprintf (stderr, "processing image %d\n", image->range.first + i);
816 
817       if (p)
818 	page_label = NULL;
819       else
820 	{
821 	  page_label = get_output_page_label (page->output_context);
822 	  if (page_label)
823 	    {
824 	      page_label->page_index = page_index;
825 	      page_label->base = page->range.first;
826 	      page_label->count = range_count (page->range);
827 
828 	      if (omit_label (page_label))
829 		page_label = NULL;
830 	    }
831 	}
832 
833       if (! process_page (image->range.first + i,
834 			  input_attributes,
835 			  p ? NULL : page->bookmark_list,
836 			  page_label,
837 			  page->has_overlay ? & page->overlay : NULL,
838 			  input_attributes.transparency))
839 	{
840 	  fprintf (stderr, "error processing image %d\n", image->range.first + i);
841 	  return (0);
842 	}
843       i++;
844       p++;
845 
846       if (! page->has_overlay)
847 	page_index++;
848     }
849 }
850 #endif /* CTL_LANG */
851