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