Blame tools/thumbnail.c

Packit Service 2594b8
/* $Id: thumbnail.c,v 1.21 2015-06-21 01:09:10 bfriesen Exp $ */
Packit Service 2594b8
Packit Service 2594b8
/*
Packit Service 2594b8
 * Copyright (c) 1994-1997 Sam Leffler
Packit Service 2594b8
 * Copyright (c) 1994-1997 Silicon Graphics, Inc.
Packit Service 2594b8
 *
Packit Service 2594b8
 * Permission to use, copy, modify, distribute, and sell this software and 
Packit Service 2594b8
 * its documentation for any purpose is hereby granted without fee, provided
Packit Service 2594b8
 * that (i) the above copyright notices and this permission notice appear in
Packit Service 2594b8
 * all copies of the software and related documentation, and (ii) the names of
Packit Service 2594b8
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
Packit Service 2594b8
 * publicity relating to the software without the specific, prior written
Packit Service 2594b8
 * permission of Sam Leffler and Silicon Graphics.
Packit Service 2594b8
 * 
Packit Service 2594b8
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
Packit Service 2594b8
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
Packit Service 2594b8
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
Packit Service 2594b8
 * 
Packit Service 2594b8
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
Packit Service 2594b8
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
Packit Service 2594b8
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
Packit Service 2594b8
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
Packit Service 2594b8
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
Packit Service 2594b8
 * OF THIS SOFTWARE.
Packit Service 2594b8
 */
Packit Service 2594b8
Packit Service 2594b8
#include "tif_config.h"
Packit Service 2594b8
Packit Service 2594b8
#include <stdio.h>
Packit Service 2594b8
#include <stdlib.h>
Packit Service 2594b8
#include <string.h>
Packit Service 2594b8
#include <math.h>
Packit Service 2594b8
Packit Service 2594b8
#ifdef HAVE_UNISTD_H
Packit Service 2594b8
# include <unistd.h>
Packit Service 2594b8
#endif
Packit Service 2594b8
Packit Service 2594b8
#ifdef NEED_LIBPORT
Packit Service 2594b8
# include "libport.h"
Packit Service 2594b8
#endif
Packit Service 2594b8
Packit Service 2594b8
#include "tiffio.h"
Packit Service 2594b8
Packit Service 2594b8
#ifndef HAVE_GETOPT
Packit Service 2594b8
extern int getopt(int, char**, char*);
Packit Service 2594b8
#endif
Packit Service 2594b8
Packit Service 2594b8
#define	streq(a,b)	(strcmp(a,b) == 0)
Packit Service 2594b8
Packit Service 2594b8
#ifndef TIFFhowmany8
Packit Service 2594b8
# define TIFFhowmany8(x) (((x)&0x07)?((uint32)(x)>>3)+1:(uint32)(x)>>3)
Packit Service 2594b8
#endif
Packit Service 2594b8
Packit Service 2594b8
typedef enum {
Packit Service 2594b8
    EXP50,
Packit Service 2594b8
    EXP60,
Packit Service 2594b8
    EXP70,
Packit Service 2594b8
    EXP80,
Packit Service 2594b8
    EXP90,
Packit Service 2594b8
    EXP,
Packit Service 2594b8
    LINEAR
Packit Service 2594b8
} Contrast;
Packit Service 2594b8
Packit Service 2594b8
static	uint32 tnw = 216;		/* thumbnail width */
Packit Service 2594b8
static	uint32 tnh = 274;		/* thumbnail height */
Packit Service 2594b8
static	Contrast contrast = LINEAR;	/* current contrast */
Packit Service 2594b8
static	uint8* thumbnail;
Packit Service 2594b8
Packit Service 2594b8
static	int cpIFD(TIFF*, TIFF*);
Packit Service 2594b8
static	int generateThumbnail(TIFF*, TIFF*);
Packit Service 2594b8
static	void initScale();
Packit Service 2594b8
static	void usage(void);
Packit Service 2594b8
Packit Service 2594b8
#if !HAVE_DECL_OPTARG
Packit Service 2594b8
extern	char* optarg;
Packit Service 2594b8
extern	int optind;
Packit Service 2594b8
#endif
Packit Service 2594b8
Packit Service 2594b8
int
Packit Service 2594b8
main(int argc, char* argv[])
Packit Service 2594b8
{
Packit Service 2594b8
    TIFF* in;
Packit Service 2594b8
    TIFF* out;
Packit Service 2594b8
    int c;
Packit Service 2594b8
Packit Service 2594b8
    while ((c = getopt(argc, argv, "w:h:c:")) != -1) {
Packit Service 2594b8
	switch (c) {
Packit Service 2594b8
	case 'w':	tnw = strtoul(optarg, NULL, 0); break;
Packit Service 2594b8
	case 'h':	tnh = strtoul(optarg, NULL, 0); break;
Packit Service 2594b8
	case 'c':	contrast = streq(optarg, "exp50") ? EXP50 :
Packit Service 2594b8
				   streq(optarg, "exp60") ? EXP60 :
Packit Service 2594b8
				   streq(optarg, "exp70") ? EXP70 :
Packit Service 2594b8
				   streq(optarg, "exp80") ? EXP80 :
Packit Service 2594b8
				   streq(optarg, "exp90") ? EXP90 :
Packit Service 2594b8
				   streq(optarg, "exp")   ? EXP :
Packit Service 2594b8
				   streq(optarg, "linear")? LINEAR :
Packit Service 2594b8
							    EXP;
Packit Service 2594b8
			break;
Packit Service 2594b8
	default:	usage();
Packit Service 2594b8
	}
Packit Service 2594b8
    }
Packit Service 2594b8
    if (argc-optind != 2)
Packit Service 2594b8
	usage();
Packit Service 2594b8
Packit Service 2594b8
    out = TIFFOpen(argv[optind+1], "w");
Packit Service 2594b8
    if (out == NULL)
Packit Service 2594b8
	return 2;
Packit Service 2594b8
    in = TIFFOpen(argv[optind], "r");
Packit Service 2594b8
    if( in == NULL )
Packit Service 2594b8
        return 2;
Packit Service 2594b8
Packit Service 2594b8
    thumbnail = (uint8*) _TIFFmalloc(tnw * tnh);
Packit Service 2594b8
    if (!thumbnail) {
Packit Service 2594b8
	    TIFFError(TIFFFileName(in),
Packit Service 2594b8
		      "Can't allocate space for thumbnail buffer.");
Packit Service 2594b8
	    return 1;
Packit Service 2594b8
    }
Packit Service 2594b8
Packit Service 2594b8
    if (in != NULL) {
Packit Service 2594b8
	initScale();
Packit Service 2594b8
	do {
Packit Service 2594b8
	    if (!generateThumbnail(in, out))
Packit Service 2594b8
		goto bad;
Packit Service 2594b8
	    if (!cpIFD(in, out) || !TIFFWriteDirectory(out))
Packit Service 2594b8
		goto bad;
Packit Service 2594b8
	} while (TIFFReadDirectory(in));
Packit Service 2594b8
	(void) TIFFClose(in);
Packit Service 2594b8
    }
Packit Service 2594b8
    (void) TIFFClose(out);
Packit Service 2594b8
    return 0;
Packit Service 2594b8
bad:
Packit Service 2594b8
    (void) TIFFClose(out);
Packit Service 2594b8
    return 1;
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
#define	CopyField(tag, v) \
Packit Service 2594b8
    if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
Packit Service 2594b8
#define	CopyField2(tag, v1, v2) \
Packit Service 2594b8
    if (TIFFGetField(in, tag, &v1, &v2)) TIFFSetField(out, tag, v1, v2)
Packit Service 2594b8
#define	CopyField3(tag, v1, v2, v3) \
Packit Service 2594b8
    if (TIFFGetField(in, tag, &v1, &v2, &v3)) TIFFSetField(out, tag, v1, v2, v3)
Packit Service 2594b8
#define	CopyField4(tag, v1, v2, v3, v4) \
Packit Service 2594b8
    if (TIFFGetField(in, tag, &v1, &v2, &v3, &v4)) TIFFSetField(out, tag, v1, v2, v3, v4)
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
cpTag(TIFF* in, TIFF* out, uint16 tag, uint16 count, TIFFDataType type)
Packit Service 2594b8
{
Packit Service 2594b8
	switch (type) {
Packit Service 2594b8
	case TIFF_SHORT:
Packit Service 2594b8
		if (count == 1) {
Packit Service 2594b8
			uint16 shortv;
Packit Service 2594b8
			CopyField(tag, shortv);
Packit Service 2594b8
		} else if (count == 2) {
Packit Service 2594b8
			uint16 shortv1, shortv2;
Packit Service 2594b8
			CopyField2(tag, shortv1, shortv2);
Packit Service 2594b8
		} else if (count == 4) {
Packit Service 2594b8
			uint16 *tr, *tg, *tb, *ta;
Packit Service 2594b8
			CopyField4(tag, tr, tg, tb, ta);
Packit Service 2594b8
		} else if (count == (uint16) -1) {
Packit Service 2594b8
			uint16 shortv1;
Packit Service 2594b8
			uint16* shortav;
Packit Service 2594b8
			CopyField2(tag, shortv1, shortav);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;
Packit Service 2594b8
	case TIFF_LONG:
Packit Service 2594b8
		{ uint32 longv;
Packit Service 2594b8
		  CopyField(tag, longv);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;
Packit Service 2594b8
	case TIFF_LONG8:
Packit Service 2594b8
		{ uint64 longv8;
Packit Service 2594b8
		  CopyField(tag, longv8);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;
Packit Service 2594b8
	case TIFF_SLONG8:
Packit Service 2594b8
		{ int64 longv8;
Packit Service 2594b8
		  CopyField(tag, longv8);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;
Packit Service 2594b8
	case TIFF_RATIONAL:
Packit Service 2594b8
		if (count == 1) {
Packit Service 2594b8
			float floatv;
Packit Service 2594b8
			CopyField(tag, floatv);
Packit Service 2594b8
		} else if (count == (uint16) -1) {
Packit Service 2594b8
			float* floatav;
Packit Service 2594b8
			CopyField(tag, floatav);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;
Packit Service 2594b8
	case TIFF_ASCII:
Packit Service 2594b8
		{ char* stringv;
Packit Service 2594b8
		  CopyField(tag, stringv);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;
Packit Service 2594b8
	case TIFF_DOUBLE:
Packit Service 2594b8
		if (count == 1) {
Packit Service 2594b8
			double doublev;
Packit Service 2594b8
			CopyField(tag, doublev);
Packit Service 2594b8
		} else if (count == (uint16) -1) {
Packit Service 2594b8
			double* doubleav;
Packit Service 2594b8
			CopyField(tag, doubleav);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;
Packit Service 2594b8
	case TIFF_IFD8:
Packit Service 2594b8
		{ toff_t ifd8;
Packit Service 2594b8
		  CopyField(tag, ifd8);
Packit Service 2594b8
		}
Packit Service 2594b8
		break;          default:
Packit Service 2594b8
                TIFFError(TIFFFileName(in),
Packit Service 2594b8
                          "Data type %d is not supported, tag %d skipped.",
Packit Service 2594b8
                          tag, type);
Packit Service 2594b8
	}
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
#undef CopyField4
Packit Service 2594b8
#undef CopyField3
Packit Service 2594b8
#undef CopyField2
Packit Service 2594b8
#undef CopyField
Packit Service 2594b8
Packit Service 2594b8
static struct cpTag {
Packit Service 2594b8
    uint16	tag;
Packit Service 2594b8
    uint16	count;
Packit Service 2594b8
    TIFFDataType type;
Packit Service 2594b8
} tags[] = {
Packit Service 2594b8
    { TIFFTAG_IMAGEWIDTH,		1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_IMAGELENGTH,		1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_BITSPERSAMPLE,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_COMPRESSION,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_FILLORDER,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_SAMPLESPERPIXEL,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_ROWSPERSTRIP,		1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_PLANARCONFIG,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_GROUP3OPTIONS,		1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_SUBFILETYPE,		1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_PHOTOMETRIC,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_THRESHHOLDING,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_DOCUMENTNAME,		1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_IMAGEDESCRIPTION,		1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_MAKE,			1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_MODEL,			1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_ORIENTATION,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_MINSAMPLEVALUE,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_MAXSAMPLEVALUE,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_XRESOLUTION,		1, TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_YRESOLUTION,		1, TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_PAGENAME,			1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_XPOSITION,		1, TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_YPOSITION,		1, TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_GROUP4OPTIONS,		1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_RESOLUTIONUNIT,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_PAGENUMBER,		2, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_SOFTWARE,			1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_DATETIME,			1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_ARTIST,			1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_HOSTCOMPUTER,		1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_WHITEPOINT,		2, TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_PRIMARYCHROMATICITIES,	(uint16) -1,TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_HALFTONEHINTS,		2, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_BADFAXLINES,		1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_CLEANFAXDATA,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_CONSECUTIVEBADFAXLINES,	1, TIFF_LONG },
Packit Service 2594b8
    { TIFFTAG_INKSET,			1, TIFF_SHORT },
Packit Service 2594b8
    /*{ TIFFTAG_INKNAMES,			1, TIFF_ASCII },*/ /* Needs much more complicated logic. See tiffcp */
Packit Service 2594b8
    { TIFFTAG_DOTRANGE,			2, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_TARGETPRINTER,		1, TIFF_ASCII },
Packit Service 2594b8
    { TIFFTAG_SAMPLEFORMAT,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_YCBCRCOEFFICIENTS,	(uint16) -1,TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_YCBCRSUBSAMPLING,		2, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_YCBCRPOSITIONING,		1, TIFF_SHORT },
Packit Service 2594b8
    { TIFFTAG_REFERENCEBLACKWHITE,	(uint16) -1,TIFF_RATIONAL },
Packit Service 2594b8
    { TIFFTAG_EXTRASAMPLES,		(uint16) -1, TIFF_SHORT },
Packit Service 2594b8
};
Packit Service 2594b8
#define	NTAGS	(sizeof (tags) / sizeof (tags[0]))
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
cpTags(TIFF* in, TIFF* out)
Packit Service 2594b8
{
Packit Service 2594b8
    struct cpTag *p;
Packit Service 2594b8
    for (p = tags; p < &tags[NTAGS]; p++)
Packit Service 2594b8
	{
Packit Service 2594b8
		/* Horrible: but TIFFGetField() expects 2 arguments to be passed */
Packit Service 2594b8
		/* if we request a tag that is defined in a codec, but that codec */
Packit Service 2594b8
		/* isn't used */
Packit Service 2594b8
		if( p->tag == TIFFTAG_GROUP3OPTIONS )
Packit Service 2594b8
		{
Packit Service 2594b8
			uint16 compression;
Packit Service 2594b8
			if( !TIFFGetField(in, TIFFTAG_COMPRESSION, &compression) ||
Packit Service 2594b8
				compression != COMPRESSION_CCITTFAX3 )
Packit Service 2594b8
				continue;
Packit Service 2594b8
		}
Packit Service 2594b8
		if( p->tag == TIFFTAG_GROUP4OPTIONS )
Packit Service 2594b8
		{
Packit Service 2594b8
			uint16 compression;
Packit Service 2594b8
			if( !TIFFGetField(in, TIFFTAG_COMPRESSION, &compression) ||
Packit Service 2594b8
				compression != COMPRESSION_CCITTFAX4 )
Packit Service 2594b8
				continue;
Packit Service 2594b8
		}
Packit Service 2594b8
		cpTag(in, out, p->tag, p->count, p->type);
Packit Service 2594b8
	}
Packit Service 2594b8
}
Packit Service 2594b8
#undef NTAGS
Packit Service 2594b8
Packit Service 2594b8
static int
Packit Service 2594b8
cpStrips(TIFF* in, TIFF* out)
Packit Service 2594b8
{
Packit Service 2594b8
    tsize_t bufsize  = TIFFStripSize(in);
Packit Service 2594b8
    unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
Packit Service 2594b8
Packit Service 2594b8
    if (buf) {
Packit Service 2594b8
	tstrip_t s, ns = TIFFNumberOfStrips(in);
Packit Service 2594b8
	uint64 *bytecounts;
Packit Service 2594b8
Packit Service 2594b8
	TIFFGetField(in, TIFFTAG_STRIPBYTECOUNTS, &bytecounts);
Packit Service 2594b8
	for (s = 0; s < ns; s++) {
Packit Service 2594b8
	  if (bytecounts[s] > (uint64) bufsize) {
Packit Service 2594b8
		buf = (unsigned char *)_TIFFrealloc(buf, (tmsize_t)bytecounts[s]);
Packit Service 2594b8
		if (!buf)
Packit Service 2594b8
		    goto bad;
Packit Service 2594b8
		bufsize = (tmsize_t)bytecounts[s];
Packit Service 2594b8
	    }
Packit Service 2594b8
	    if (TIFFReadRawStrip(in, s, buf, (tmsize_t)bytecounts[s]) < 0 ||
Packit Service 2594b8
		TIFFWriteRawStrip(out, s, buf, (tmsize_t)bytecounts[s]) < 0) {
Packit Service 2594b8
		_TIFFfree(buf);
Packit Service 2594b8
		return 0;
Packit Service 2594b8
	    }
Packit Service 2594b8
	}
Packit Service 2594b8
	_TIFFfree(buf);
Packit Service 2594b8
	return 1;
Packit Service 2594b8
    }
Packit Service 2594b8
Packit Service 2594b8
bad:
Packit Service 2594b8
	TIFFError(TIFFFileName(in),
Packit Service 2594b8
		  "Can't allocate space for strip buffer.");
Packit Service 2594b8
	return 0;
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static int
Packit Service 2594b8
cpTiles(TIFF* in, TIFF* out)
Packit Service 2594b8
{
Packit Service 2594b8
    tsize_t bufsize = TIFFTileSize(in);
Packit Service 2594b8
    unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize);
Packit Service 2594b8
Packit Service 2594b8
    if (buf) {
Packit Service 2594b8
	ttile_t t, nt = TIFFNumberOfTiles(in);
Packit Service 2594b8
	uint64 *bytecounts;
Packit Service 2594b8
Packit Service 2594b8
	TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts);
Packit Service 2594b8
	for (t = 0; t < nt; t++) {
Packit Service 2594b8
	    if (bytecounts[t] > (uint64) bufsize) {
Packit Service 2594b8
		buf = (unsigned char *)_TIFFrealloc(buf, (tmsize_t)bytecounts[t]);
Packit Service 2594b8
		if (!buf)
Packit Service 2594b8
		    goto bad;
Packit Service 2594b8
		bufsize = (tmsize_t)bytecounts[t];
Packit Service 2594b8
	    }
Packit Service 2594b8
	    if (TIFFReadRawTile(in, t, buf, (tmsize_t)bytecounts[t]) < 0 ||
Packit Service 2594b8
		TIFFWriteRawTile(out, t, buf, (tmsize_t)bytecounts[t]) < 0) {
Packit Service 2594b8
		_TIFFfree(buf);
Packit Service 2594b8
		return 0;
Packit Service 2594b8
	    }
Packit Service 2594b8
	}
Packit Service 2594b8
	_TIFFfree(buf);
Packit Service 2594b8
	return 1;
Packit Service 2594b8
    }
Packit Service 2594b8
Packit Service 2594b8
bad:
Packit Service 2594b8
    TIFFError(TIFFFileName(in),
Packit Service 2594b8
		  "Can't allocate space for tile buffer.");
Packit Service 2594b8
	return (0);
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static int
Packit Service 2594b8
cpIFD(TIFF* in, TIFF* out)
Packit Service 2594b8
{
Packit Service 2594b8
    cpTags(in, out);
Packit Service 2594b8
    if (TIFFIsTiled(in)) {
Packit Service 2594b8
	if (!cpTiles(in, out))
Packit Service 2594b8
	    return (0);
Packit Service 2594b8
    } else {
Packit Service 2594b8
	if (!cpStrips(in, out))
Packit Service 2594b8
	    return (0);
Packit Service 2594b8
    }
Packit Service 2594b8
    return (1);
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static	uint16	photometric;		/* current photometric of raster */
Packit Service 2594b8
static	uint16	filterWidth;		/* filter width in pixels */
Packit Service 2594b8
static	uint32	stepSrcWidth;		/* src image stepping width */
Packit Service 2594b8
static	uint32	stepDstWidth;		/* dest stepping width */
Packit Service 2594b8
static	uint8* src0;			/* horizontal bit stepping (start) */
Packit Service 2594b8
static	uint8* src1;			/* horizontal bit stepping (middle) */
Packit Service 2594b8
static	uint8* src2;			/* horizontal bit stepping (end) */
Packit Service 2594b8
static	uint32* rowoff;			/* row offset for stepping */
Packit Service 2594b8
static	uint8 cmap[256];		/* colormap indexes */
Packit Service 2594b8
static	uint8 bits[256];		/* count of bits set */
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
setupBitsTables()
Packit Service 2594b8
{
Packit Service 2594b8
    int i;
Packit Service 2594b8
    for (i = 0; i < 256; i++) {
Packit Service 2594b8
	int n = 0;
Packit Service 2594b8
	if (i&0x01) n++;
Packit Service 2594b8
	if (i&0x02) n++;
Packit Service 2594b8
	if (i&0x04) n++;
Packit Service 2594b8
	if (i&0x08) n++;
Packit Service 2594b8
	if (i&0x10) n++;
Packit Service 2594b8
	if (i&0x20) n++;
Packit Service 2594b8
	if (i&0x40) n++;
Packit Service 2594b8
	if (i&0x80) n++;
Packit Service 2594b8
	bits[i] = n;
Packit Service 2594b8
    }
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static int clamp(float v, int low, int high)
Packit Service 2594b8
    { return (v < low ? low : v > high ? high : (int)v); }
Packit Service 2594b8
Packit Service 2594b8
#ifndef M_E
Packit Service 2594b8
#define M_E		2.7182818284590452354
Packit Service 2594b8
#endif
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
expFill(float pct[], uint32 p, uint32 n)
Packit Service 2594b8
{
Packit Service 2594b8
    uint32 i;
Packit Service 2594b8
    uint32 c = (p * n) / 100;
Packit Service 2594b8
    for (i = 1; i < c; i++)
Packit Service 2594b8
	pct[i] = (float) (1-exp(i/((double)(n-1)))/ M_E);
Packit Service 2594b8
    for (; i < n; i++)
Packit Service 2594b8
	pct[i] = 0.;
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
setupCmap()
Packit Service 2594b8
{
Packit Service 2594b8
    float pct[256];			/* known to be large enough */
Packit Service 2594b8
    uint32 i;
Packit Service 2594b8
    pct[0] = 1;				/* force white */
Packit Service 2594b8
    switch (contrast) {
Packit Service 2594b8
    case EXP50: expFill(pct, 50, 256); break;
Packit Service 2594b8
    case EXP60:	expFill(pct, 60, 256); break;
Packit Service 2594b8
    case EXP70:	expFill(pct, 70, 256); break;
Packit Service 2594b8
    case EXP80:	expFill(pct, 80, 256); break;
Packit Service 2594b8
    case EXP90:	expFill(pct, 90, 256); break;
Packit Service 2594b8
    case EXP:	expFill(pct, 100, 256); break;
Packit Service 2594b8
    case LINEAR:
Packit Service 2594b8
	for (i = 1; i < 256; i++)
Packit Service 2594b8
	    pct[i] = 1-((float)i)/(256-1);
Packit Service 2594b8
	break;
Packit Service 2594b8
    }
Packit Service 2594b8
    switch (photometric) {
Packit Service 2594b8
    case PHOTOMETRIC_MINISWHITE:
Packit Service 2594b8
	for (i = 0; i < 256; i++)
Packit Service 2594b8
	    cmap[i] = clamp(255*pct[(256-1)-i], 0, 255);
Packit Service 2594b8
	break;
Packit Service 2594b8
    case PHOTOMETRIC_MINISBLACK:
Packit Service 2594b8
	for (i = 0; i < 256; i++)
Packit Service 2594b8
	    cmap[i] = clamp(255*pct[i], 0, 255);
Packit Service 2594b8
	break;
Packit Service 2594b8
    }
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
initScale()
Packit Service 2594b8
{
Packit Service 2594b8
    src0 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
Packit Service 2594b8
    src1 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
Packit Service 2594b8
    src2 = (uint8*) _TIFFmalloc(sizeof (uint8) * tnw);
Packit Service 2594b8
    rowoff = (uint32*) _TIFFmalloc(sizeof (uint32) * tnw);
Packit Service 2594b8
    filterWidth = 0;
Packit Service 2594b8
    stepDstWidth = stepSrcWidth = 0;
Packit Service 2594b8
    setupBitsTables();
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
/*
Packit Service 2594b8
 * Calculate the horizontal accumulation parameteres
Packit Service 2594b8
 * according to the widths of the src and dst images.
Packit Service 2594b8
 */
Packit Service 2594b8
static void
Packit Service 2594b8
setupStepTables(uint32 sw)
Packit Service 2594b8
{
Packit Service 2594b8
    if (stepSrcWidth != sw || stepDstWidth != tnw) {
Packit Service 2594b8
	int step = sw;
Packit Service 2594b8
	int limit = tnw;
Packit Service 2594b8
	int err = 0;
Packit Service 2594b8
	uint32 sx = 0;
Packit Service 2594b8
	uint32 x;
Packit Service 2594b8
	int fw;
Packit Service 2594b8
	uint8 b;
Packit Service 2594b8
	for (x = 0; x < tnw; x++) {
Packit Service 2594b8
	    uint32 sx0 = sx;
Packit Service 2594b8
	    err += step;
Packit Service 2594b8
	    while (err >= limit) {
Packit Service 2594b8
		err -= limit;
Packit Service 2594b8
		sx++;
Packit Service 2594b8
	    }
Packit Service 2594b8
	    rowoff[x] = sx0 >> 3;
Packit Service 2594b8
	    fw = sx - sx0;		/* width */
Packit Service 2594b8
	    b = (fw < 8) ? 0xff<<(8-fw) : 0xff;
Packit Service 2594b8
	    src0[x] = b >> (sx0&7;;
Packit Service 2594b8
	    fw -= 8 - (sx0&7;;
Packit Service 2594b8
	    if (fw < 0)
Packit Service 2594b8
		fw = 0;
Packit Service 2594b8
	    src1[x] = fw >> 3;
Packit Service 2594b8
	    fw -= (fw>>3)<<3;
Packit Service 2594b8
	    src2[x] = 0xff << (8-fw);
Packit Service 2594b8
	}
Packit Service 2594b8
	stepSrcWidth = sw;
Packit Service 2594b8
	stepDstWidth = tnw;
Packit Service 2594b8
    }
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
setrow(uint8* row, uint32 nrows, const uint8* rows[])
Packit Service 2594b8
{
Packit Service 2594b8
    uint32 x;
Packit Service 2594b8
    uint32 area = nrows * filterWidth;
Packit Service 2594b8
    for (x = 0; x < tnw; x++) {
Packit Service 2594b8
	uint32 mask0 = src0[x];
Packit Service 2594b8
	uint32 fw = src1[x];
Packit Service 2594b8
	uint32 mask1 = src1[x];
Packit Service 2594b8
	uint32 off = rowoff[x];
Packit Service 2594b8
	uint32 acc = 0;
Packit Service 2594b8
	uint32 y, i;
Packit Service 2594b8
	for (y = 0; y < nrows; y++) {
Packit Service 2594b8
	    const uint8* src = rows[y] + off;
Packit Service 2594b8
	    acc += bits[*src++ & mask0];
Packit Service 2594b8
	    switch (fw) {
Packit Service 2594b8
	    default:
Packit Service 2594b8
		for (i = fw; i > 8; i--)
Packit Service 2594b8
		    acc += bits[*src++];
Packit Service 2594b8
		/* fall thru... */
Packit Service 2594b8
	    case 8: acc += bits[*src++];
Packit Service 2594b8
	    case 7: acc += bits[*src++];
Packit Service 2594b8
	    case 6: acc += bits[*src++];
Packit Service 2594b8
	    case 5: acc += bits[*src++];
Packit Service 2594b8
	    case 4: acc += bits[*src++];
Packit Service 2594b8
	    case 3: acc += bits[*src++];
Packit Service 2594b8
	    case 2: acc += bits[*src++];
Packit Service 2594b8
	    case 1: acc += bits[*src++];
Packit Service 2594b8
	    case 0: break;
Packit Service 2594b8
	    }
Packit Service 2594b8
	    acc += bits[*src & mask1];
Packit Service 2594b8
	}
Packit Service 2594b8
	*row++ = cmap[(255*acc)/area];
Packit Service 2594b8
    }
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
/*
Packit Service 2594b8
 * Install the specified image.  The
Packit Service 2594b8
 * image is resized to fit the display page using
Packit Service 2594b8
 * a box filter.  The resultant pixels are mapped
Packit Service 2594b8
 * with a user-selectable contrast curve.
Packit Service 2594b8
 */
Packit Service 2594b8
static void
Packit Service 2594b8
setImage1(const uint8* br, uint32 rw, uint32 rh)
Packit Service 2594b8
{
Packit Service 2594b8
    int step = rh;
Packit Service 2594b8
    int limit = tnh;
Packit Service 2594b8
    int err = 0;
Packit Service 2594b8
    int bpr = TIFFhowmany8(rw);
Packit Service 2594b8
    int sy = 0;
Packit Service 2594b8
    uint8* row = thumbnail;
Packit Service 2594b8
    uint32 dy;
Packit Service 2594b8
    for (dy = 0; dy < tnh; dy++) {
Packit Service 2594b8
	const uint8* rows[256];
Packit Service 2594b8
	uint32 nrows = 1;
Packit Service 2594b8
	fprintf(stderr, "bpr=%d, sy=%d, bpr*sy=%d\n", bpr, sy, bpr*sy);
Packit Service 2594b8
	rows[0] = br + bpr*sy;
Packit Service 2594b8
	err += step;
Packit Service 2594b8
	while (err >= limit) {
Packit Service 2594b8
	    err -= limit;
Packit Service 2594b8
	    sy++;
Packit Service 2594b8
	    if (err >= limit)
Packit Service 2594b8
		{
Packit Service 2594b8
			/* We should perhaps error loudly, but I can't make sense of that */
Packit Service 2594b8
			/* code... */
Packit Service 2594b8
			if( nrows == 256 )
Packit Service 2594b8
				break;
Packit Service 2594b8
			rows[nrows++] = br + bpr*sy;
Packit Service 2594b8
		}
Packit Service 2594b8
	}
Packit Service 2594b8
	setrow(row, nrows, rows);
Packit Service 2594b8
	row += tnw;
Packit Service 2594b8
    }
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
setImage(const uint8* br, uint32 rw, uint32 rh)
Packit Service 2594b8
{
Packit Service 2594b8
    filterWidth = (uint16) ceil((double) rw / (double) tnw);
Packit Service 2594b8
    setupStepTables(rw);
Packit Service 2594b8
    setImage1(br, rw, rh);
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
static int
Packit Service 2594b8
generateThumbnail(TIFF* in, TIFF* out)
Packit Service 2594b8
{
Packit Service 2594b8
    unsigned char* raster;
Packit Service 2594b8
    unsigned char* rp;
Packit Service 2594b8
    uint32 sw, sh, rps;
Packit Service 2594b8
    uint16 bps, spp;
Packit Service 2594b8
    tsize_t rowsize, rastersize;
Packit Service 2594b8
    tstrip_t s, ns = TIFFNumberOfStrips(in);
Packit Service 2594b8
    toff_t diroff[1];
Packit Service 2594b8
Packit Service 2594b8
    TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &sw);
Packit Service 2594b8
    TIFFGetField(in, TIFFTAG_IMAGELENGTH, &sh);
Packit Service 2594b8
    TIFFGetFieldDefaulted(in, TIFFTAG_BITSPERSAMPLE, &bps;;
Packit Service 2594b8
    TIFFGetFieldDefaulted(in, TIFFTAG_SAMPLESPERPIXEL, &spp;;
Packit Service 2594b8
    TIFFGetFieldDefaulted(in, TIFFTAG_ROWSPERSTRIP, &rps;;
Packit Service 2594b8
    if (spp != 1 || bps != 1)
Packit Service 2594b8
	return 0;
Packit Service 2594b8
    rowsize = TIFFScanlineSize(in);
Packit Service 2594b8
    rastersize = sh * rowsize;
Packit Service 2594b8
    fprintf(stderr, "rastersize=%u\n", (unsigned int)rastersize);
Packit Service 2594b8
	/* +3 : add a few guard bytes since setrow() can read a bit */
Packit Service 2594b8
	/* outside buffer */
Packit Service 2594b8
    raster = (unsigned char*)_TIFFmalloc(rastersize+3);
Packit Service 2594b8
    if (!raster) {
Packit Service 2594b8
	    TIFFError(TIFFFileName(in),
Packit Service 2594b8
		      "Can't allocate space for raster buffer.");
Packit Service 2594b8
	    return 0;
Packit Service 2594b8
    }
Packit Service 2594b8
    raster[rastersize] = 0;
Packit Service 2594b8
    raster[rastersize+1] = 0;
Packit Service 2594b8
    raster[rastersize+2] = 0;
Packit Service 2594b8
    rp = raster;
Packit Service 2594b8
    for (s = 0; s < ns; s++) {
Packit Service 2594b8
	(void) TIFFReadEncodedStrip(in, s, rp, -1);
Packit Service 2594b8
	rp += rps * rowsize;
Packit Service 2594b8
    }
Packit Service 2594b8
    TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric);
Packit Service 2594b8
    setupCmap();
Packit Service 2594b8
    setImage(raster, sw, sh);
Packit Service 2594b8
    _TIFFfree(raster);
Packit Service 2594b8
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (uint32) tnw);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_IMAGELENGTH, (uint32) tnh);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (uint16) 8);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (uint16) 1);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
Packit Service 2594b8
    cpTag(in, out, TIFFTAG_SOFTWARE,		(uint16) -1, TIFF_ASCII);
Packit Service 2594b8
    cpTag(in, out, TIFFTAG_IMAGEDESCRIPTION,	(uint16) -1, TIFF_ASCII);
Packit Service 2594b8
    cpTag(in, out, TIFFTAG_DATETIME,		(uint16) -1, TIFF_ASCII);
Packit Service 2594b8
    cpTag(in, out, TIFFTAG_HOSTCOMPUTER,	(uint16) -1, TIFF_ASCII);
Packit Service 2594b8
    diroff[0] = 0UL;
Packit Service 2594b8
    TIFFSetField(out, TIFFTAG_SUBIFD, 1, diroff);
Packit Service 2594b8
    return (TIFFWriteEncodedStrip(out, 0, thumbnail, tnw*tnh) != -1 &&
Packit Service 2594b8
            TIFFWriteDirectory(out) != -1);
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
char* stuff[] = {
Packit Service 2594b8
"usage: thumbnail [options] input.tif output.tif",
Packit Service 2594b8
"where options are:",
Packit Service 2594b8
" -h #		specify thumbnail image height (default is 274)",
Packit Service 2594b8
" -w #		specify thumbnail image width (default is 216)",
Packit Service 2594b8
"",
Packit Service 2594b8
" -c linear	use linear contrast curve",
Packit Service 2594b8
" -c exp50	use 50% exponential contrast curve",
Packit Service 2594b8
" -c exp60	use 60% exponential contrast curve",
Packit Service 2594b8
" -c exp70	use 70% exponential contrast curve",
Packit Service 2594b8
" -c exp80	use 80% exponential contrast curve",
Packit Service 2594b8
" -c exp90	use 90% exponential contrast curve",
Packit Service 2594b8
" -c exp		use pure exponential contrast curve",
Packit Service 2594b8
NULL
Packit Service 2594b8
};
Packit Service 2594b8
Packit Service 2594b8
static void
Packit Service 2594b8
usage(void)
Packit Service 2594b8
{
Packit Service 2594b8
	char buf[BUFSIZ];
Packit Service 2594b8
	int i;
Packit Service 2594b8
Packit Service 2594b8
	setbuf(stderr, buf);
Packit Service 2594b8
        fprintf(stderr, "%s\n\n", TIFFGetVersion());
Packit Service 2594b8
	for (i = 0; stuff[i] != NULL; i++)
Packit Service 2594b8
		fprintf(stderr, "%s\n", stuff[i]);
Packit Service 2594b8
	exit(-1);
Packit Service 2594b8
}
Packit Service 2594b8
Packit Service 2594b8
/* vim: set ts=8 sts=8 sw=8 noet: */
Packit Service 2594b8
/*
Packit Service 2594b8
 * Local Variables:
Packit Service 2594b8
 * mode: c
Packit Service 2594b8
 * c-basic-offset: 8
Packit Service 2594b8
 * fill-column: 78
Packit Service 2594b8
 * End:
Packit Service 2594b8
 */