Thu, 20 Mar 2003 14:55:28 +0000
added match_suffix() to input handlers.
1 /*
2 * tumble: build a PDF file from image files
3 *
4 * $Id: tumble_tiff.c,v 1.4 2003/03/20 06:55:28 eric Exp $
5 * Copyright 2001, 2002, 2003 Eric Smith <eric@brouhaha.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 */
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <strings.h> /* strcasecmp() is a BSDism */
30 #include <tiffio.h>
31 #define TIFF_REVERSE_BITS
34 #include "semantics.h"
35 #include "tumble.h"
36 #include "bitblt.h"
37 #include "pdf.h"
38 #include "tumble_input.h"
41 TIFF *tiff_in;
44 #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
47 static bool match_tiff_suffix (char *suffix)
48 {
49 return ((strcasecmp (suffix, ".tif") == 0) ||
50 (strcasecmp (suffix, ".tiff") == 0));
51 }
54 static bool close_tiff_input_file (void)
55 {
56 TIFFClose (tiff_in);
57 return (1);
58 }
61 static bool open_tiff_input_file (FILE *f, char *name)
62 {
63 uint8_t buf [2];
64 size_t l;
66 l = fread (& buf [0], 1, sizeof (buf), f);
67 if (l != sizeof (buf))
68 return (0);
70 rewind (f);
72 if ((buf [0] != 0x49) || (buf [1] != 0x49))
73 return (0);
75 tiff_in = TIFFFdOpen (fileno (f), name, "r");
76 if (! tiff_in)
77 {
78 fprintf (stderr, "can't open input file '%s'\n", name);
79 return (0);
80 }
81 return (1);
82 }
85 static bool last_tiff_input_page (void)
86 {
87 return (TIFFLastDirectory (tiff_in));
88 }
91 static bool get_tiff_image_info (int image,
92 input_attributes_t input_attributes,
93 image_info_t *image_info)
94 {
95 uint32_t image_height, image_width;
96 uint16_t samples_per_pixel;
97 uint16_t bits_per_sample;
98 uint16_t planar_config;
100 uint16_t resolution_unit;
101 float x_resolution, y_resolution;
103 double dest_x_resolution, dest_y_resolution;
105 #ifdef CHECK_DEPTH
106 uint32_t image_depth;
107 #endif
109 if (! TIFFSetDirectory (tiff_in, image - 1))
110 {
111 fprintf (stderr, "can't find page %d of input file\n", image);
112 return (0);
113 }
114 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGELENGTH, & image_height))
115 {
116 fprintf (stderr, "can't get image height\n");
117 return (0);
118 }
119 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEWIDTH, & image_width))
120 {
121 fprintf (stderr, "can't get image width\n");
122 return (0);
123 }
125 if (1 != TIFFGetField (tiff_in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
126 {
127 fprintf (stderr, "can't get samples per pixel\n");
128 return (0);
129 }
131 #ifdef CHECK_DEPTH
132 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEDEPTH, & image_depth))
133 {
134 fprintf (stderr, "can't get image depth\n");
135 return (0);
136 }
137 #endif
139 if (1 != TIFFGetField (tiff_in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
140 {
141 fprintf (stderr, "can't get bits per sample\n");
142 return (0);
143 }
145 if (1 != TIFFGetField (tiff_in, TIFFTAG_PLANARCONFIG, & planar_config))
146 planar_config = 1;
148 if (1 != TIFFGetField (tiff_in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
149 resolution_unit = 2;
150 if (1 != TIFFGetField (tiff_in, TIFFTAG_XRESOLUTION, & x_resolution))
151 x_resolution = 300;
152 if (1 != TIFFGetField (tiff_in, TIFFTAG_YRESOLUTION, & y_resolution))
153 y_resolution = 300;
155 if (samples_per_pixel != 1)
156 {
157 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
158 return (0);
159 }
161 #ifdef CHECK_DEPTH
162 if (image_depth != 1)
163 {
164 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
165 return (0);
166 }
167 #endif
169 if (bits_per_sample != 1)
170 {
171 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
172 return (0);
173 }
175 if (planar_config != 1)
176 {
177 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
178 return (0);
179 }
181 if (input_attributes.has_resolution)
182 {
183 x_resolution = input_attributes.x_resolution;
184 y_resolution = input_attributes.y_resolution;
185 }
187 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
188 {
189 image_info->width_samples = image_height;
190 image_info->height_samples = image_width;
191 dest_x_resolution = y_resolution;
192 dest_y_resolution = x_resolution;
193 SWAP (double, image_info->width_points, image_info->height_points);
194 }
195 else
196 {
197 image_info->width_samples = image_width;
198 image_info->height_samples = image_height;
199 dest_x_resolution = x_resolution;
200 dest_y_resolution = y_resolution;
201 }
203 image_info->width_points = (image_info->width_samples / dest_x_resolution) * POINTS_PER_INCH;
204 image_info->height_points = (image_info->height_samples / dest_y_resolution) * POINTS_PER_INCH;
206 if ((image_info->height_points > PAGE_MAX_POINTS) ||
207 (image_info->width_points > PAGE_MAX_POINTS))
208 {
209 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
210 return (0);
211 }
213 return (1);
214 }
217 /* frees original! */
218 static Bitmap *resize_bitmap (Bitmap *src,
219 double x_resolution,
220 double y_resolution,
221 input_attributes_t input_attributes)
222 {
223 Rect src_rect;
224 Point dest_min;
225 Bitmap *dest;
227 int width_pixels = input_attributes.page_size.width * x_resolution;
228 int height_pixels = input_attributes.page_size.height * y_resolution;
230 src_rect.min.x = (rect_width (& src->rect) - width_pixels) / 2;
231 src_rect.min.y = (rect_height (& src->rect) - height_pixels) / 2;
232 src_rect.max.x = src_rect.min.x + width_pixels;
233 src_rect.max.y = src_rect.min.y + height_pixels;
235 dest_min.x = 0;
236 dest_min.y = 0;
238 dest = bitblt (src, & src_rect, NULL, & dest_min, TF_SRC, 0);
239 free_bitmap (src);
240 return (dest);
241 }
244 /* "in place" rotation */
245 static void rotate_bitmap (Bitmap *src,
246 input_attributes_t input_attributes)
247 {
248 switch (input_attributes.rotation)
249 {
250 case 0: break;
251 case 90: rot_90 (src); break;
252 case 180: rot_180 (src); break;
253 case 270: rot_270 (src); break;
254 default:
255 fprintf (stderr, "rotation must be 0, 90, 180, or 270\n");
256 }
257 }
260 static bool process_tiff_image (int image, /* range 1 .. n */
261 input_attributes_t input_attributes,
262 image_info_t *image_info,
263 pdf_page_handle page)
264 {
265 bool result = 0;
266 Rect rect;
267 Bitmap *bitmap = NULL;
269 int row;
271 rect.min.x = 0;
272 rect.min.y = 0;
274 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
275 {
276 rect.max.x = image_info->height_samples;
277 rect.max.y = image_info->width_samples;
278 }
279 else
280 {
281 rect.max.x = image_info->width_samples;
282 rect.max.y = image_info->height_samples;
283 }
285 bitmap = create_bitmap (& rect);
287 if (! bitmap)
288 {
289 fprintf (stderr, "can't allocate bitmap\n");
290 fprintf (stderr, "width %d height %d\n", image_info->width_samples, image_info->height_samples);
291 goto fail;
292 }
294 for (row = 0; row < rect.max.y; row++)
295 if (1 != TIFFReadScanline (tiff_in,
296 bitmap->bits + row * bitmap->row_words,
297 row,
298 0))
299 {
300 fprintf (stderr, "can't read TIFF scanline\n");
301 goto fail;
302 }
304 #ifdef TIFF_REVERSE_BITS
305 reverse_bits ((uint8_t *) bitmap->bits,
306 rect.max.y * bitmap->row_words * sizeof (word_t));
307 #endif /* TIFF_REVERSE_BITS */
309 #if 0
310 if (input_attributes.has_page_size)
311 bitmap = resize_bitmap (bitmap,
312 x_resolution,
313 y_resolution,
314 input_attributes);
315 #endif
317 rotate_bitmap (bitmap,
318 input_attributes);
320 #if 0
321 pdf_write_text (page);
322 #else
323 pdf_write_g4_fax_image (page,
324 0, 0, /* x, y */
325 image_info->width_points, image_info->height_points,
326 bitmap,
327 0, /* ImageMask */
328 0, 0, 0, /* r, g, b */
329 0); /* BlackIs1 */
330 #endif
332 result = 1;
334 fail:
335 if (bitmap)
336 free_bitmap (bitmap);
337 return (result);
338 }
341 input_handler_t tiff_handler =
342 {
343 match_tiff_suffix,
344 open_tiff_input_file,
345 close_tiff_input_file,
346 last_tiff_input_page,
347 get_tiff_image_info,
348 process_tiff_image
349 };
352 void init_tiff_handler (void)
353 {
354 install_input_handler (& tiff_handler);
355 }