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