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