Mon, 14 Dec 2009 16:15:04 +0000
added support for TIFF Photometric Tag
1 /*
2 * tumble: build a PDF file from image files
3 *
4 * $Id: tumble_tiff.c,v 1.5 2003/03/20 07:22:23 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 /*
32 * On the x86, libtiff defaults to bit-endian bit order for no good reason.
33 * In theory, the '-L' (and maybe '-H') should give us little-endian bit
34 * order, but it doesn't seem to work. Thus we reverse the bits ourselves
35 * after we read in the file.
36 */
37 #define TIFF_REVERSE_BITS
39 /*
40 * If we're reading in a TIFF file that doesn't have a
41 * PhotometricInterpretation TIFF tag (TIFFTAG_PHOTOMETRIC), then this
42 * value will be assumed.
43 *
44 * This is the default value used by tumble-0.33 before the Photometric
45 * Tag read changes. ImageMagick often produces G4TIFF images which have
46 * black and white reversed, and the photometric tag set accordingly; in
47 * these cases, Tumble will create a PDF file with B+W swapped.
48 *
49 * Ideally this should be a command-line parameter.
50 */
51 #define TUMBLE_TIFF_PHOTOMETRIC_ASSUME 0
53 #include "semantics.h"
54 #include "tumble.h"
55 #include "bitblt.h"
56 #include "pdf.h"
57 #include "tumble_input.h"
60 TIFF *tiff_in;
63 #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
66 static bool match_tiff_suffix (char *suffix)
67 {
68 return ((strcasecmp (suffix, ".tif") == 0) ||
69 (strcasecmp (suffix, ".tiff") == 0));
70 }
73 static bool close_tiff_input_file (void)
74 {
75 TIFFClose (tiff_in);
76 return (1);
77 }
80 static bool open_tiff_input_file (FILE *f, char *name)
81 {
82 uint8_t buf [2];
83 size_t l;
85 l = fread (& buf [0], 1, sizeof (buf), f);
86 if (l != sizeof (buf))
87 return (0);
89 rewind (f);
91 if (! (((buf [0] == 0x49) && (buf [1] == 0x49)) ||
92 ((buf [0] == 0x4d) && (buf [1] == 0x4d))))
93 return (0);
95 tiff_in = TIFFFdOpen (fileno (f), name, "r");
96 if (! tiff_in)
97 {
98 fprintf (stderr, "can't open input file '%s'\n", name);
99 return (0);
100 }
101 return (1);
102 }
105 static bool last_tiff_input_page (void)
106 {
107 return (TIFFLastDirectory (tiff_in));
108 }
111 static bool get_tiff_image_info (int image,
112 input_attributes_t input_attributes,
113 image_info_t *image_info)
114 {
115 uint32_t image_height, image_width;
116 uint16_t samples_per_pixel;
117 uint16_t bits_per_sample;
118 uint16_t planar_config;
119 uint16_t photometric;
121 uint16_t resolution_unit;
122 float x_resolution, y_resolution;
124 double dest_x_resolution, dest_y_resolution;
126 #ifdef CHECK_DEPTH
127 uint32_t image_depth;
128 #endif
130 if (! TIFFSetDirectory (tiff_in, image - 1))
131 {
132 fprintf (stderr, "can't find page %d of input file\n", image);
133 return (0);
134 }
135 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGELENGTH, & image_height))
136 {
137 fprintf (stderr, "can't get image height\n");
138 return (0);
139 }
140 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEWIDTH, & image_width))
141 {
142 fprintf (stderr, "can't get image width\n");
143 return (0);
144 }
146 if (1 != TIFFGetField (tiff_in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
147 {
148 fprintf (stderr, "can't get samples per pixel\n");
149 return (0);
150 }
152 #ifdef CHECK_DEPTH
153 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEDEPTH, & image_depth))
154 {
155 fprintf (stderr, "can't get image depth\n");
156 return (0);
157 }
158 #endif
160 if (1 != TIFFGetField (tiff_in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
161 {
162 fprintf (stderr, "can't get bits per sample\n");
163 return (0);
164 }
166 if (1 != TIFFGetField (tiff_in, TIFFTAG_PHOTOMETRIC, & photometric))
167 {
168 fprintf(stderr, "warning: photometric tag not present, assuming %d\n", TUMBLE_TIFF_PHOTOMETRIC_ASSUME);
169 photometric = TUMBLE_TIFF_PHOTOMETRIC_ASSUME;
170 }
172 if ((photometric != 0) && (photometric != 1))
173 {
174 fprintf(stderr, "TIFF photometric tag not valid; got %u, must be 0 or 1\n", photometric);
175 return (0);
176 }
178 if (1 != TIFFGetField (tiff_in, TIFFTAG_PLANARCONFIG, & planar_config))
179 planar_config = 1;
181 if (1 != TIFFGetField (tiff_in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
182 resolution_unit = 2;
183 if (1 != TIFFGetField (tiff_in, TIFFTAG_XRESOLUTION, & x_resolution))
184 x_resolution = 300;
185 if (1 != TIFFGetField (tiff_in, TIFFTAG_YRESOLUTION, & y_resolution))
186 y_resolution = 300;
188 if (samples_per_pixel != 1)
189 {
190 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
191 return (0);
192 }
194 #ifdef CHECK_DEPTH
195 if (image_depth != 1)
196 {
197 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
198 return (0);
199 }
200 #endif
202 if (bits_per_sample != 1)
203 {
204 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
205 return (0);
206 }
208 if (planar_config != 1)
209 {
210 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
211 return (0);
212 }
214 if (input_attributes.has_resolution)
215 {
216 x_resolution = input_attributes.x_resolution;
217 y_resolution = input_attributes.y_resolution;
218 }
220 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
221 {
222 image_info->width_samples = image_height;
223 image_info->height_samples = image_width;
224 dest_x_resolution = y_resolution;
225 dest_y_resolution = x_resolution;
226 SWAP (double, image_info->width_points, image_info->height_points);
227 }
228 else
229 {
230 image_info->width_samples = image_width;
231 image_info->height_samples = image_height;
232 dest_x_resolution = x_resolution;
233 dest_y_resolution = y_resolution;
234 }
236 image_info->width_points = (image_info->width_samples / dest_x_resolution) * POINTS_PER_INCH;
237 image_info->height_points = (image_info->height_samples / dest_y_resolution) * POINTS_PER_INCH;
239 if ((image_info->height_points > PAGE_MAX_POINTS) ||
240 (image_info->width_points > PAGE_MAX_POINTS))
241 {
242 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
243 return (0);
244 }
246 image_info->tiff_photometric_tag = photometric;
248 return (1);
249 }
252 /* frees original! */
253 static Bitmap *resize_bitmap (Bitmap *src,
254 double x_resolution,
255 double y_resolution,
256 input_attributes_t input_attributes)
257 {
258 Rect src_rect;
259 Point dest_min;
260 Bitmap *dest;
262 int width_pixels = input_attributes.page_size.width * x_resolution;
263 int height_pixels = input_attributes.page_size.height * y_resolution;
265 src_rect.min.x = (rect_width (& src->rect) - width_pixels) / 2;
266 src_rect.min.y = (rect_height (& src->rect) - height_pixels) / 2;
267 src_rect.max.x = src_rect.min.x + width_pixels;
268 src_rect.max.y = src_rect.min.y + height_pixels;
270 dest_min.x = 0;
271 dest_min.y = 0;
273 dest = bitblt (src, & src_rect, NULL, & dest_min, TF_SRC, 0);
274 free_bitmap (src);
275 return (dest);
276 }
279 /* "in place" rotation */
280 static void rotate_bitmap (Bitmap *src,
281 input_attributes_t input_attributes)
282 {
283 switch (input_attributes.rotation)
284 {
285 case 0: break;
286 case 90: rot_90 (src); break;
287 case 180: rot_180 (src); break;
288 case 270: rot_270 (src); break;
289 default:
290 fprintf (stderr, "rotation must be 0, 90, 180, or 270\n");
291 }
292 }
295 static bool process_tiff_image (int image, /* range 1 .. n */
296 input_attributes_t input_attributes,
297 image_info_t *image_info,
298 pdf_page_handle page)
299 {
300 bool result = 0;
301 Rect rect;
302 Bitmap *bitmap = NULL;
304 int row;
306 rect.min.x = 0;
307 rect.min.y = 0;
309 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
310 {
311 rect.max.x = image_info->height_samples;
312 rect.max.y = image_info->width_samples;
313 }
314 else
315 {
316 rect.max.x = image_info->width_samples;
317 rect.max.y = image_info->height_samples;
318 }
320 bitmap = create_bitmap (& rect);
322 if (! bitmap)
323 {
324 fprintf (stderr, "can't allocate bitmap\n");
325 fprintf (stderr, "width %d height %d\n", image_info->width_samples, image_info->height_samples);
326 goto fail;
327 }
329 for (row = 0; row < rect.max.y; row++)
330 if (1 != TIFFReadScanline (tiff_in,
331 bitmap->bits + row * bitmap->row_words,
332 row,
333 0))
334 {
335 fprintf (stderr, "can't read TIFF scanline\n");
336 goto fail;
337 }
339 #ifdef TIFF_REVERSE_BITS
340 reverse_bits ((uint8_t *) bitmap->bits,
341 rect.max.y * bitmap->row_words * sizeof (word_t));
342 #endif /* TIFF_REVERSE_BITS */
344 #if 0
345 if (input_attributes.has_page_size)
346 bitmap = resize_bitmap (bitmap,
347 x_resolution,
348 y_resolution,
349 input_attributes);
350 #endif
352 rotate_bitmap (bitmap,
353 input_attributes);
355 #if 0
356 pdf_write_text (page);
357 #else
358 pdf_write_g4_fax_image (page,
359 0, 0, /* x, y */
360 image_info->width_points, image_info->height_points,
361 bitmap,
362 0, /* ImageMask */
363 0, 0, 0, /* r, g, b */
364 image_info->tiff_photometric_tag); /* 0=BlackIs1, 1=WhiteIs1 */
365 #endif
367 result = 1;
369 fail:
370 if (bitmap)
371 free_bitmap (bitmap);
372 return (result);
373 }
376 input_handler_t tiff_handler =
377 {
378 match_tiff_suffix,
379 open_tiff_input_file,
380 close_tiff_input_file,
381 last_tiff_input_page,
382 get_tiff_image_info,
383 process_tiff_image
384 };
387 void init_tiff_handler (void)
388 {
389 install_input_handler (& tiff_handler);
390 }