Mon, 26 Aug 2002 06:03:55 +0000
now use C99 stdint.h and stdbool.h
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 * Main program
7 * $Id: t2p.c,v 1.19 2002/08/25 22:02:31 eric Exp $
8 * Copyright 2001 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 <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
32 #include <tiffio.h>
33 #define TIFF_REVERSE_BITS
35 #include <panda/functions.h>
36 #include <panda/constants.h>
38 #include "bitblt.h"
39 #include "semantics.h"
40 #include "parser.tab.h"
41 #include "t2p.h"
44 #define POINTS_PER_INCH 72
46 /* page size limited by Acrobat Reader to 45 inches on a side */
47 #define PAGE_MAX_INCHES 45
48 #define PAGE_MAX_POINTS (PAGE_MAX_INCHES * POINTS_PER_INCH)
51 typedef struct output_file_t
52 {
53 struct output_file_t *next;
54 char *name;
55 panda_pdf *pdf;
56 } output_file_t;
59 char *in_filename;
60 TIFF *in;
61 output_file_t *output_files;
62 output_file_t *out;
63 /* panda_pdf *out; */
66 bool close_tiff_input_file (void)
67 {
68 if (in)
69 {
70 free (in_filename);
71 TIFFClose (in);
72 }
73 in = NULL;
74 in_filename = NULL;
75 return (1);
76 }
78 bool open_tiff_input_file (char *name)
79 {
80 if (in)
81 {
82 if (strcmp (name, in_filename) == 0)
83 return (1);
84 close_tiff_input_file ();
85 }
86 in_filename = strdup (name);
87 if (! in_filename)
88 {
89 fprintf (stderr, "can't strdup input filename '%s'\n", name);
90 return (0);
91 }
92 in = TIFFOpen (name, "r");
93 if (! in)
94 {
95 fprintf (stderr, "can't open input file '%s'\n", name);
96 free (in_filename);
97 return (0);
98 }
99 return (1);
100 }
103 bool close_pdf_output_files (void)
104 {
105 output_file_t *o, *n;
107 for (o = output_files; o; o = n)
108 {
109 n = o->next;
110 panda_close (o->pdf);
111 free (o->name);
112 free (o);
113 }
114 out = NULL;
115 output_files = NULL;
116 return (1);
117 }
119 bool open_pdf_output_file (char *name,
120 pdf_file_attributes_t *attributes)
121 {
122 output_file_t *o;
124 if (out && (strcmp (name, out->name) == 0))
125 return (1);
126 for (o = output_files; o; o = o->next)
127 if (strcmp (name, o->name) == 0)
128 {
129 out = o;
130 return (1);
131 }
132 o = calloc (1, sizeof (output_file_t));
133 if (! o)
134 {
135 fprintf (stderr, "can't calloc output file struct for '%s'\n", name);
136 return (0);
137 }
139 o->name = strdup (name);
140 if (! o->name)
141 {
142 fprintf (stderr, "can't strdup output filename '%s'\n", name);
143 free (o);
144 return (0);
145 }
147 o->pdf = panda_open (name, "w");
148 if (! o->pdf)
149 {
150 fprintf (stderr, "can't open output file '%s'\n", name);
151 free (o->name);
152 free (o);
153 return (0);
154 }
156 if (attributes->author)
157 panda_setauthor (o->pdf, attributes->author);
158 if (attributes->creator)
159 panda_setcreator (o->pdf, attributes->creator);
160 if (attributes->title)
161 panda_settitle (o->pdf, attributes->title);
162 if (attributes->subject)
163 panda_setsubject (o->pdf, attributes->subject);
164 if (attributes->keywords)
165 panda_setkeywords (o->pdf, attributes->keywords);
167 /* prepend new output file onto list */
168 o->next = output_files;
169 output_files = o;
171 out = o;
172 return (1);
173 }
176 void process_page_numbers (int page_index,
177 int count,
178 int base,
179 page_label_t *page_label)
180 {
181 }
184 /* frees original! */
185 static Bitmap *resize_bitmap (Bitmap *src,
186 float x_resolution,
187 float y_resolution,
188 input_attributes_t input_attributes)
189 {
190 Rect src_rect;
191 Point dest_min;
192 Bitmap *dest;
194 int width_pixels = input_attributes.page_size.width * x_resolution;
195 int height_pixels = input_attributes.page_size.height * y_resolution;
197 src_rect.min.x = (rect_width (& src->rect) - width_pixels) / 2;
198 src_rect.min.y = (rect_height (& src->rect) - height_pixels) / 2;
199 src_rect.max.x = src_rect.min.x + width_pixels;
200 src_rect.max.y = src_rect.min.y + height_pixels;
202 dest_min.x = 0;
203 dest_min.y = 0;
205 dest = bitblt (src, & src_rect, NULL, & dest_min, TF_SRC, 0);
206 free_bitmap (src);
207 return (dest);
208 }
211 /* "in place" rotation */
212 static void rotate_bitmap (Bitmap *src,
213 input_attributes_t input_attributes)
214 {
215 switch (input_attributes.rotation)
216 {
217 case 0: break;
218 case 90: rot_90 (src); break;
219 case 180: rot_180 (src); break;
220 case 270: rot_270 (src); break;
221 default:
222 fprintf (stderr, "rotation must be 0, 90, 180, or 270\n");
223 }
224 }
227 #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
229 bool process_page (int image, /* range 1 .. n */
230 input_attributes_t input_attributes,
231 bookmark_t *bookmarks)
232 {
233 int result = 0;
235 uint32_t image_length, image_width;
236 uint32_t dest_image_length, dest_image_width;
237 #ifdef CHECK_DEPTH
238 uint32_t image_depth;
239 #endif
241 uint16_t samples_per_pixel;
242 uint16_t bits_per_sample;
243 uint16_t planar_config;
245 uint16_t resolution_unit;
246 float x_resolution, y_resolution;
247 float dest_x_resolution, dest_y_resolution;
249 int width_points, height_points; /* really 1/72 inch units rather than
250 points */
252 Rect rect;
253 Bitmap *bitmap;
255 int row;
257 panda_page *page;
259 int tiff_temp_fd;
260 char tiff_temp_fn [] = "/var/tmp/t2p-XXXXXX\0";
261 TIFF *tiff_temp;
263 char pagesize [26]; /* Needs to hold two ints of four characters (0..3420),
264 two zeros, three spaces, two brackets, and a NULL.
265 Added an extra ten characters just in case. */
267 if (! TIFFSetDirectory (in, image - 1))
268 {
269 fprintf (stderr, "can't find page %d of input file\n", image);
270 goto fail;
271 }
272 if (1 != TIFFGetField (in, TIFFTAG_IMAGELENGTH, & image_length))
273 {
274 fprintf (stderr, "can't get image length\n");
275 goto fail;
276 }
277 if (1 != TIFFGetField (in, TIFFTAG_IMAGEWIDTH, & image_width))
278 {
279 fprintf (stderr, "can't get image width\n");
280 goto fail;
281 }
283 if (1 != TIFFGetField (in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
284 {
285 fprintf (stderr, "can't get samples per pixel\n");
286 goto fail;
287 }
289 #ifdef CHECK_DEPTH
290 if (1 != TIFFGetField (in, TIFFTAG_IMAGEDEPTH, & image_depth))
291 {
292 fprintf (stderr, "can't get image depth\n");
293 goto fail;
294 }
295 #endif
297 if (1 != TIFFGetField (in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
298 {
299 fprintf (stderr, "can't get bits per sample\n");
300 goto fail;
301 }
303 if (1 != TIFFGetField (in, TIFFTAG_PLANARCONFIG, & planar_config))
304 planar_config = 1;
306 if (1 != TIFFGetField (in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
307 resolution_unit = 2;
308 if (1 != TIFFGetField (in, TIFFTAG_XRESOLUTION, & x_resolution))
309 x_resolution = 300;
310 if (1 != TIFFGetField (in, TIFFTAG_YRESOLUTION, & y_resolution))
311 y_resolution = 300;
313 if (samples_per_pixel != 1)
314 {
315 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
316 goto fail;
317 }
319 #ifdef CHECK_DEPTH
320 if (image_depth != 1)
321 {
322 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
323 goto fail;
324 }
325 #endif
327 if (bits_per_sample != 1)
328 {
329 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
330 goto fail;
331 }
333 if (planar_config != 1)
334 {
335 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
336 goto fail;
337 }
339 if (input_attributes.has_resolution)
340 {
341 x_resolution = input_attributes.x_resolution;
342 y_resolution = input_attributes.y_resolution;
343 }
345 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
346 {
347 dest_image_width = image_length;
348 dest_image_length = image_width;
349 dest_x_resolution = y_resolution;
350 dest_y_resolution = x_resolution;
351 SWAP (int, width_points, height_points);
352 }
353 else
354 {
355 dest_image_width = image_width;
356 dest_image_length = image_length;
357 dest_x_resolution = x_resolution;
358 dest_y_resolution = y_resolution;
359 }
361 rect.min.x = 0;
362 rect.min.y = 0;
363 rect.max.x = image_width;
364 rect.max.y = image_length;
366 bitmap = create_bitmap (& rect);
368 if (! bitmap)
369 {
370 fprintf (stderr, "can't allocate bitmap\n");
371 goto fail;
372 }
374 for (row = 0; row < image_length; row++)
375 if (1 != TIFFReadScanline (in,
376 bitmap->bits + row * bitmap->row_words,
377 row,
378 0))
379 {
380 fprintf (stderr, "can't read TIFF scanline\n");
381 goto fail;
382 }
384 #ifdef TIFF_REVERSE_BITS
385 reverse_bits ((uint8_t *) bitmap->bits,
386 image_length * bitmap->row_words * sizeof (word_type));
387 #endif /* TIFF_REVERSE_BITS */
389 if (input_attributes.has_page_size)
390 bitmap = resize_bitmap (bitmap,
391 x_resolution,
392 y_resolution,
393 input_attributes);
395 rotate_bitmap (bitmap,
396 input_attributes);
398 tiff_temp_fd = mkstemp (tiff_temp_fn);
399 if (tiff_temp_fd < 0)
400 {
401 fprintf (stderr, "can't create temporary TIFF file\n");
402 goto fail;
403 }
405 tiff_temp = TIFFFdOpen (tiff_temp_fd, tiff_temp_fn, "w");
406 if (! out)
407 {
408 fprintf (stderr, "can't open temporary TIFF file '%s'\n", tiff_temp_fn);
409 goto fail;
410 }
412 TIFFSetField (tiff_temp, TIFFTAG_IMAGELENGTH, rect_height (& bitmap->rect));
413 TIFFSetField (tiff_temp, TIFFTAG_IMAGEWIDTH, rect_width (& bitmap->rect));
414 TIFFSetField (tiff_temp, TIFFTAG_PLANARCONFIG, planar_config);
416 TIFFSetField (tiff_temp, TIFFTAG_ROWSPERSTRIP, rect_height (& bitmap->rect));
418 TIFFSetField (tiff_temp, TIFFTAG_RESOLUTIONUNIT, resolution_unit);
419 TIFFSetField (tiff_temp, TIFFTAG_XRESOLUTION, dest_x_resolution);
420 TIFFSetField (tiff_temp, TIFFTAG_YRESOLUTION, dest_y_resolution);
422 TIFFSetField (tiff_temp, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
423 TIFFSetField (tiff_temp, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
424 TIFFSetField (tiff_temp, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
425 TIFFSetField (tiff_temp, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
427 #ifdef TIFF_REVERSE_BITS
428 reverse_bits ((uint8_t *) bitmap->bits,
429 image_length * bitmap->row_words * sizeof (word_type));
430 #endif /* TIFF_REVERSE_BITS */
432 for (row = 0; row < rect_height (& bitmap->rect); row++)
433 if (1 != TIFFWriteScanline (tiff_temp,
434 bitmap->bits + row * bitmap->row_words,
435 row,
436 0))
437 {
438 fprintf (stderr, "can't write TIFF scanline\n");
439 goto fail;
440 }
442 TIFFClose (tiff_temp);
444 width_points = (rect_width (& bitmap->rect) / dest_x_resolution) * POINTS_PER_INCH;
445 height_points = (rect_height (& bitmap->rect) / dest_y_resolution) * POINTS_PER_INCH;
447 free_bitmap (bitmap);
449 if ((height_points > PAGE_MAX_POINTS) || (width_points > PAGE_MAX_POINTS))
450 {
451 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
452 goto fail;
453 }
455 sprintf (pagesize, "[0 0 %d %d]", width_points, height_points);
457 page = panda_newpage (out->pdf, pagesize);
458 panda_imagebox (out->pdf,
459 page,
460 0, /* top */
461 0, /* left */
462 height_points, /* bottom */
463 width_points, /* right */
464 tiff_temp_fn,
465 panda_image_tiff);
467 result = 1;
469 fail:
470 if (tiff_temp_fd)
471 unlink (tiff_temp_fn);
472 return (result);
473 }
476 int main (int argc, char *argv[])
477 {
478 int result = 0;
480 panda_init ();
482 if (argc != 2)
483 {
484 fprintf (stderr, "usage: %s spec\n", argv [0]);
485 result = 1;
486 goto fail;
487 }
489 if (! parse_spec_file (argv [1]))
490 {
491 result = 2;
492 goto fail;
493 }
495 if (! process_specs ())
496 {
497 result = 3;
498 goto fail;
499 }
501 fail:
502 close_tiff_input_file ();
503 close_pdf_output_files ();
504 return (result);
505 }