Tue, 09 Dec 2003 18:05:44 +0000
fix sed regexp in bin-dist-rh for Red Hat 9 (no minor version).
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
40 #include "semantics.h"
41 #include "tumble.h"
42 #include "bitblt.h"
43 #include "pdf.h"
44 #include "tumble_input.h"
47 TIFF *tiff_in;
50 #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
53 static bool match_tiff_suffix (char *suffix)
54 {
55 return ((strcasecmp (suffix, ".tif") == 0) ||
56 (strcasecmp (suffix, ".tiff") == 0));
57 }
60 static bool close_tiff_input_file (void)
61 {
62 TIFFClose (tiff_in);
63 return (1);
64 }
67 static bool open_tiff_input_file (FILE *f, char *name)
68 {
69 uint8_t buf [2];
70 size_t l;
72 l = fread (& buf [0], 1, sizeof (buf), f);
73 if (l != sizeof (buf))
74 return (0);
76 rewind (f);
78 if (! (((buf [0] == 0x49) && (buf [1] == 0x49)) ||
79 ((buf [0] == 0x4d) && (buf [1] == 0x4d))))
80 return (0);
82 tiff_in = TIFFFdOpen (fileno (f), name, "r");
83 if (! tiff_in)
84 {
85 fprintf (stderr, "can't open input file '%s'\n", name);
86 return (0);
87 }
88 return (1);
89 }
92 static bool last_tiff_input_page (void)
93 {
94 return (TIFFLastDirectory (tiff_in));
95 }
98 static bool get_tiff_image_info (int image,
99 input_attributes_t input_attributes,
100 image_info_t *image_info)
101 {
102 uint32_t image_height, image_width;
103 uint16_t samples_per_pixel;
104 uint16_t bits_per_sample;
105 uint16_t planar_config;
107 uint16_t resolution_unit;
108 float x_resolution, y_resolution;
110 double dest_x_resolution, dest_y_resolution;
112 #ifdef CHECK_DEPTH
113 uint32_t image_depth;
114 #endif
116 if (! TIFFSetDirectory (tiff_in, image - 1))
117 {
118 fprintf (stderr, "can't find page %d of input file\n", image);
119 return (0);
120 }
121 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGELENGTH, & image_height))
122 {
123 fprintf (stderr, "can't get image height\n");
124 return (0);
125 }
126 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEWIDTH, & image_width))
127 {
128 fprintf (stderr, "can't get image width\n");
129 return (0);
130 }
132 if (1 != TIFFGetField (tiff_in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
133 {
134 fprintf (stderr, "can't get samples per pixel\n");
135 return (0);
136 }
138 #ifdef CHECK_DEPTH
139 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEDEPTH, & image_depth))
140 {
141 fprintf (stderr, "can't get image depth\n");
142 return (0);
143 }
144 #endif
146 if (1 != TIFFGetField (tiff_in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
147 {
148 fprintf (stderr, "can't get bits per sample\n");
149 return (0);
150 }
152 if (1 != TIFFGetField (tiff_in, TIFFTAG_PLANARCONFIG, & planar_config))
153 planar_config = 1;
155 if (1 != TIFFGetField (tiff_in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
156 resolution_unit = 2;
157 if (1 != TIFFGetField (tiff_in, TIFFTAG_XRESOLUTION, & x_resolution))
158 x_resolution = 300;
159 if (1 != TIFFGetField (tiff_in, TIFFTAG_YRESOLUTION, & y_resolution))
160 y_resolution = 300;
162 if (samples_per_pixel != 1)
163 {
164 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
165 return (0);
166 }
168 #ifdef CHECK_DEPTH
169 if (image_depth != 1)
170 {
171 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
172 return (0);
173 }
174 #endif
176 if (bits_per_sample != 1)
177 {
178 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
179 return (0);
180 }
182 if (planar_config != 1)
183 {
184 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
185 return (0);
186 }
188 if (input_attributes.has_resolution)
189 {
190 x_resolution = input_attributes.x_resolution;
191 y_resolution = input_attributes.y_resolution;
192 }
194 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
195 {
196 image_info->width_samples = image_height;
197 image_info->height_samples = image_width;
198 dest_x_resolution = y_resolution;
199 dest_y_resolution = x_resolution;
200 SWAP (double, image_info->width_points, image_info->height_points);
201 }
202 else
203 {
204 image_info->width_samples = image_width;
205 image_info->height_samples = image_height;
206 dest_x_resolution = x_resolution;
207 dest_y_resolution = y_resolution;
208 }
210 image_info->width_points = (image_info->width_samples / dest_x_resolution) * POINTS_PER_INCH;
211 image_info->height_points = (image_info->height_samples / dest_y_resolution) * POINTS_PER_INCH;
213 if ((image_info->height_points > PAGE_MAX_POINTS) ||
214 (image_info->width_points > PAGE_MAX_POINTS))
215 {
216 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
217 return (0);
218 }
220 return (1);
221 }
224 /* frees original! */
225 static Bitmap *resize_bitmap (Bitmap *src,
226 double x_resolution,
227 double y_resolution,
228 input_attributes_t input_attributes)
229 {
230 Rect src_rect;
231 Point dest_min;
232 Bitmap *dest;
234 int width_pixels = input_attributes.page_size.width * x_resolution;
235 int height_pixels = input_attributes.page_size.height * y_resolution;
237 src_rect.min.x = (rect_width (& src->rect) - width_pixels) / 2;
238 src_rect.min.y = (rect_height (& src->rect) - height_pixels) / 2;
239 src_rect.max.x = src_rect.min.x + width_pixels;
240 src_rect.max.y = src_rect.min.y + height_pixels;
242 dest_min.x = 0;
243 dest_min.y = 0;
245 dest = bitblt (src, & src_rect, NULL, & dest_min, TF_SRC, 0);
246 free_bitmap (src);
247 return (dest);
248 }
251 /* "in place" rotation */
252 static void rotate_bitmap (Bitmap *src,
253 input_attributes_t input_attributes)
254 {
255 switch (input_attributes.rotation)
256 {
257 case 0: break;
258 case 90: rot_90 (src); break;
259 case 180: rot_180 (src); break;
260 case 270: rot_270 (src); break;
261 default:
262 fprintf (stderr, "rotation must be 0, 90, 180, or 270\n");
263 }
264 }
267 static bool process_tiff_image (int image, /* range 1 .. n */
268 input_attributes_t input_attributes,
269 image_info_t *image_info,
270 pdf_page_handle page)
271 {
272 bool result = 0;
273 Rect rect;
274 Bitmap *bitmap = NULL;
276 int row;
278 rect.min.x = 0;
279 rect.min.y = 0;
281 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
282 {
283 rect.max.x = image_info->height_samples;
284 rect.max.y = image_info->width_samples;
285 }
286 else
287 {
288 rect.max.x = image_info->width_samples;
289 rect.max.y = image_info->height_samples;
290 }
292 bitmap = create_bitmap (& rect);
294 if (! bitmap)
295 {
296 fprintf (stderr, "can't allocate bitmap\n");
297 fprintf (stderr, "width %d height %d\n", image_info->width_samples, image_info->height_samples);
298 goto fail;
299 }
301 for (row = 0; row < rect.max.y; row++)
302 if (1 != TIFFReadScanline (tiff_in,
303 bitmap->bits + row * bitmap->row_words,
304 row,
305 0))
306 {
307 fprintf (stderr, "can't read TIFF scanline\n");
308 goto fail;
309 }
311 #ifdef TIFF_REVERSE_BITS
312 reverse_bits ((uint8_t *) bitmap->bits,
313 rect.max.y * bitmap->row_words * sizeof (word_t));
314 #endif /* TIFF_REVERSE_BITS */
316 #if 0
317 if (input_attributes.has_page_size)
318 bitmap = resize_bitmap (bitmap,
319 x_resolution,
320 y_resolution,
321 input_attributes);
322 #endif
324 rotate_bitmap (bitmap,
325 input_attributes);
327 #if 0
328 pdf_write_text (page);
329 #else
330 pdf_write_g4_fax_image (page,
331 0, 0, /* x, y */
332 image_info->width_points, image_info->height_points,
333 bitmap,
334 0, /* ImageMask */
335 0, 0, 0, /* r, g, b */
336 0); /* BlackIs1 */
337 #endif
339 result = 1;
341 fail:
342 if (bitmap)
343 free_bitmap (bitmap);
344 return (result);
345 }
348 input_handler_t tiff_handler =
349 {
350 match_tiff_suffix,
351 open_tiff_input_file,
352 close_tiff_input_file,
353 last_tiff_input_page,
354 get_tiff_image_info,
355 process_tiff_image
356 };
359 void init_tiff_handler (void)
360 {
361 install_input_handler (& tiff_handler);
362 }