~ubuntu-branches/ubuntu/precise/tiff/precise-security

« back to all changes in this revision

Viewing changes to .pc/CVE-2014-81xx-5.patch/tools/thumbnail.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2015-03-30 08:11:18 UTC
  • Revision ID: package-import@ubuntu.com-20150330081118-bvaoaii1act27voq
Tags: 3.9.5-2ubuntu1.7
* SECURITY UPDATE: Fix multiple security issues
  - debian/patches/CVE-2014-81xx-1.patch to CVE-2014-81xx-11.patch
  - debian/patches/CVE-2014-8128-5.patch
  - debian/patches/CVE-2014-9655-1.patch to CVE-2014-9655-3.patch
  - debian/patches/read_overrun.patch
  - debian/patches/CVE-2014-8130.patch
  - CVE-2014-8127 (partially)
  - CVE-2014-8128
  - CVE-2014-8129
  - CVE-2014-8130
  - CVE-2014-9330
  - CVE-2014-9655

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: thumbnail.c,v 1.9.2.2 2010-07-02 12:03:27 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
#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,               2, 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
 */