tumble_tiff.c

Tue, 25 Mar 2003 09:38:08 +0000

author
eric
date
Tue, 25 Mar 2003 09:38:08 +0000
changeset 156
745483d15215
parent 152
e69798068425
child 168
ad0b9a8990ac
permissions
-rw-r--r--

support both big- and little-endian TIFF files. don't crash in close_input_file() if current_input_handler is NULL.

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