Blame tools/thumbnail.c

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