1 /*
2 * tumble: build a PDF file from image files
3 *
4 * Copyright 2001, 2002, 2003, 2017 Eric Smith <spacewar@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. Note that permission is
9 * not granted to redistribute this program under the terms of any
10 * other version of the General Public License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 *
21 * 2010-09-02 [JDB] Added support for min-is-black TIFF images.
22 */
23
24
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <strings.h> /* strcasecmp() is a BSDism */
30
31 #include <tiffio.h>
32 /*
33 * On the x86, libtiff defaults to bit-endian bit order for no good reason.
34 * In theory, the '-L' (and maybe '-H') should give us little-endian bit
35 * order, but it doesn't seem to work. Thus we reverse the bits ourselves
36 * after we read in the file.
37 */
38 #define TIFF_REVERSE_BITS
39
40
41 #include "semantics.h"
42 #include "tumble.h"
43 #include "bitblt.h"
44 #include "pdf.h"
45 #include "tumble_input.h"
46
47
48 TIFF *tiff_in;
49
50
51 #define SWAP(type,a,b) do { type temp; temp = a; a = b; b = temp; } while (0)
52
53
match_tiff_suffix(char * suffix)54 static bool match_tiff_suffix (char *suffix)
55 {
56 return ((strcasecmp (suffix, ".tif") == 0) ||
57 (strcasecmp (suffix, ".tiff") == 0));
58 }
59
60
close_tiff_input_file(void)61 static bool close_tiff_input_file (void)
62 {
63 TIFFClose (tiff_in);
64 return (1);
65 }
66
67
open_tiff_input_file(FILE * f,char * name)68 static bool open_tiff_input_file (FILE *f, char *name)
69 {
70 uint8_t buf [2];
71 size_t l;
72
73 l = fread (& buf [0], 1, sizeof (buf), f);
74 if (l != sizeof (buf))
75 return (0);
76
77 rewind (f);
78
79 if (! (((buf [0] == 0x49) && (buf [1] == 0x49)) ||
80 ((buf [0] == 0x4d) && (buf [1] == 0x4d))))
81 return (0);
82
83 tiff_in = TIFFFdOpen (fileno (f), name, "r");
84 if (! tiff_in)
85 {
86 fprintf (stderr, "can't open input file '%s'\n", name);
87 return (0);
88 }
89 return (1);
90 }
91
92
last_tiff_input_page(void)93 static bool last_tiff_input_page (void)
94 {
95 return (TIFFLastDirectory (tiff_in));
96 }
97
98
get_tiff_image_info(int image,input_attributes_t input_attributes,image_info_t * image_info)99 static bool get_tiff_image_info (int image,
100 input_attributes_t input_attributes,
101 image_info_t *image_info)
102 {
103 uint32_t image_height, image_width;
104 uint16_t samples_per_pixel;
105 uint16_t bits_per_sample;
106 uint16_t photometric_interpretation;
107 uint16_t planar_config;
108
109 uint16_t resolution_unit;
110 float x_resolution, y_resolution;
111
112 double dest_x_resolution, dest_y_resolution;
113
114 #ifdef CHECK_DEPTH
115 uint32_t image_depth;
116 #endif
117
118 if (! TIFFSetDirectory (tiff_in, image - 1))
119 {
120 fprintf (stderr, "can't find page %d of input file\n", image);
121 return (0);
122 }
123 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGELENGTH, & image_height))
124 {
125 fprintf (stderr, "can't get image height\n");
126 return (0);
127 }
128 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEWIDTH, & image_width))
129 {
130 fprintf (stderr, "can't get image width\n");
131 return (0);
132 }
133
134 if (1 != TIFFGetField (tiff_in, TIFFTAG_SAMPLESPERPIXEL, & samples_per_pixel))
135 {
136 fprintf (stderr, "can't get samples per pixel\n");
137 return (0);
138 }
139
140 #ifdef CHECK_DEPTH
141 if (1 != TIFFGetField (tiff_in, TIFFTAG_IMAGEDEPTH, & image_depth))
142 {
143 fprintf (stderr, "can't get image depth\n");
144 return (0);
145 }
146 #endif
147
148 if (1 != TIFFGetField (tiff_in, TIFFTAG_BITSPERSAMPLE, & bits_per_sample))
149 {
150 fprintf (stderr, "can't get bits per sample\n");
151 return (0);
152 }
153
154 if (1 != TIFFGetField (tiff_in, TIFFTAG_PHOTOMETRIC, & photometric_interpretation))
155 {
156 fprintf(stderr, "warning: photometric interpretation not specified, assuming min-is-white\n");
157 photometric_interpretation = PHOTOMETRIC_MINISWHITE;
158 }
159
160 else if ((photometric_interpretation != PHOTOMETRIC_MINISWHITE) &&
161 (photometric_interpretation != PHOTOMETRIC_MINISBLACK))
162 {
163 fprintf(stderr, "photometric interpretation value %u is invalid\n", photometric_interpretation);
164 return (0);
165 }
166
167 if (1 != TIFFGetField (tiff_in, TIFFTAG_PLANARCONFIG, & planar_config))
168 planar_config = 1;
169
170 if (1 != TIFFGetField (tiff_in, TIFFTAG_RESOLUTIONUNIT, & resolution_unit))
171 resolution_unit = 2;
172 if (1 != TIFFGetField (tiff_in, TIFFTAG_XRESOLUTION, & x_resolution))
173 x_resolution = 300;
174 if (1 != TIFFGetField (tiff_in, TIFFTAG_YRESOLUTION, & y_resolution))
175 y_resolution = 300;
176
177 if (samples_per_pixel != 1)
178 {
179 fprintf (stderr, "samples per pixel %u, must be 1\n", samples_per_pixel);
180 return (0);
181 }
182
183 #ifdef CHECK_DEPTH
184 if (image_depth != 1)
185 {
186 fprintf (stderr, "image depth %u, must be 1\n", image_depth);
187 return (0);
188 }
189 #endif
190
191 if (bits_per_sample != 1)
192 {
193 fprintf (stderr, "bits per sample %u, must be 1\n", bits_per_sample);
194 return (0);
195 }
196
197 if (planar_config != 1)
198 {
199 fprintf (stderr, "planar config %u, must be 1\n", planar_config);
200 return (0);
201 }
202
203 if (input_attributes.has_resolution)
204 {
205 x_resolution = input_attributes.x_resolution;
206 y_resolution = input_attributes.y_resolution;
207 }
208
209 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
210 {
211 image_info->width_samples = image_height;
212 image_info->height_samples = image_width;
213 dest_x_resolution = y_resolution;
214 dest_y_resolution = x_resolution;
215 SWAP (double, image_info->width_points, image_info->height_points);
216 }
217 else
218 {
219 image_info->width_samples = image_width;
220 image_info->height_samples = image_height;
221 dest_x_resolution = x_resolution;
222 dest_y_resolution = y_resolution;
223 }
224
225 image_info->width_points = (image_info->width_samples / dest_x_resolution) * POINTS_PER_INCH;
226 image_info->height_points = (image_info->height_samples / dest_y_resolution) * POINTS_PER_INCH;
227
228 if ((image_info->height_points > PAGE_MAX_POINTS) ||
229 (image_info->width_points > PAGE_MAX_POINTS))
230 {
231 fprintf (stdout, "image too large (max %d inches on a side\n", PAGE_MAX_INCHES);
232 return (0);
233 }
234
235 image_info->negative = (photometric_interpretation == PHOTOMETRIC_MINISBLACK);
236
237 return (1);
238 }
239
240
241
242
process_tiff_image(int image,input_attributes_t input_attributes,image_info_t * image_info,pdf_page_handle page,position_t position)243 static bool process_tiff_image (int image, /* range 1 .. n */
244 input_attributes_t input_attributes,
245 image_info_t *image_info,
246 pdf_page_handle page,
247 position_t position)
248 {
249 bool result = 0;
250 Rect rect;
251 Bitmap *bitmap = NULL;
252
253 int row;
254
255 rect.min.x = 0;
256 rect.min.y = 0;
257
258 if ((input_attributes.rotation == 90) || (input_attributes.rotation == 270))
259 {
260 rect.max.x = image_info->height_samples;
261 rect.max.y = image_info->width_samples;
262 }
263 else
264 {
265 rect.max.x = image_info->width_samples;
266 rect.max.y = image_info->height_samples;
267 }
268
269 bitmap = create_bitmap (& rect);
270
271 if (! bitmap)
272 {
273 fprintf (stderr, "can't allocate bitmap\n");
274 fprintf (stderr, "width %d height %d\n", image_info->width_samples, image_info->height_samples);
275 goto fail;
276 }
277
278 for (row = 0; row < rect.max.y; row++)
279 if (1 != TIFFReadScanline (tiff_in,
280 bitmap->bits + row * bitmap->row_words,
281 row,
282 0))
283 {
284 fprintf (stderr, "can't read TIFF scanline\n");
285 goto fail;
286 }
287
288 #ifdef TIFF_REVERSE_BITS
289 reverse_bits ((uint8_t *) bitmap->bits,
290 rect.max.y * bitmap->row_words * sizeof (word_t));
291 #endif /* TIFF_REVERSE_BITS */
292
293 #if 0
294 if (input_attributes.has_page_size)
295 bitmap = resize_bitmap (bitmap,
296 input_attributes.page_size.width * x_resolution,
297 input_attributes.page_size.height * y_resolution);
298 #endif
299
300 rotate_bitmap (bitmap, input_attributes.rotation);
301
302 #if 0
303 pdf_write_text (page);
304 #else
305 pdf_write_g4_fax_image (page,
306 position.x, position.y,
307 image_info->width_points, image_info->height_points,
308 image_info->negative,
309 bitmap,
310 input_attributes.colormap,
311 input_attributes.transparency);
312 #endif
313
314 result = 1;
315
316 fail:
317 if (bitmap)
318 free_bitmap (bitmap);
319 return (result);
320 }
321
322
323 input_handler_t tiff_handler =
324 {
325 match_tiff_suffix,
326 open_tiff_input_file,
327 close_tiff_input_file,
328 last_tiff_input_page,
329 get_tiff_image_info,
330 process_tiff_image
331 };
332
333
init_tiff_handler(void)334 void init_tiff_handler (void)
335 {
336 install_input_handler (& tiff_handler);
337 }
338