1 /* $Id: tiff2rgba.c,v 1.22 2016-08-15 20:06:41 erouault Exp $ */
2
3 /*
4 * Copyright (c) 1991-1997 Sam Leffler
5 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6 *
7 * Permission to use, copy, modify, distribute, and sell this software and
8 * its documentation for any purpose is hereby granted without fee, provided
9 * that (i) the above copyright notices and this permission notice appear in
10 * all copies of the software and related documentation, and (ii) the names of
11 * Sam Leffler and Silicon Graphics may not be used in any advertising or
12 * publicity relating to the software without the specific, prior written
13 * permission of Sam Leffler and Silicon Graphics.
14 *
15 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 * OF THIS SOFTWARE.
25 */
26
27 #include "tif_config.h"
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #ifdef NEED_LIBPORT
38 # include "libport.h"
39 #endif
40
41 #include "tiffiop.h"
42 #include "tiffio.h"
43
44 #define streq(a,b) (strcmp(a,b) == 0)
45 #define CopyField(tag, v) \
46 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
47
48 #ifndef howmany
49 #define howmany(x, y) (((x)+((y)-1))/(y))
50 #endif
51 #define roundup(x, y) (howmany(x,y)*((uint32)(y)))
52
53 uint16 compression = COMPRESSION_PACKBITS;
54 uint32 rowsperstrip = (uint32) -1;
55 int process_by_block = 0; /* default is whole image at once */
56 int no_alpha = 0;
57 int bigtiff_output = 0;
58
59
60 static int tiffcvt(TIFF* in, TIFF* out);
61 static void usage(int code);
62
63 int
main(int argc,char * argv[])64 main(int argc, char* argv[])
65 {
66 TIFF *in, *out;
67 int c;
68 #if !HAVE_DECL_OPTARG
69 extern int optind;
70 extern char *optarg;
71 #endif
72
73 while ((c = getopt(argc, argv, "c:r:t:bn8")) != -1)
74 switch (c) {
75 case 'b':
76 process_by_block = 1;
77 break;
78
79 case 'c':
80 if (streq(optarg, "none"))
81 compression = COMPRESSION_NONE;
82 else if (streq(optarg, "packbits"))
83 compression = COMPRESSION_PACKBITS;
84 else if (streq(optarg, "lzw"))
85 compression = COMPRESSION_LZW;
86 else if (streq(optarg, "jpeg"))
87 compression = COMPRESSION_JPEG;
88 else if (streq(optarg, "zip"))
89 compression = COMPRESSION_DEFLATE;
90 else
91 usage(-1);
92 break;
93
94 case 'r':
95 rowsperstrip = atoi(optarg);
96 break;
97
98 case 't':
99 rowsperstrip = atoi(optarg);
100 break;
101
102 case 'n':
103 no_alpha = 1;
104 break;
105
106 case '8':
107 bigtiff_output = 1;
108 break;
109
110 case '?':
111 usage(0);
112 /*NOTREACHED*/
113 }
114
115 if (argc - optind < 2)
116 usage(-1);
117
118 out = TIFFOpen(argv[argc-1], bigtiff_output?"w8":"w");
119 if (out == NULL)
120 return (-2);
121
122 for (; optind < argc-1; optind++) {
123 in = TIFFOpen(argv[optind], "r");
124 if (in != NULL) {
125 do {
126 if (!tiffcvt(in, out) ||
127 !TIFFWriteDirectory(out)) {
128 (void) TIFFClose(out);
129 (void) TIFFClose(in);
130 return (1);
131 }
132 } while (TIFFReadDirectory(in));
133 (void) TIFFClose(in);
134 }
135 }
136 (void) TIFFClose(out);
137 return (0);
138 }
139
140 static int
cvt_by_tile(TIFF * in,TIFF * out)141 cvt_by_tile( TIFF *in, TIFF *out )
142
143 {
144 uint32* raster; /* retrieve RGBA image */
145 uint32 width, height; /* image width & height */
146 uint32 tile_width, tile_height;
147 uint32 row, col;
148 uint32 *wrk_line;
149 int ok = 1;
150 uint32 rastersize, wrk_linesize;
151
152 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
153 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
154
155 if( !TIFFGetField(in, TIFFTAG_TILEWIDTH, &tile_width)
156 || !TIFFGetField(in, TIFFTAG_TILELENGTH, &tile_height) ) {
157 TIFFError(TIFFFileName(in), "Source image not tiled");
158 return (0);
159 }
160
161 TIFFSetField(out, TIFFTAG_TILEWIDTH, tile_width );
162 TIFFSetField(out, TIFFTAG_TILELENGTH, tile_height );
163
164 /*
165 * Allocate tile buffer
166 */
167 rastersize = tile_width * tile_height * sizeof (uint32);
168 if (tile_width != (rastersize / tile_height) / sizeof( uint32))
169 {
170 TIFFError(TIFFFileName(in), "Integer overflow when calculating raster buffer");
171 exit(-1);
172 }
173 raster = (uint32*)_TIFFmalloc(rastersize);
174 if (raster == 0) {
175 TIFFError(TIFFFileName(in), "No space for raster buffer");
176 return (0);
177 }
178
179 /*
180 * Allocate a scanline buffer for swapping during the vertical
181 * mirroring pass.
182 */
183 wrk_linesize = tile_width * sizeof (uint32);
184 if (tile_width != wrk_linesize / sizeof (uint32))
185 {
186 TIFFError(TIFFFileName(in), "Integer overflow when calculating wrk_line buffer");
187 exit(-1);
188 }
189 wrk_line = (uint32*)_TIFFmalloc(wrk_linesize);
190 if (!wrk_line) {
191 TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
192 ok = 0;
193 }
194
195 /*
196 * Loop over the tiles.
197 */
198 for( row = 0; ok && row < height; row += tile_height )
199 {
200 for( col = 0; ok && col < width; col += tile_width )
201 {
202 uint32 i_row;
203
204 /* Read the tile into an RGBA array */
205 if (!TIFFReadRGBATile(in, col, row, raster)) {
206 ok = 0;
207 break;
208 }
209
210
211 /*
212 * XXX: raster array has 4-byte unsigned integer type, that is why
213 * we should rearrange it here.
214 */
215 #if HOST_BIGENDIAN
216 TIFFSwabArrayOfLong(raster, tile_width * tile_height);
217 #endif
218
219 /*
220 * For some reason the TIFFReadRGBATile() function chooses the
221 * lower left corner as the origin. Vertically mirror scanlines.
222 */
223 for( i_row = 0; i_row < tile_height / 2; i_row++ )
224 {
225 uint32 *top_line, *bottom_line;
226
227 top_line = raster + tile_width * i_row;
228 bottom_line = raster + tile_width * (tile_height-i_row-1);
229
230 _TIFFmemcpy(wrk_line, top_line, 4*tile_width);
231 _TIFFmemcpy(top_line, bottom_line, 4*tile_width);
232 _TIFFmemcpy(bottom_line, wrk_line, 4*tile_width);
233 }
234
235 /*
236 * Write out the result in a tile.
237 */
238
239 if( TIFFWriteEncodedTile( out,
240 TIFFComputeTile( out, col, row, 0, 0),
241 raster,
242 4 * tile_width * tile_height ) == -1 )
243 {
244 ok = 0;
245 break;
246 }
247 }
248 }
249
250 _TIFFfree( raster );
251 _TIFFfree( wrk_line );
252
253 return ok;
254 }
255
256 static int
cvt_by_strip(TIFF * in,TIFF * out)257 cvt_by_strip( TIFF *in, TIFF *out )
258
259 {
260 uint32* raster; /* retrieve RGBA image */
261 uint32 width, height; /* image width & height */
262 uint32 row;
263 uint32 *wrk_line;
264 int ok = 1;
265 uint32 rastersize, wrk_linesize;
266
267 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
268 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
269
270 if( !TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip) ) {
271 TIFFError(TIFFFileName(in), "Source image not in strips");
272 return (0);
273 }
274
275 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
276
277 /*
278 * Allocate strip buffer
279 */
280 rastersize = width * rowsperstrip * sizeof (uint32);
281 if (width != (rastersize / rowsperstrip) / sizeof( uint32))
282 {
283 TIFFError(TIFFFileName(in), "Integer overflow when calculating raster buffer");
284 exit(-1);
285 }
286 raster = (uint32*)_TIFFmalloc(rastersize);
287 if (raster == 0) {
288 TIFFError(TIFFFileName(in), "No space for raster buffer");
289 return (0);
290 }
291
292 /*
293 * Allocate a scanline buffer for swapping during the vertical
294 * mirroring pass.
295 */
296 wrk_linesize = width * sizeof (uint32);
297 if (width != wrk_linesize / sizeof (uint32))
298 {
299 TIFFError(TIFFFileName(in), "Integer overflow when calculating wrk_line buffer");
300 exit(-1);
301 }
302 wrk_line = (uint32*)_TIFFmalloc(wrk_linesize);
303 if (!wrk_line) {
304 TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
305 ok = 0;
306 }
307
308 /*
309 * Loop over the strips.
310 */
311 for( row = 0; ok && row < height; row += rowsperstrip )
312 {
313 int rows_to_write, i_row;
314
315 /* Read the strip into an RGBA array */
316 if (!TIFFReadRGBAStrip(in, row, raster)) {
317 ok = 0;
318 break;
319 }
320
321 /*
322 * XXX: raster array has 4-byte unsigned integer type, that is why
323 * we should rearrange it here.
324 */
325 #if HOST_BIGENDIAN
326 TIFFSwabArrayOfLong(raster, width * rowsperstrip);
327 #endif
328
329 /*
330 * Figure out the number of scanlines actually in this strip.
331 */
332 if( row + rowsperstrip > height )
333 rows_to_write = height - row;
334 else
335 rows_to_write = rowsperstrip;
336
337 /*
338 * For some reason the TIFFReadRGBAStrip() function chooses the
339 * lower left corner as the origin. Vertically mirror scanlines.
340 */
341
342 for( i_row = 0; i_row < rows_to_write / 2; i_row++ )
343 {
344 uint32 *top_line, *bottom_line;
345
346 top_line = raster + width * i_row;
347 bottom_line = raster + width * (rows_to_write-i_row-1);
348
349 _TIFFmemcpy(wrk_line, top_line, 4*width);
350 _TIFFmemcpy(top_line, bottom_line, 4*width);
351 _TIFFmemcpy(bottom_line, wrk_line, 4*width);
352 }
353
354 /*
355 * Write out the result in a strip
356 */
357
358 if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster,
359 4 * rows_to_write * width ) == -1 )
360 {
361 ok = 0;
362 break;
363 }
364 }
365
366 _TIFFfree( raster );
367 _TIFFfree( wrk_line );
368
369 return ok;
370 }
371
372 /*
373 * cvt_whole_image()
374 *
375 * read the whole image into one big RGBA buffer and then write out
376 * strips from that. This is using the traditional TIFFReadRGBAImage()
377 * API that we trust.
378 */
379
380 static int
cvt_whole_image(TIFF * in,TIFF * out)381 cvt_whole_image( TIFF *in, TIFF *out )
382
383 {
384 uint32* raster; /* retrieve RGBA image */
385 uint32 width, height; /* image width & height */
386 uint32 row;
387 size_t pixel_count;
388
389 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
390 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
391 pixel_count = width * height;
392
393 /* XXX: Check the integer overflow. */
394 if (!width || !height || pixel_count / width != height) {
395 TIFFError(TIFFFileName(in),
396 "Malformed input file; can't allocate buffer for raster of %lux%lu size",
397 (unsigned long)width, (unsigned long)height);
398 return 0;
399 }
400
401 rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
402 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
403
404 raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32), "raster buffer");
405 if (raster == 0) {
406 TIFFError(TIFFFileName(in), "Failed to allocate buffer (%lu elements of %lu each)",
407 (unsigned long)pixel_count, (unsigned long)sizeof(uint32));
408 return (0);
409 }
410
411 /* Read the image in one chunk into an RGBA array */
412 if (!TIFFReadRGBAImageOriented(in, width, height, raster,
413 ORIENTATION_TOPLEFT, 0)) {
414 _TIFFfree(raster);
415 return (0);
416 }
417
418 /*
419 * XXX: raster array has 4-byte unsigned integer type, that is why
420 * we should rearrange it here.
421 */
422 #if HOST_BIGENDIAN
423 TIFFSwabArrayOfLong(raster, width * height);
424 #endif
425
426 /*
427 * Do we want to strip away alpha components?
428 */
429 if (no_alpha)
430 {
431 size_t count = pixel_count;
432 unsigned char *src, *dst;
433
434 src = dst = (unsigned char *) raster;
435 while (count > 0)
436 {
437 *(dst++) = *(src++);
438 *(dst++) = *(src++);
439 *(dst++) = *(src++);
440 src++;
441 count--;
442 }
443 }
444
445 /*
446 * Write out the result in strips
447 */
448 for (row = 0; row < height; row += rowsperstrip)
449 {
450 unsigned char * raster_strip;
451 int rows_to_write;
452 int bytes_per_pixel;
453
454 if (no_alpha)
455 {
456 raster_strip = ((unsigned char *) raster) + 3 * row * width;
457 bytes_per_pixel = 3;
458 }
459 else
460 {
461 raster_strip = (unsigned char *) (raster + row * width);
462 bytes_per_pixel = 4;
463 }
464
465 if( row + rowsperstrip > height )
466 rows_to_write = height - row;
467 else
468 rows_to_write = rowsperstrip;
469
470 if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster_strip,
471 bytes_per_pixel * rows_to_write * width ) == -1 )
472 {
473 _TIFFfree( raster );
474 return 0;
475 }
476 }
477
478 _TIFFfree( raster );
479
480 return 1;
481 }
482
483
484 static int
tiffcvt(TIFF * in,TIFF * out)485 tiffcvt(TIFF* in, TIFF* out)
486 {
487 uint32 width, height; /* image width & height */
488 uint16 shortv;
489 float floatv;
490 char *stringv;
491 uint32 longv;
492 uint16 v[1];
493
494 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
495 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
496
497 CopyField(TIFFTAG_SUBFILETYPE, longv);
498 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
499 TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
500 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
501 TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
502 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
503
504 CopyField(TIFFTAG_FILLORDER, shortv);
505 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
506
507 if( no_alpha )
508 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
509 else
510 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 4);
511
512 if( !no_alpha )
513 {
514 v[0] = EXTRASAMPLE_ASSOCALPHA;
515 TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
516 }
517
518 CopyField(TIFFTAG_XRESOLUTION, floatv);
519 CopyField(TIFFTAG_YRESOLUTION, floatv);
520 CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
521 TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
522 TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
523 CopyField(TIFFTAG_DOCUMENTNAME, stringv);
524
525 if( process_by_block && TIFFIsTiled( in ) )
526 return( cvt_by_tile( in, out ) );
527 else if( process_by_block )
528 return( cvt_by_strip( in, out ) );
529 else
530 return( cvt_whole_image( in, out ) );
531 }
532
533 static char* stuff[] = {
534 "usage: tiff2rgba [-c comp] [-r rows] [-b] [-n] [-8] input... output",
535 "where comp is one of the following compression algorithms:",
536 " jpeg\t\tJPEG encoding",
537 " zip\t\tZip/Deflate encoding",
538 " lzw\t\tLempel-Ziv & Welch encoding",
539 " packbits\tPackBits encoding",
540 " none\t\tno compression",
541 "and the other options are:",
542 " -r\trows/strip",
543 " -b (progress by block rather than as a whole image)",
544 " -n don't emit alpha component.",
545 " -8 write BigTIFF file instead of ClassicTIFF",
546 NULL
547 };
548
549 static void
usage(int code)550 usage(int code)
551 {
552 char buf[BUFSIZ];
553 int i;
554
555 setbuf(stderr, buf);
556 fprintf(stderr, "%s\n\n", TIFFGetVersion());
557 for (i = 0; stuff[i] != NULL; i++)
558 fprintf(stderr, "%s\n", stuff[i]);
559 exit(code);
560 }
561
562 /* vim: set ts=8 sts=8 sw=8 noet: */
563 /*
564 * Local Variables:
565 * mode: c
566 * c-basic-offset: 8
567 * fill-column: 78
568 * End:
569 */
570