New comit of SDL2
[supertux.git] / src / SDL2 / external / tiff-4.0.3 / tools / thumbnail.c
1 /* $Id: thumbnail.c,v 1.16 2010-07-02 12:02:56 dron Exp $ */
2
3 /*
4  * Copyright (c) 1994-1997 Sam Leffler
5  * Copyright (c) 1994-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 <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37
38 #ifdef NEED_LIBPORT
39 # include "libport.h"
40 #endif
41
42 #include "tiffio.h"
43
44 #ifndef HAVE_GETOPT
45 extern int getopt(int, char**, char*);
46 #endif
47
48 #define streq(a,b)      (strcmp(a,b) == 0)
49
50 #ifndef TIFFhowmany8
51 # define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
52 #endif
53
54 typedef enum {
55     EXP50,
56     EXP60,
57     EXP70,
58     EXP80,
59     EXP90,
60     EXP,
61     LINEAR
62 } Contrast;
63
64 static  uint32 tnw = 216;               /* thumbnail width */
65 static  uint32 tnh = 274;               /* thumbnail height */
66 static  Contrast contrast = LINEAR;     /* current contrast */
67 static  uint8* thumbnail;
68
69 static  int cpIFD(TIFF*, TIFF*);
70 static  int generateThumbnail(TIFF*, TIFF*);
71 static  void initScale();
72 static  void usage(void);
73
74 extern  char* optarg;
75 extern  int optind;
76
77 int
78 main(int argc, char* argv[])
79 {
80     TIFF* in;
81     TIFF* out;
82     int c;
83
84     while ((c = getopt(argc, argv, "w:h:c:")) != -1) {
85         switch (c) {
86         case 'w':       tnw = strtoul(optarg, NULL, 0); break;
87         case 'h':       tnh = strtoul(optarg, NULL, 0); break;
88         case 'c':       contrast = streq(optarg, "exp50") ? EXP50 :
89                                    streq(optarg, "exp60") ? EXP60 :
90                                    streq(optarg, "exp70") ? EXP70 :
91                                    streq(optarg, "exp80") ? EXP80 :
92                                    streq(optarg, "exp90") ? EXP90 :
93                                    streq(optarg, "exp")   ? EXP :
94                                    streq(optarg, "linear")? LINEAR :
95                                                             EXP;
96                         break;
97         default:        usage();
98         }
99     }
100     if (argc-optind != 2)
101         usage();
102
103     out = TIFFOpen(argv[optind+1], "w");
104     if (out == NULL)
105         return 2;
106     in = TIFFOpen(argv[optind], "r");
107     if( in == NULL )
108         return 2;
109
110     thumbnail = (uint8*) _TIFFmalloc(tnw * tnh);
111     if (!thumbnail) {
112             TIFFError(TIFFFileName(in),
113                       "Can't allocate space for thumbnail buffer.");
114             return 1;
115     }
116
117     if (in != NULL) {
118         initScale();
119         do {
120             if (!generateThumbnail(in, out))
121                 goto bad;
122             if (!cpIFD(in, out) || !TIFFWriteDirectory(out))
123                 goto bad;
124         } while (TIFFReadDirectory(in));
125         (void) TIFFClose(in);
126     }
127     (void) TIFFClose(out);
128     return 0;
129 bad:
130     (void) TIFFClose(out);
131     return 1;
132 }
133
134 #define CopyField(tag, v) \
135     if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
136 #define CopyField2(tag, v1, v2) \
137     if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
138 #define CopyField3(tag, v1, v2, v3) \
139     if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
140 #define CopyField4(tag, v1, v2, v3, v4) \
141     if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
142
143 static void
144 cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
145 {
146         switch (type) {
147         case TIFF_SHORT:
148                 if (count == 1) {
149                         uint16 shortv;
150                         CopyField(tag, shortv);
151                 } else if (count == 2) {
152                         uint16 shortv1, shortv2;
153                         CopyField2(tag, shortv1, shortv2);
154                 } else if (count == 4) {
155                         uint16 *tr, *tg, *tb, *ta;
156                         CopyField4(tag, tr, tg, tb, ta);
157                 } else if (count == (uint16) -1) {
158                         uint16 shortv1;
159                         uint16* shortav;
160                         CopyField2(tag, shortv1, shortav);
161                 }
162                 break;
163         case TIFF_LONG:
164                 { uint32 longv;
165                   CopyField(tag, longv);
166                 }
167                 break;
168         case TIFF_LONG8:
169                 { uint64 longv8;
170                   CopyField(tag, longv8);
171                 }
172                 break;
173         case TIFF_SLONG8:
174                 { int64 longv8;
175                   CopyField(tag, longv8);
176                 }
177                 break;
178         case TIFF_RATIONAL:
179                 if (count == 1) {
180                         float floatv;
181                         CopyField(tag, floatv);
182                 } else if (count == (uint16) -1) {
183                         float* floatav;
184                         CopyField(tag, floatav);
185                 }
186                 break;
187         case TIFF_ASCII:
188                 { char* stringv;
189                   CopyField(tag, stringv);
190                 }
191                 break;
192         case TIFF_DOUBLE:
193                 if (count == 1) {
194                         double doublev;
195                         CopyField(tag, doublev);
196                 } else if (count == (uint16) -1) {
197                         double* doubleav;
198                         CopyField(tag, doubleav);
199                 }
200                 break;
201         case TIFF_IFD8:
202                 { toff_t ifd8;
203                   CopyField(tag, ifd8);
204                 }
205                 break;          default:
206                 TIFFError(TIFFFileName(in),
207                           "Data type %d is not supported, tag %d skipped.",
208                           tag, type);
209         }
210 }
211
212 #undef CopyField4
213 #undef CopyField3
214 #undef CopyField2
215 #undef CopyField
216
217 static struct cpTag {
218     uint16      tag;
219     uint16      count;
220     TIFFDataType type;
221 } tags[] = {
222     { TIFFTAG_IMAGEWIDTH,               1, TIFF_LONG },
223     { TIFFTAG_IMAGELENGTH,              1, TIFF_LONG },
224     { TIFFTAG_BITSPERSAMPLE,            1, TIFF_SHORT },
225     { TIFFTAG_COMPRESSION,              1, TIFF_SHORT },
226     { TIFFTAG_FILLORDER,                1, TIFF_SHORT },
227     { TIFFTAG_SAMPLESPERPIXEL,          1, TIFF_SHORT },
228     { TIFFTAG_ROWSPERSTRIP,             1, TIFF_LONG },
229     { TIFFTAG_PLANARCONFIG,             1, TIFF_SHORT },
230     { TIFFTAG_GROUP3OPTIONS,            1, TIFF_LONG },
231     { TIFFTAG_SUBFILETYPE,              1, TIFF_LONG },
232     { TIFFTAG_PHOTOMETRIC,              1, TIFF_SHORT },
233     { TIFFTAG_THRESHHOLDING,            1, TIFF_SHORT },
234     { TIFFTAG_DOCUMENTNAME,             1, TIFF_ASCII },
235     { TIFFTAG_IMAGEDESCRIPTION,         1, TIFF_ASCII },
236     { TIFFTAG_MAKE,                     1, TIFF_ASCII },
237     { TIFFTAG_MODEL,                    1, TIFF_ASCII },
238     { TIFFTAG_ORIENTATION,              1, TIFF_SHORT },
239     { TIFFTAG_MINSAMPLEVALUE,           1, TIFF_SHORT },
240     { TIFFTAG_MAXSAMPLEVALUE,           1, TIFF_SHORT },
241     { TIFFTAG_XRESOLUTION,              1, TIFF_RATIONAL },
242     { TIFFTAG_YRESOLUTION,              1, TIFF_RATIONAL },
243     { TIFFTAG_PAGENAME,                 1, TIFF_ASCII },
244     { TIFFTAG_XPOSITION,                1, TIFF_RATIONAL },
245     { TIFFTAG_YPOSITION,                1, TIFF_RATIONAL },
246     { TIFFTAG_GROUP4OPTIONS,            1, TIFF_LONG },
247     { TIFFTAG_RESOLUTIONUNIT,           1, TIFF_SHORT },
248     { TIFFTAG_PAGENUMBER,               2, TIFF_SHORT },
249     { TIFFTAG_SOFTWARE,                 1, TIFF_ASCII },
250     { TIFFTAG_DATETIME,                 1, TIFF_ASCII },
251     { TIFFTAG_ARTIST,                   1, TIFF_ASCII },
252     { TIFFTAG_HOSTCOMPUTER,             1, TIFF_ASCII },
253     { TIFFTAG_WHITEPOINT,               2, TIFF_RATIONAL },
254     { TIFFTAG_PRIMARYCHROMATICITIES,    (uint16) -1,TIFF_RATIONAL },
255     { TIFFTAG_HALFTONEHINTS,            2, TIFF_SHORT },
256     { TIFFTAG_BADFAXLINES,              1, TIFF_LONG },
257     { TIFFTAG_CLEANFAXDATA,             1, TIFF_SHORT },
258     { TIFFTAG_CONSECUTIVEBADFAXLINES,   1, TIFF_LONG },
259     { TIFFTAG_INKSET,                   1, TIFF_SHORT },
260     { TIFFTAG_INKNAMES,                 1, TIFF_ASCII },
261     { TIFFTAG_DOTRANGE,                 2, TIFF_SHORT },
262     { TIFFTAG_TARGETPRINTER,            1, TIFF_ASCII },
263     { TIFFTAG_SAMPLEFORMAT,             1, TIFF_SHORT },
264     { TIFFTAG_YCBCRCOEFFICIENTS,        (uint16) -1,TIFF_RATIONAL },
265     { TIFFTAG_YCBCRSUBSAMPLING,         2, TIFF_SHORT },
266     { TIFFTAG_YCBCRPOSITIONING,         1, TIFF_SHORT },
267     { TIFFTAG_REFERENCEBLACKWHITE,      (uint16) -1,TIFF_RATIONAL },
268     { TIFFTAG_EXTRASAMPLES,             (uint16) -1, TIFF_SHORT },
269 };
270 #define NTAGS   (sizeof (tags) / sizeof (tags[0]))
271
272 static void
273 cpTags(TIFF* in, TIFF* out)
274 {
275     struct cpTag *p;
276     for (p = tags; p < &tags[NTAGS]; p++)
277         cpTag(in, out, p->tag, p->count, p->type);
278 }
279 #undef NTAGS
280
281 static int
282 cpStrips(TIFF* in, TIFF* out)
283 {
284     tsize_t bufsize  = TIFFStripSize(in);
285     unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
286
287     if (buf) {
288         tstrip_t s, ns = TIFFNumberOfStrips(in);
289         uint64 *bytecounts;
290
291         TIFFGetField(in, TIFFTAG_STRIPBYTECOUNTS, &bytecounts);
292         for (s = 0; s < ns; s++) {
293           if (bytecounts[s] > (uint64) bufsize) {
294                 buf = (unsigned char *)_TIFFrealloc(buf, (tmsize_t)bytecounts[s]);
295                 if (!buf)
296                     goto bad;
297                 bufsize = (tmsize_t)bytecounts[s];
298             }
299             if (TIFFReadRawStrip(in, s, buf, (tmsize_t)bytecounts[s]) < 0 ||
300                 TIFFWriteRawStrip(out, s, buf, (tmsize_t)bytecounts[s]) < 0) {
301                 _TIFFfree(buf);
302                 return 0;
303             }
304         }
305         _TIFFfree(buf);
306         return 1;
307     }
308
309 bad:
310         TIFFError(TIFFFileName(in),
311                   "Can't allocate space for strip buffer.");
312         return 0;
313 }
314
315 static int
316 cpTiles(TIFF* in, TIFF* out)
317 {
318     tsize_t bufsize = TIFFTileSize(in);
319     unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
320
321     if (buf) {
322         ttile_t t, nt = TIFFNumberOfTiles(in);
323         uint64 *bytecounts;
324
325         TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts);
326         for (t = 0; t < nt; t++) {
327             if (bytecounts[t] > (uint64) bufsize) {
328                 buf = (unsigned char *)_TIFFrealloc(buf, (tmsize_t)bytecounts[t]);
329                 if (!buf)
330                     goto bad;
331                 bufsize = (tmsize_t)bytecounts[t];
332             }
333             if (TIFFReadRawTile(in, t, buf, (tmsize_t)bytecounts[t]) < 0 ||
334                 TIFFWriteRawTile(out, t, buf, (tmsize_t)bytecounts[t]) < 0) {
335                 _TIFFfree(buf);
336                 return 0;
337             }
338         }
339         _TIFFfree(buf);
340         return 1;
341     }
342
343 bad:
344     TIFFError(TIFFFileName(in),
345                   "Can't allocate space for tile buffer.");
346         return (0);
347 }
348
349 static int
350 cpIFD(TIFF* in, TIFF* out)
351 {
352     cpTags(in, out);
353     if (TIFFIsTiled(in)) {
354         if (!cpTiles(in, out))
355             return (0);
356     } else {
357         if (!cpStrips(in, out))
358             return (0);
359     }
360     return (1);
361 }
362
363 static  uint16  photometric;            /* current photometric of raster */
364 static  uint16  filterWidth;            /* filter width in pixels */
365 static  uint32  stepSrcWidth;           /* src image stepping width */
366 static  uint32  stepDstWidth;           /* dest stepping width */
367 static  uint8* src0;                    /* horizontal bit stepping (start) */
368 static  uint8* src1;                    /* horizontal bit stepping (middle) */
369 static  uint8* src2;                    /* horizontal bit stepping (end) */
370 static  uint32* rowoff;                 /* row offset for stepping */
371 static  uint8 cmap[256];                /* colormap indexes */
372 static  uint8 bits[256];                /* count of bits set */
373
374 static void
375 setupBitsTables()
376 {
377     int i;
378     for (i = 0; i < 256; i++) {
379         int n = 0;
380         if (i&0x01) n++;
381         if (i&0x02) n++;
382         if (i&0x04) n++;
383         if (i&0x08) n++;
384         if (i&0x10) n++;
385         if (i&0x20) n++;
386         if (i&0x40) n++;
387         if (i&0x80) n++;
388         bits[i] = n;
389     }
390 }
391
392 static int clamp(float v, int low, int high)
393     { return (v < low ? low : v > high ? high : (int)v); }
394
395 #ifndef M_E
396 #define M_E             2.7182818284590452354
397 #endif
398
399 static void
400 expFill(float pct[], uint32 p, uint32 n)
401 {
402     uint32 i;
403     uint32 c = (p * n) / 100;
404     for (i = 1; i < c; i++)
405         pct[i] = (float) (1-exp(i/((double)(n-1)))/ M_E);
406     for (; i < n; i++)
407         pct[i] = 0.;
408 }
409
410 static void
411 setupCmap()
412 {
413     float pct[256];                     /* known to be large enough */
414     uint32 i;
415     pct[0] = 1;                         /* force white */
416     switch (contrast) {
417     case EXP50: expFill(pct, 50, 256); break;
418     case EXP60: expFill(pct, 60, 256); break;
419     case EXP70: expFill(pct, 70, 256); break;
420     case EXP80: expFill(pct, 80, 256); break;
421     case EXP90: expFill(pct, 90, 256); break;
422     case EXP:   expFill(pct, 100, 256); break;
423     case LINEAR:
424         for (i = 1; i < 256; i++)
425             pct[i] = 1-((float)i)/(256-1);
426         break;
427     }
428     switch (photometric) {
429     case PHOTOMETRIC_MINISWHITE:
430         for (i = 0; i < 256; i++)
431             cmap[i] = clamp(255*pct[(256-1)-i], 0, 255);
432         break;
433     case PHOTOMETRIC_MINISBLACK:
434         for (i = 0; i < 256; i++)
435             cmap[i] = clamp(255*pct[i], 0, 255);
436         break;
437     }
438 }
439
440 static void
441 initScale()
442 {
443     src0 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
444     src1 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
445     src2 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
446     rowoff = (uint32*) _TIFFmalloc(sizeof (uint32) * tnw);
447     filterWidth = 0;
448     stepDstWidth = stepSrcWidth = 0;
449     setupBitsTables();
450 }
451
452 /*
453  * Calculate the horizontal accumulation parameteres
454  * according to the widths of the src and dst images.
455  */
456 static void
457 setupStepTables(uint32 sw)
458 {
459     if (stepSrcWidth != sw || stepDstWidth != tnw) {
460         int step = sw;
461         int limit = tnw;
462         int err = 0;
463         uint32 sx = 0;
464         uint32 x;
465         int fw;
466         uint8 b;
467         for (x = 0; x < tnw; x++) {
468             uint32 sx0 = sx;
469             err += step;
470             while (err >= limit) {
471                 err -= limit;
472                 sx++;
473             }
474             rowoff[x] = sx0 >> 3;
475             fw = sx - sx0;              /* width */
476             b = (fw < 8) ? 0xff<<(8-fw) : 0xff;
477             src0[x] = b >> (sx0&7);
478             fw -= 8 - (sx0&7);
479             if (fw < 0)
480                 fw = 0;
481             src1[x] = fw >> 3;
482             fw -= (fw>>3)<<3;
483             src2[x] = 0xff << (8-fw);
484         }
485         stepSrcWidth = sw;
486         stepDstWidth = tnw;
487     }
488 }
489
490 static void
491 setrow(uint8* row, uint32 nrows, const uint8* rows[])
492 {
493     uint32 x;
494     uint32 area = nrows * filterWidth;
495     for (x = 0; x < tnw; x++) {
496         uint32 mask0 = src0[x];
497         uint32 fw = src1[x];
498         uint32 mask1 = src1[x];
499         uint32 off = rowoff[x];
500         uint32 acc = 0;
501         uint32 y, i;
502         for (y = 0; y < nrows; y++) {
503             const uint8* src = rows[y] + off;
504             acc += bits[*src++ & mask0];
505             switch (fw) {
506             default:
507                 for (i = fw; i > 8; i--)
508                     acc += bits[*src++];
509                 /* fall thru... */
510             case 8: acc += bits[*src++];
511             case 7: acc += bits[*src++];
512             case 6: acc += bits[*src++];
513             case 5: acc += bits[*src++];
514             case 4: acc += bits[*src++];
515             case 3: acc += bits[*src++];
516             case 2: acc += bits[*src++];
517             case 1: acc += bits[*src++];
518             case 0: break;
519             }
520             acc += bits[*src & mask1];
521         }
522         *row++ = cmap[(255*acc)/area];
523     }
524 }
525
526 /*
527  * Install the specified image.  The
528  * image is resized to fit the display page using
529  * a box filter.  The resultant pixels are mapped
530  * with a user-selectable contrast curve.
531  */
532 static void
533 setImage1(const uint8* br, uint32 rw, uint32 rh)
534 {
535     int step = rh;
536     int limit = tnh;
537     int err = 0;
538     int bpr = TIFFhowmany8(rw);
539     int sy = 0;
540     uint8* row = thumbnail;
541     uint32 dy;
542     for (dy = 0; dy < tnh; dy++) {
543         const uint8* rows[256];
544         uint32 nrows = 1;
545         fprintf(stderr, "bpr=%d, sy=%d, bpr*sy=%d\n", bpr, sy, bpr*sy);
546         rows[0] = br + bpr*sy;
547         err += step;
548         while (err >= limit) {
549             err -= limit;
550             sy++;
551             if (err >= limit)
552                 rows[nrows++] = br + bpr*sy;
553         }
554         setrow(row, nrows, rows);
555         row += tnw;
556     }
557 }
558
559 static void
560 setImage(const uint8* br, uint32 rw, uint32 rh)
561 {
562     filterWidth = (uint16) ceil((double) rw / (double) tnw);
563     setupStepTables(rw);
564     setImage1(br, rw, rh);
565 }
566
567 static int
568 generateThumbnail(TIFF* in, TIFF* out)
569 {
570     unsigned char* raster;
571     unsigned char* rp;
572     uint32 sw, sh, rps;
573     uint16 bps, spp;
574     tsize_t rowsize, rastersize;
575     tstrip_t s, ns = TIFFNumberOfStrips(in);
576     toff_t diroff[1];
577
578     TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &sw);
579     TIFFGetField(in, TIFFTAG_IMAGELENGTH, &sh);
580     TIFFGetFieldDefaulted(in, TIFFTAG_BITSPERSAMPLE, &bps);
581     TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &spp);
582     TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps);
583     if (spp != 1 || bps != 1)
584         return 0;
585     rowsize = TIFFScanlineSize(in);
586     rastersize = sh * rowsize;
587     fprintf(stderr, "rastersize=%u\n", (unsigned int)rastersize);
588     raster = (unsigned char*)_TIFFmalloc(rastersize);
589     if (!raster) {
590             TIFFError(TIFFFileName(in),
591                       "Can't allocate space for raster buffer.");
592             return 0;
593     }
594     rp = raster;
595     for (s = 0; s < ns; s++) {
596         (void) TIFFReadEncodedStrip(in, s, rp, -1);
597         rp += rps * rowsize;
598     }
599     TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric);
600     setupCmap();
601     setImage(raster, sw, sh);
602     _TIFFfree(raster);
603
604     TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE);
605     TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) tnw);
606     TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) tnh);
607     TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (uint16) 8);
608     TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (uint16) 1);
609     TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
610     TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
611     TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
612     TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
613     cpTag(in, out, TIFFTAG_SOFTWARE,            (uint16) -1, TIFF_ASCII);
614     cpTag(in, out, TIFFTAG_IMAGEDESCRIPTION,    (uint16) -1, TIFF_ASCII);
615     cpTag(in, out, TIFFTAG_DATETIME,            (uint16) -1, TIFF_ASCII);
616     cpTag(in, out, TIFFTAG_HOSTCOMPUTER,        (uint16) -1, TIFF_ASCII);
617     diroff[0] = 0UL;
618     TIFFSetField(out, TIFFTAG_SUBIFD, 1, diroff);
619     return (TIFFWriteEncodedStrip(out, 0, thumbnail, tnw*tnh) != -1 &&
620             TIFFWriteDirectory(out) != -1);
621 }
622
623 char* stuff[] = {
624 "usage: thumbnail [options] input.tif output.tif",
625 "where options are:",
626 " -h #          specify thumbnail image height (default is 274)",
627 " -w #          specify thumbnail image width (default is 216)",
628 "",
629 " -c linear     use linear contrast curve",
630 " -c exp50      use 50% exponential contrast curve",
631 " -c exp60      use 60% exponential contrast curve",
632 " -c exp70      use 70% exponential contrast curve",
633 " -c exp80      use 80% exponential contrast curve",
634 " -c exp90      use 90% exponential contrast curve",
635 " -c exp                use pure exponential contrast curve",
636 NULL
637 };
638
639 static void
640 usage(void)
641 {
642         char buf[BUFSIZ];
643         int i;
644
645         setbuf(stderr, buf);
646         fprintf(stderr, "%s\n\n", TIFFGetVersion());
647         for (i = 0; stuff[i] != NULL; i++)
648                 fprintf(stderr, "%s\n", stuff[i]);
649         exit(-1);
650 }
651
652 /* vim: set ts=8 sts=8 sw=8 noet: */
653 /*
654  * Local Variables:
655  * mode: c
656  * c-basic-offset: 8
657  * fill-column: 78
658  * End:
659  */