]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/tools/tiff2rgba.c
52d72b155070e93299fa64a5d28f0bf49cb22bae
[wxWidgets.git] / src / tiff / tools / tiff2rgba.c
1 /* $Id$ */
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
64 main(int argc, char* argv[])
65 {
66 TIFF *in, *out;
67 int c;
68 extern int optind;
69 extern char *optarg;
70
71 while ((c = getopt(argc, argv, "c:r:t:bn8")) != -1)
72 switch (c) {
73 case 'b':
74 process_by_block = 1;
75 break;
76
77 case 'c':
78 if (streq(optarg, "none"))
79 compression = COMPRESSION_NONE;
80 else if (streq(optarg, "packbits"))
81 compression = COMPRESSION_PACKBITS;
82 else if (streq(optarg, "lzw"))
83 compression = COMPRESSION_LZW;
84 else if (streq(optarg, "jpeg"))
85 compression = COMPRESSION_JPEG;
86 else if (streq(optarg, "zip"))
87 compression = COMPRESSION_DEFLATE;
88 else
89 usage(-1);
90 break;
91
92 case 'r':
93 rowsperstrip = atoi(optarg);
94 break;
95
96 case 't':
97 rowsperstrip = atoi(optarg);
98 break;
99
100 case 'n':
101 no_alpha = 1;
102 break;
103
104 case '8':
105 bigtiff_output = 1;
106 break;
107
108 case '?':
109 usage(0);
110 /*NOTREACHED*/
111 }
112
113 if (argc - optind < 2)
114 usage(-1);
115
116 out = TIFFOpen(argv[argc-1], bigtiff_output?"w8":"w");
117 if (out == NULL)
118 return (-2);
119
120 for (; optind < argc-1; optind++) {
121 in = TIFFOpen(argv[optind], "r");
122 if (in != NULL) {
123 do {
124 if (!tiffcvt(in, out) ||
125 !TIFFWriteDirectory(out)) {
126 (void) TIFFClose(out);
127 (void) TIFFClose(in);
128 return (1);
129 }
130 } while (TIFFReadDirectory(in));
131 (void) TIFFClose(in);
132 }
133 }
134 (void) TIFFClose(out);
135 return (0);
136 }
137
138 static int
139 cvt_by_tile( TIFF *in, TIFF *out )
140
141 {
142 uint32* raster; /* retrieve RGBA image */
143 uint32 width, height; /* image width & height */
144 uint32 tile_width, tile_height;
145 uint32 row, col;
146 uint32 *wrk_line;
147 int ok = 1;
148
149 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
150 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
151
152 if( !TIFFGetField(in, TIFFTAG_TILEWIDTH, &tile_width)
153 || !TIFFGetField(in, TIFFTAG_TILELENGTH, &tile_height) ) {
154 TIFFError(TIFFFileName(in), "Source image not tiled");
155 return (0);
156 }
157
158 TIFFSetField(out, TIFFTAG_TILEWIDTH, tile_width );
159 TIFFSetField(out, TIFFTAG_TILELENGTH, tile_height );
160
161 /*
162 * Allocate tile buffer
163 */
164 raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32));
165 if (raster == 0) {
166 TIFFError(TIFFFileName(in), "No space for raster buffer");
167 return (0);
168 }
169
170 /*
171 * Allocate a scanline buffer for swapping during the vertical
172 * mirroring pass.
173 */
174 wrk_line = (uint32*)_TIFFmalloc(tile_width * sizeof (uint32));
175 if (!wrk_line) {
176 TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
177 ok = 0;
178 }
179
180 /*
181 * Loop over the tiles.
182 */
183 for( row = 0; ok && row < height; row += tile_height )
184 {
185 for( col = 0; ok && col < width; col += tile_width )
186 {
187 uint32 i_row;
188
189 /* Read the tile into an RGBA array */
190 if (!TIFFReadRGBATile(in, col, row, raster)) {
191 ok = 0;
192 break;
193 }
194
195
196 /*
197 * XXX: raster array has 4-byte unsigned integer type, that is why
198 * we should rearrange it here.
199 */
200 #if HOST_BIGENDIAN
201 TIFFSwabArrayOfLong(raster, tile_width * tile_height);
202 #endif
203
204 /*
205 * For some reason the TIFFReadRGBATile() function chooses the
206 * lower left corner as the origin. Vertically mirror scanlines.
207 */
208 for( i_row = 0; i_row < tile_height / 2; i_row++ )
209 {
210 uint32 *top_line, *bottom_line;
211
212 top_line = raster + tile_width * i_row;
213 bottom_line = raster + tile_width * (tile_height-i_row-1);
214
215 _TIFFmemcpy(wrk_line, top_line, 4*tile_width);
216 _TIFFmemcpy(top_line, bottom_line, 4*tile_width);
217 _TIFFmemcpy(bottom_line, wrk_line, 4*tile_width);
218 }
219
220 /*
221 * Write out the result in a tile.
222 */
223
224 if( TIFFWriteEncodedTile( out,
225 TIFFComputeTile( out, col, row, 0, 0),
226 raster,
227 4 * tile_width * tile_height ) == -1 )
228 {
229 ok = 0;
230 break;
231 }
232 }
233 }
234
235 _TIFFfree( raster );
236 _TIFFfree( wrk_line );
237
238 return ok;
239 }
240
241 static int
242 cvt_by_strip( TIFF *in, TIFF *out )
243
244 {
245 uint32* raster; /* retrieve RGBA image */
246 uint32 width, height; /* image width & height */
247 uint32 row;
248 uint32 *wrk_line;
249 int ok = 1;
250
251 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
252 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
253
254 if( !TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip) ) {
255 TIFFError(TIFFFileName(in), "Source image not in strips");
256 return (0);
257 }
258
259 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
260
261 /*
262 * Allocate strip buffer
263 */
264 raster = (uint32*)_TIFFmalloc(width * rowsperstrip * sizeof (uint32));
265 if (raster == 0) {
266 TIFFError(TIFFFileName(in), "No space for raster buffer");
267 return (0);
268 }
269
270 /*
271 * Allocate a scanline buffer for swapping during the vertical
272 * mirroring pass.
273 */
274 wrk_line = (uint32*)_TIFFmalloc(width * sizeof (uint32));
275 if (!wrk_line) {
276 TIFFError(TIFFFileName(in), "No space for raster scanline buffer");
277 ok = 0;
278 }
279
280 /*
281 * Loop over the strips.
282 */
283 for( row = 0; ok && row < height; row += rowsperstrip )
284 {
285 int rows_to_write, i_row;
286
287 /* Read the strip into an RGBA array */
288 if (!TIFFReadRGBAStrip(in, row, raster)) {
289 ok = 0;
290 break;
291 }
292
293 /*
294 * XXX: raster array has 4-byte unsigned integer type, that is why
295 * we should rearrange it here.
296 */
297 #if HOST_BIGENDIAN
298 TIFFSwabArrayOfLong(raster, width * rowsperstrip);
299 #endif
300
301 /*
302 * Figure out the number of scanlines actually in this strip.
303 */
304 if( row + rowsperstrip > height )
305 rows_to_write = height - row;
306 else
307 rows_to_write = rowsperstrip;
308
309 /*
310 * For some reason the TIFFReadRGBAStrip() function chooses the
311 * lower left corner as the origin. Vertically mirror scanlines.
312 */
313
314 for( i_row = 0; i_row < rows_to_write / 2; i_row++ )
315 {
316 uint32 *top_line, *bottom_line;
317
318 top_line = raster + width * i_row;
319 bottom_line = raster + width * (rows_to_write-i_row-1);
320
321 _TIFFmemcpy(wrk_line, top_line, 4*width);
322 _TIFFmemcpy(top_line, bottom_line, 4*width);
323 _TIFFmemcpy(bottom_line, wrk_line, 4*width);
324 }
325
326 /*
327 * Write out the result in a strip
328 */
329
330 if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster,
331 4 * rows_to_write * width ) == -1 )
332 {
333 ok = 0;
334 break;
335 }
336 }
337
338 _TIFFfree( raster );
339 _TIFFfree( wrk_line );
340
341 return ok;
342 }
343
344 /*
345 * cvt_whole_image()
346 *
347 * read the whole image into one big RGBA buffer and then write out
348 * strips from that. This is using the traditional TIFFReadRGBAImage()
349 * API that we trust.
350 */
351
352 static int
353 cvt_whole_image( TIFF *in, TIFF *out )
354
355 {
356 uint32* raster; /* retrieve RGBA image */
357 uint32 width, height; /* image width & height */
358 uint32 row;
359 size_t pixel_count;
360
361 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
362 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
363 pixel_count = width * height;
364
365 /* XXX: Check the integer overflow. */
366 if (!width || !height || pixel_count / width != height) {
367 TIFFError(TIFFFileName(in),
368 "Malformed input file; can't allocate buffer for raster of %lux%lu size",
369 (unsigned long)width, (unsigned long)height);
370 return 0;
371 }
372
373 rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip);
374 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
375
376 raster = (uint32*)_TIFFCheckMalloc(in, pixel_count, sizeof(uint32), "raster buffer");
377 if (raster == 0) {
378 TIFFError(TIFFFileName(in), "Failed to allocate buffer (%lu elements of %lu each)",
379 (unsigned long)pixel_count, (unsigned long)sizeof(uint32));
380 return (0);
381 }
382
383 /* Read the image in one chunk into an RGBA array */
384 if (!TIFFReadRGBAImageOriented(in, width, height, raster,
385 ORIENTATION_TOPLEFT, 0)) {
386 _TIFFfree(raster);
387 return (0);
388 }
389
390 /*
391 * XXX: raster array has 4-byte unsigned integer type, that is why
392 * we should rearrange it here.
393 */
394 #if HOST_BIGENDIAN
395 TIFFSwabArrayOfLong(raster, width * height);
396 #endif
397
398 /*
399 * Do we want to strip away alpha components?
400 */
401 if (no_alpha)
402 {
403 size_t count = pixel_count;
404 unsigned char *src, *dst;
405
406 src = dst = (unsigned char *) raster;
407 while (count > 0)
408 {
409 *(dst++) = *(src++);
410 *(dst++) = *(src++);
411 *(dst++) = *(src++);
412 src++;
413 count--;
414 }
415 }
416
417 /*
418 * Write out the result in strips
419 */
420 for (row = 0; row < height; row += rowsperstrip)
421 {
422 unsigned char * raster_strip;
423 int rows_to_write;
424 int bytes_per_pixel;
425
426 if (no_alpha)
427 {
428 raster_strip = ((unsigned char *) raster) + 3 * row * width;
429 bytes_per_pixel = 3;
430 }
431 else
432 {
433 raster_strip = (unsigned char *) (raster + row * width);
434 bytes_per_pixel = 4;
435 }
436
437 if( row + rowsperstrip > height )
438 rows_to_write = height - row;
439 else
440 rows_to_write = rowsperstrip;
441
442 if( TIFFWriteEncodedStrip( out, row / rowsperstrip, raster_strip,
443 bytes_per_pixel * rows_to_write * width ) == -1 )
444 {
445 _TIFFfree( raster );
446 return 0;
447 }
448 }
449
450 _TIFFfree( raster );
451
452 return 1;
453 }
454
455
456 static int
457 tiffcvt(TIFF* in, TIFF* out)
458 {
459 uint32 width, height; /* image width & height */
460 uint16 shortv;
461 float floatv;
462 char *stringv;
463 uint32 longv;
464 uint16 v[1];
465
466 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
467 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
468
469 CopyField(TIFFTAG_SUBFILETYPE, longv);
470 TIFFSetField(out, TIFFTAG_IMAGEWIDTH, width);
471 TIFFSetField(out, TIFFTAG_IMAGELENGTH, height);
472 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 8);
473 TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
474 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
475
476 CopyField(TIFFTAG_FILLORDER, shortv);
477 TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
478
479 if( no_alpha )
480 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 3);
481 else
482 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, 4);
483
484 if( !no_alpha )
485 {
486 v[0] = EXTRASAMPLE_ASSOCALPHA;
487 TIFFSetField(out, TIFFTAG_EXTRASAMPLES, 1, v);
488 }
489
490 CopyField(TIFFTAG_XRESOLUTION, floatv);
491 CopyField(TIFFTAG_YRESOLUTION, floatv);
492 CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
493 TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
494 TIFFSetField(out, TIFFTAG_SOFTWARE, TIFFGetVersion());
495 CopyField(TIFFTAG_DOCUMENTNAME, stringv);
496
497 if( process_by_block && TIFFIsTiled( in ) )
498 return( cvt_by_tile( in, out ) );
499 else if( process_by_block )
500 return( cvt_by_strip( in, out ) );
501 else
502 return( cvt_whole_image( in, out ) );
503 }
504
505 static char* stuff[] = {
506 "usage: tiff2rgba [-c comp] [-r rows] [-b] [-n] [-8] input... output",
507 "where comp is one of the following compression algorithms:",
508 " jpeg\t\tJPEG encoding",
509 " zip\t\tLempel-Ziv & Welch encoding",
510 " lzw\t\tLempel-Ziv & Welch encoding",
511 " packbits\tPackBits encoding",
512 " none\t\tno compression",
513 "and the other options are:",
514 " -r\trows/strip",
515 " -b (progress by block rather than as a whole image)",
516 " -n don't emit alpha component.",
517 " -8 write BigTIFF file instead of ClassicTIFF",
518 NULL
519 };
520
521 static void
522 usage(int code)
523 {
524 char buf[BUFSIZ];
525 int i;
526
527 setbuf(stderr, buf);
528 fprintf(stderr, "%s\n\n", TIFFGetVersion());
529 for (i = 0; stuff[i] != NULL; i++)
530 fprintf(stderr, "%s\n", stuff[i]);
531 exit(code);
532 }
533
534 /* vim: set ts=8 sts=8 sw=8 noet: */
535 /*
536 * Local Variables:
537 * mode: c
538 * c-basic-offset: 8
539 * fill-column: 78
540 * End:
541 */