Tue, 01 Jan 2002 06:11:43 +0000
add support for PDF file attributes: author, creator, title, etc.
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: t2p.c,v 1.11 2001/12/31 22:11:43 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 boolean process_page (int image, /* range 1 .. n */
183 input_attributes_t input_attributes,
184 bookmark_t *bookmarks)
185 {
186 int result = 0;
188 u32 image_length, image_width;
189 #ifdef CHECK_DEPTH
190 u32 image_depth;
191 #endif
193 u16 samples_per_pixel;
194 u16 bits_per_sample;
195 u16 planar_config;
196 u16 resolution_unit;
197 float x_resolution, y_resolution;
198 int width_points, height_points; /* really 1/72 inch units rather than
199 points */
202 char *buffer;
203 u32 row;
205 panda_page *page;
207 int tiff_temp_fd;
208 char tiff_temp_fn [] = "/var/tmp/tiff2pdf-XXXXXX\0";
209 TIFF *tiff_temp;
211 char pagesize [26]; /* Needs to hold two ints of four characters (0..3420),
212 two zeros, three spaces, two brackets, and a NULL.
213 Added an extra ten characters just in case. */
215 if (! TIFFSetDirectory (in, image - 1))
216 {
217 fprintf (stderr, "can't find page %d of input file\n", image);
218 goto fail;
219 }
220 if (1 != TIFFGetField (in, TIFFTAG_IMAGELENGTH, & image_length))
221 {
222 fprintf (stderr, "can't get image length\n");
223 goto fail;
224 }
225 if (1 != TIFFGetField (in, TIFFTAG_IMAGEWIDTH, & image_width))
226 {
227 fprintf (stderr, "can't get image width\n");
228 goto fail;
229 }
231 if (1 != TIFFGetField (in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
232 {
233 fprintf (stderr, "can't get samples per pixel\n");
234 goto fail;
235 }
237 #ifdef CHECK_DEPTH
238 if (1 != TIFFGetField (in, TIFFTAG_IMAGEDEPTH, & image_depth))
239 {
240 fprintf (stderr, "can't get image depth\n");
241 goto fail;
242 }
243 #endif
245 if (1 != TIFFGetField (in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
246 {
247 fprintf (stderr, "can't get bits per sample\n");
248 goto fail;
249 }
251 if (1 != TIFFGetField (in, TIFFTAG_PLANARCONFIG, & planar_config))
252 planar_config = 1;
254 printf ("image length %u width %u, "
255 #ifdef CHECK_DEPTH
256 "depth %u, "
257 #endif
258 "planar config %u\n",
259 image_length, image_width,
260 #ifdef CHECK_DEPTH
261 image_depth,
262 #endif
263 planar_config);
265 if (1 != TIFFGetField (in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
266 resolution_unit = 2;
267 if (1 != TIFFGetField (in, TIFFTAG_XRESOLUTION, & x_resolution))
268 x_resolution = 300;
269 if (1 != TIFFGetField (in, TIFFTAG_YRESOLUTION, & y_resolution))
270 y_resolution = 300;
272 printf ("resolution unit %u, x resolution %f, y resolution %f\n",
273 resolution_unit, x_resolution, y_resolution);
275 if (samples_per_pixel != 1)
276 {
277 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
278 goto fail;
279 }
281 #ifdef CHECK_DEPTH
282 if (image_depth != 1)
283 {
284 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
285 goto fail;
286 }
287 #endif
289 if (bits_per_sample != 1)
290 {
291 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
292 goto fail;
293 }
295 if (planar_config != 1)
296 {
297 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
298 goto fail;
299 }
301 tiff_temp_fd = mkstemp (tiff_temp_fn);
302 if (tiff_temp_fd < 0)
303 {
304 fprintf (stderr, "can't create temporary TIFF file\n");
305 goto fail;
306 }
308 tiff_temp = TIFFFdOpen (tiff_temp_fd, tiff_temp_fn, "w");
309 if (! out)
310 {
311 fprintf (stderr, "can't open temporary TIFF file '%s'\n", tiff_temp_fn);
312 goto fail;
313 }
315 TIFFSetField (tiff_temp, TIFFTAG_IMAGELENGTH, image_length);
316 TIFFSetField (tiff_temp, TIFFTAG_IMAGEWIDTH, image_width);
317 TIFFSetField (tiff_temp, TIFFTAG_PLANARCONFIG, planar_config);
319 TIFFSetField (tiff_temp, TIFFTAG_ROWSPERSTRIP, image_length);
321 TIFFSetField (tiff_temp, TIFFTAG_RESOLUTIONUNIT, resolution_unit);
322 TIFFSetField (tiff_temp, TIFFTAG_XRESOLUTION, x_resolution);
323 TIFFSetField (tiff_temp, TIFFTAG_YRESOLUTION, y_resolution);
325 TIFFSetField (tiff_temp, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
326 TIFFSetField (tiff_temp, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
327 TIFFSetField (tiff_temp, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4);
328 TIFFSetField (tiff_temp, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
330 buffer = _TIFFmalloc (TIFFScanlineSize (in));
331 if (! buffer)
332 {
333 fprintf (stderr, "failed to allocate buffer\n");
334 goto fail;
335 }
337 for (row = 0; row < image_length; row++)
338 {
339 TIFFReadScanline (in, buffer, row, 0);
340 TIFFWriteScanline (tiff_temp, buffer, row, 0);
341 }
343 _TIFFfree (buffer);
344 TIFFClose (tiff_temp);
346 width_points = (image_width / x_resolution) * POINTS_PER_INCH;
347 height_points = (image_length / y_resolution) * POINTS_PER_INCH;
349 if ((height_points > PAGE_MAX_POINTS) || (width_points > PAGE_MAX_POINTS))
350 {
351 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
352 goto fail;
353 }
355 printf ("height_points %d, width_points %d\n", height_points, width_points);
357 sprintf (pagesize, "[0 0 %d %d]", width_points, height_points);
359 page = panda_newpage (out->pdf, pagesize);
360 panda_imagebox (out->pdf,
361 page,
362 0, /* top */
363 0, /* left */
364 height_points, /* bottom */
365 width_points, /* right */
366 tiff_temp_fn,
367 panda_image_tiff);
369 result = 1;
371 fail:
372 if (tiff_temp_fd)
373 unlink (tiff_temp_fn);
374 return (result);
375 }
378 int main (int argc, char *argv[])
379 {
380 int result = 0;
382 panda_init ();
384 if (argc != 2)
385 {
386 fprintf (stderr, "usage: %s spec\n", argv [0]);
387 result = 1;
388 goto fail;
389 }
391 if (! parse_spec_file (argv [1]))
392 {
393 result = 2;
394 goto fail;
395 }
397 if (! process_specs ())
398 {
399 result = 3;
400 goto fail;
401 }
403 fail:
404 close_tiff_input_file ();
405 close_pdf_output_files ();
406 return (result);
407 }