Tue, 01 Jan 2002 10:18:33 +0000
change coordinates to signed.
1 /*
2 * tiff2pdf: Create a PDF file from the contents of one or more
3 * TIFF bilevel image files. The images in the resulting
4 * PDF file will be compressed using ITU-T T.6 (G4) fax
5 * encoding.
6 *
7 * Main program
8 * $Id: tumble.c,v 1.12 2002/01/01 02:16:50 eric Exp $
9 * Copyright 2001 Eric Smith <eric@brouhaha.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation. Note that permission is
14 * not granted to redistribute this program under the terms of any
15 * other version of the General Public License.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
25 */
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <tiffio.h>
32 #include <panda/functions.h>
33 #include <panda/constants.h>
35 #include "type.h"
36 #include "bitblt.h"
37 #include "semantics.h"
38 #include "parser.tab.h"
39 #include "tiff2pdf.h"
42 #define POINTS_PER_INCH 72
44 /* page size limited by Acrobat Reader to 45 inches on a side */
45 #define PAGE_MAX_INCHES 45
46 #define PAGE_MAX_POINTS (PAGE_MAX_INCHES * POINTS_PER_INCH)
49 typedef struct output_file_t
50 {
51 struct output_file_t *next;
52 char *name;
53 panda_pdf *pdf;
54 } output_file_t;
57 char *in_filename;
58 TIFF *in;
59 output_file_t *output_files;
60 output_file_t *out;
61 /* panda_pdf *out; */
64 boolean close_tiff_input_file (void)
65 {
66 if (in)
67 {
68 free (in_filename);
69 TIFFClose (in);
70 }
71 in = NULL;
72 in_filename = NULL;
73 return (1);
74 }
76 boolean open_tiff_input_file (char *name)
77 {
78 if (in)
79 {
80 if (strcmp (name, in_filename) == 0)
81 return (1);
82 close_tiff_input_file ();
83 }
84 in_filename = strdup (name);
85 if (! in_filename)
86 {
87 fprintf (stderr, "can't strdup input filename '%s'\n", name);
88 return (0);
89 }
90 in = TIFFOpen (name, "r");
91 if (! in)
92 {
93 fprintf (stderr, "can't open input file '%s'\n", name);
94 free (in_filename);
95 return (0);
96 }
97 return (1);
98 }
101 boolean close_pdf_output_files (void)
102 {
103 output_file_t *o, *n;
105 for (o = output_files; o; o = n)
106 {
107 n = o->next;
108 panda_close (o->pdf);
109 free (o->name);
110 free (o);
111 }
112 out = NULL;
113 output_files = NULL;
114 return (1);
115 }
117 boolean open_pdf_output_file (char *name,
118 pdf_file_attributes_t *attributes)
119 {
120 output_file_t *o;
122 if (out && (strcmp (name, out->name) == 0))
123 return (1);
124 for (o = output_files; o; o = o->next)
125 if (strcmp (name, o->name) == 0)
126 {
127 out = o;
128 return (1);
129 }
130 o = calloc (1, sizeof (output_file_t));
131 if (! o)
132 {
133 fprintf (stderr, "can't calloc output file struct for '%s'\n", name);
134 return (0);
135 }
137 o->name = strdup (name);
138 if (! o->name)
139 {
140 fprintf (stderr, "can't strdup output filename '%s'\n", name);
141 free (o);
142 return (0);
143 }
145 o->pdf = panda_open (name, "w");
146 if (! o->pdf)
147 {
148 fprintf (stderr, "can't open output file '%s'\n", name);
149 free (o->name);
150 free (o);
151 return (0);
152 }
154 if (attributes->author)
155 panda_setauthor (o->pdf, attributes->author);
156 if (attributes->creator)
157 panda_setcreator (o->pdf, attributes->creator);
158 if (attributes->title)
159 panda_settitle (o->pdf, attributes->title);
160 if (attributes->subject)
161 panda_setsubject (o->pdf, attributes->subject);
162 if (attributes->keywords)
163 panda_setkeywords (o->pdf, attributes->keywords);
165 /* prepend new output file onto list */
166 o->next = output_files;
167 output_files = o;
169 out = o;
170 return (1);
171 }
174 void process_page_numbers (int page_index,
175 int count,
176 int base,
177 page_label_t *page_label)
178 {
179 }
182 static Bitmap *rotate_bitmap (Bitmap *src, int rotation)
183 {
184 Rect src_rect;
185 Point dest_upper_left;
186 int scan;
188 src_rect.upper_left.x = 0;
189 src_rect.upper_left.y = 0;
190 src_rect.lower_right.x = src->width;
191 src_rect.lower_right.y = src->height;
193 dest_upper_left.x = 0;
194 dest_upper_left.y = 0;
196 switch (rotation)
197 {
198 case 0: scan = ROT_0; break;
199 case 90: scan = ROT_90; break;
200 case 180: scan = ROT_180; break;
201 case 270: scan = ROT_270; break;
202 default:
203 fprintf (stderr, "rotation must be 0, 90, 180, or 270\n");
204 return (NULL);
205 }
207 return (bitblt (src,
208 src_rect,
209 NULL, /* dest_bitmap */
210 dest_upper_left,
211 scan,
212 TF_SRC));
213 }
216 #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
218 boolean process_page (int image, /* range 1 .. n */
219 input_attributes_t input_attributes,
220 bookmark_t *bookmarks)
221 {
222 int result = 0;
224 u32 image_length, image_width;
225 u32 dest_image_length, dest_image_width;
226 #ifdef CHECK_DEPTH
227 u32 image_depth;
228 #endif
230 u16 samples_per_pixel;
231 u16 bits_per_sample;
232 u16 planar_config;
234 u16 resolution_unit;
235 float x_resolution, y_resolution;
236 float dest_x_resolution, dest_y_resolution;
238 int scanline_size;
240 int width_points, height_points; /* really 1/72 inch units rather than
241 points */
243 Bitmap *src_bitmap;
244 Bitmap *dest_bitmap;
245 int row;
247 panda_page *page;
249 int tiff_temp_fd;
250 char tiff_temp_fn [] = "/var/tmp/tiff2pdf-XXXXXX\0";
251 TIFF *tiff_temp;
253 char pagesize [26]; /* Needs to hold two ints of four characters (0..3420),
254 two zeros, three spaces, two brackets, and a NULL.
255 Added an extra ten characters just in case. */
257 if (! TIFFSetDirectory (in, image - 1))
258 {
259 fprintf (stderr, "can't find page %d of input file\n", image);
260 goto fail;
261 }
262 if (1 != TIFFGetField (in, TIFFTAG_IMAGELENGTH, & image_length))
263 {
264 fprintf (stderr, "can't get image length\n");
265 goto fail;
266 }
267 if (1 != TIFFGetField (in, TIFFTAG_IMAGEWIDTH, & image_width))
268 {
269 fprintf (stderr, "can't get image width\n");
270 goto fail;
271 }
273 if (1 != TIFFGetField (in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
274 {
275 fprintf (stderr, "can't get samples per pixel\n");
276 goto fail;
277 }
279 #ifdef CHECK_DEPTH
280 if (1 != TIFFGetField (in, TIFFTAG_IMAGEDEPTH, & image_depth))
281 {
282 fprintf (stderr, "can't get image depth\n");
283 goto fail;
284 }
285 #endif
287 if (1 != TIFFGetField (in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
288 {
289 fprintf (stderr, "can't get bits per sample\n");
290 goto fail;
291 }
293 if (1 != TIFFGetField (in, TIFFTAG_PLANARCONFIG, & planar_config))
294 planar_config = 1;
296 printf ("image length %u width %u, "
297 #ifdef CHECK_DEPTH
298 "depth %u, "
299 #endif
300 "planar config %u\n",
301 image_length, image_width,
302 #ifdef CHECK_DEPTH
303 image_depth,
304 #endif
305 planar_config);
307 if (1 != TIFFGetField (in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
308 resolution_unit = 2;
309 if (1 != TIFFGetField (in, TIFFTAG_XRESOLUTION, & x_resolution))
310 x_resolution = 300;
311 if (1 != TIFFGetField (in, TIFFTAG_YRESOLUTION, & y_resolution))
312 y_resolution = 300;
314 printf ("resolution unit %u, x resolution %f, y resolution %f\n",
315 resolution_unit, x_resolution, y_resolution);
317 if (samples_per_pixel != 1)
318 {
319 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
320 goto fail;
321 }
323 #ifdef CHECK_DEPTH
324 if (image_depth != 1)
325 {
326 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
327 goto fail;
328 }
329 #endif
331 if (bits_per_sample != 1)
332 {
333 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
334 goto fail;
335 }
337 if (planar_config != 1)
338 {
339 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
340 goto fail;
341 }
343 width_points = (image_width / x_resolution) * POINTS_PER_INCH;
344 height_points = (image_length / y_resolution) * POINTS_PER_INCH;
346 if ((height_points > PAGE_MAX_POINTS) || (width_points > PAGE_MAX_POINTS))
347 {
348 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
349 goto fail;
350 }
352 printf ("height_points %d, width_points %d\n", height_points, width_points);
354 tiff_temp_fd = mkstemp (tiff_temp_fn);
355 if (tiff_temp_fd < 0)
356 {
357 fprintf (stderr, "can't create temporary TIFF file\n");
358 goto fail;
359 }
361 tiff_temp = TIFFFdOpen (tiff_temp_fd, tiff_temp_fn, "w");
362 if (! out)
363 {
364 fprintf (stderr, "can't open temporary TIFF file '%s'\n", tiff_temp_fn);
365 goto fail;
366 }
368 printf ("rotation %d\n", input_attributes.rotation);
370 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
371 {
372 dest_image_width = image_length;
373 dest_image_length = image_width;
374 dest_x_resolution = y_resolution;
375 dest_y_resolution = x_resolution;
376 SWAP (int, width_points, height_points);
377 }
378 else
379 {
380 dest_image_width = image_width;
381 dest_image_length = image_length;
382 dest_x_resolution = x_resolution;
383 dest_y_resolution = y_resolution;
384 }
386 TIFFSetField (tiff_temp, TIFFTAG_IMAGELENGTH, dest_image_length);
387 TIFFSetField (tiff_temp, TIFFTAG_IMAGEWIDTH, dest_image_width);
388 TIFFSetField (tiff_temp, TIFFTAG_PLANARCONFIG, planar_config);
390 TIFFSetField (tiff_temp, TIFFTAG_ROWSPERSTRIP, dest_image_length);
392 TIFFSetField (tiff_temp, TIFFTAG_RESOLUTIONUNIT, resolution_unit);
393 TIFFSetField (tiff_temp, TIFFTAG_XRESOLUTION, dest_x_resolution);
394 TIFFSetField (tiff_temp, TIFFTAG_YRESOLUTION, dest_y_resolution);
396 TIFFSetField (tiff_temp, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
397 TIFFSetField (tiff_temp, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
398 TIFFSetField (tiff_temp, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
399 TIFFSetField (tiff_temp, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
401 scanline_size = TIFFScanlineSize (in);
403 src_bitmap = create_bitmap (image_width, image_length);
404 if (! src_bitmap)
405 {
406 fprintf (stderr, "can't allocate bitmap\n");
407 goto fail;
408 }
410 if (src_bitmap->rowbytes != scanline_size)
411 {
412 printf ("image_width %d\n", image_width);
413 printf ("rowbytes %d\n", src_bitmap->rowbytes);
414 printf ("TIFFScanlineSize %d\n", scanline_size);
415 }
417 for (row = 0; row < image_length; row++)
418 TIFFReadScanline (in,
419 src_bitmap->bits + row * src_bitmap->rowbytes,
420 row,
421 0);
423 for (row = 0; row < dest_image_length; row++)
424 if (1 != TIFFReadScanline (in,
425 src_bitmap->bits + row * src_bitmap->rowbytes,
426 row,
427 0))
428 {
429 fprintf (stderr, "can't read TIFF scanline\n");
430 goto fail;
431 }
433 dest_bitmap = rotate_bitmap (src_bitmap, input_attributes.rotation);
434 if (! dest_bitmap)
435 {
436 fprintf (stderr, "can't allocate bitmap\n");
437 goto fail;
438 }
440 for (row = 0; row < dest_bitmap->height; row++)
441 if (1 != TIFFWriteScanline (tiff_temp,
442 dest_bitmap->bits + row * dest_bitmap->rowbytes,
443 row,
444 0))
445 {
446 fprintf (stderr, "can't write TIFF scanline\n");
447 goto fail;
448 }
450 TIFFClose (tiff_temp);
452 free_bitmap (dest_bitmap);
453 free_bitmap (src_bitmap);
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 }