⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tiffmedian.c

📁 tiff文件开发库
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Header: /cvsroot/osrs/libtiff/tools/tiffmedian.c,v 1.5 2003/08/21 10:00:06 dron Exp $ *//* * Apply median cut on an image. * * tiffmedian [-c n] [-f] input output *     -C n		- set colortable size.  Default is 256. *     -f		- use Floyd-Steinberg dithering. *     -c lzw		- compress output with LZW  *                        (no longer supported by default due to unisys patent enforcement)  *     -c none		- use no compression on output *     -c packbits	- use packbits compression on output *     -r n		- create output with n rows/strip of data * (by default the compression scheme and rows/strip are taken *  from the input file) * * Notes: * * [1] Floyd-Steinberg dither: *  I should point out that the actual fractions we used were, assuming *  you are at X, moving left to right: * *		    X     7/16 *	     3/16   5/16  1/16     * *  Note that the error goes to four neighbors, not three.  I think this *  will probably do better (at least for black and white) than the *  3/8-3/8-1/4 distribution, at the cost of greater processing.  I have *  seen the 3/8-3/8-1/4 distribution described as "our" algorithm before, *  but I have no idea who the credit really belongs to. *  Also, I should add that if you do zig-zag scanning (see my immediately *  previous message), it is sufficient (but not quite as good) to send *  half the error one pixel ahead (e.g. to the right on lines you scan *  left to right), and half one pixel straight down.  Again, this is for *  black and white;  I've not tried it with color. *  --  *					    Lou Steinberg * * [2] Color Image Quantization for Frame Buffer Display, Paul Heckbert, *	Siggraph '82 proceedings, pp. 297-307 */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "tiffio.h"#define	MAX_CMAP_SIZE	256#define	streq(a,b)	(strcmp(a,b) == 0)#define	strneq(a,b,n)	(strncmp(a,b,n) == 0)#define	COLOR_DEPTH	8#define	MAX_COLOR	256#define	B_DEPTH		5		/* # bits/pixel to use */#define	B_LEN		(1L<<B_DEPTH)#define	C_DEPTH		2#define	C_LEN		(1L<<C_DEPTH)	/* # cells/color to use */#define	COLOR_SHIFT	(COLOR_DEPTH-B_DEPTH)typedef	struct colorbox {	struct	colorbox *next, *prev;	int	rmin, rmax;	int	gmin, gmax;	int	bmin, bmax;	uint32	total;} Colorbox;typedef struct {	int	num_ents;	int	entries[MAX_CMAP_SIZE][2];} C_cell;uint16	rm[MAX_CMAP_SIZE], gm[MAX_CMAP_SIZE], bm[MAX_CMAP_SIZE];int	num_colors;uint32	histogram[B_LEN][B_LEN][B_LEN];Colorbox *freeboxes;Colorbox *usedboxes;C_cell	**ColorCells;TIFF	*in, *out;uint32	rowsperstrip = (uint32) -1;uint16	compression = (uint16) -1;uint16	bitspersample = 1;uint16	samplesperpixel;uint32	imagewidth;uint32	imagelength;uint16	predictor = 0;static	void get_histogram(TIFF*, Colorbox*);static	void splitbox(Colorbox*);static	void shrinkbox(Colorbox*);static	void map_colortable(void);static	void quant(TIFF*, TIFF*);static	void quant_fsdither(TIFF*, TIFF*);static	Colorbox* largest_box(void);static	void usage(void);static	int processCompressOptions(char*);#define	CopyField(tag, v) \	if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)intmain(int argc, char* argv[]){	int i, dither = 0;	uint16 shortv, config, photometric;	Colorbox *box_list, *ptr;	float floatv;	uint32 longv;	int c;	extern int optind;	extern char* optarg;	num_colors = MAX_CMAP_SIZE;	while ((c = getopt(argc, argv, "c:C:r:f")) != -1)		switch (c) {		case 'c':		/* compression scheme */			if (!processCompressOptions(optarg))				usage();			break;		case 'C':		/* set colormap size */			num_colors = atoi(optarg);			if (num_colors > MAX_CMAP_SIZE) {				fprintf(stderr,				   "-c: colormap too big, max %d\n",				   MAX_CMAP_SIZE);				usage();			}			break;		case 'f':		/* dither */			dither = 1;			break;		case 'r':		/* rows/strip */			rowsperstrip = atoi(optarg);			break;		case '?':			usage();			/*NOTREACHED*/		}	if (argc - optind != 2)		usage();	in = TIFFOpen(argv[optind], "r");	if (in == NULL)		return (-1);	TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);	TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);	TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);	TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);	if (bitspersample != 8 && bitspersample != 16) {		fprintf(stderr, "%s: Image must have at least 8-bits/sample\n",		    argv[optind]);		return (-3);	}	if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) ||	    photometric != PHOTOMETRIC_RGB || samplesperpixel < 3) {		fprintf(stderr, "%s: Image must have RGB data\n", argv[optind]);		return (-4);	}	TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);	if (config != PLANARCONFIG_CONTIG) {		fprintf(stderr, "%s: Can only handle contiguous data packing\n",		    argv[optind]);		return (-5);	}	/*	 * STEP 1:  create empty boxes	 */	usedboxes = NULL;	box_list = freeboxes = (Colorbox *)_TIFFmalloc(num_colors*sizeof (Colorbox));	freeboxes[0].next = &freeboxes[1];	freeboxes[0].prev = NULL;	for (i = 1; i < num_colors-1; ++i) {		freeboxes[i].next = &freeboxes[i+1];		freeboxes[i].prev = &freeboxes[i-1];	}	freeboxes[num_colors-1].next = NULL;	freeboxes[num_colors-1].prev = &freeboxes[num_colors-2];	/*	 * STEP 2: get histogram, initialize first box	 */	ptr = freeboxes;	freeboxes = ptr->next;	if (freeboxes)		freeboxes->prev = NULL;	ptr->next = usedboxes;	usedboxes = ptr;	if (ptr->next)		ptr->next->prev = ptr;	get_histogram(in, ptr);	/*	 * STEP 3: continually subdivide boxes until no more free	 * boxes remain or until all colors assigned.	 */	while (freeboxes != NULL) {		ptr = largest_box();		if (ptr != NULL)			splitbox(ptr);		else			freeboxes = NULL;	}	/*	 * STEP 4: assign colors to all boxes	 */	for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next) {		rm[i] = ((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2;		gm[i] = ((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2;		bm[i] = ((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2;	}	/* We're done with the boxes now */	_TIFFfree(box_list);	freeboxes = usedboxes = NULL;	/*	 * STEP 5: scan histogram and map all values to closest color	 */	/* 5a: create cell list as described in Heckbert[2] */	ColorCells = (C_cell **)_TIFFmalloc(C_LEN*C_LEN*C_LEN*sizeof (C_cell*));	_TIFFmemset(ColorCells, 0, C_LEN*C_LEN*C_LEN*sizeof (C_cell*));	/* 5b: create mapping from truncated pixel space to color	   table entries */	map_colortable();	/*	 * STEP 6: scan image, match input values to table entries	 */	out = TIFFOpen(argv[optind+1], "w");	if (out == NULL)		return (-2);	CopyField(TIFFTAG_SUBFILETYPE, longv);	CopyField(TIFFTAG_IMAGEWIDTH, longv);	TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (short)COLOR_DEPTH);	if (compression != (uint16)-1) {		TIFFSetField(out, TIFFTAG_COMPRESSION, compression);		switch (compression) {		case COMPRESSION_LZW:		case COMPRESSION_DEFLATE:			if (predictor != 0)				TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);			break;		}	} else		CopyField(TIFFTAG_COMPRESSION, compression);	TIFFSetField(out, TIFFTAG_PHOTOMETRIC, (short)PHOTOMETRIC_PALETTE);	CopyField(TIFFTAG_ORIENTATION, shortv);	TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (short)1);	CopyField(TIFFTAG_PLANARCONFIG, shortv);	TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,	    TIFFDefaultStripSize(out, rowsperstrip));	CopyField(TIFFTAG_MINSAMPLEVALUE, shortv);	CopyField(TIFFTAG_MAXSAMPLEVALUE, shortv);	CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);	CopyField(TIFFTAG_XRESOLUTION, floatv);	CopyField(TIFFTAG_YRESOLUTION, floatv);	CopyField(TIFFTAG_XPOSITION, floatv);	CopyField(TIFFTAG_YPOSITION, floatv);	if (dither)		quant_fsdither(in, out);	else		quant(in, out);	/*	 * Scale colormap to TIFF-required 16-bit values.	 */#define	SCALE(x)	(((x)*((1L<<16)-1))/255)	for (i = 0; i < MAX_CMAP_SIZE; ++i) {		rm[i] = SCALE(rm[i]);		gm[i] = SCALE(gm[i]);		bm[i] = SCALE(bm[i]);	}	TIFFSetField(out, TIFFTAG_COLORMAP, rm, gm, bm);	(void) TIFFClose(out);	return (0);}static intprocessCompressOptions(char* opt){	if (streq(opt, "none"))		compression = COMPRESSION_NONE;	else if (streq(opt, "packbits"))		compression = COMPRESSION_PACKBITS;	else if (strneq(opt, "lzw", 3)) {		char* cp = strchr(opt, ':');		if (cp)			predictor = atoi(cp+1);		compression = COMPRESSION_LZW;	} else if (strneq(opt, "zip", 3)) {		char* cp = strchr(opt, ':');		if (cp)			predictor = atoi(cp+1);		compression = COMPRESSION_DEFLATE;	} else		return (0);	return (1);}char* stuff[] = {"usage: tiffmedian [options] input.tif output.tif","where options are:"," -r #		make each strip have no more than # rows"," -C #		create a colormap with # entries"," -f		use Floyd-Steinberg dithering"," -c lzw[:opts]	compress output with Lempel-Ziv & Welch encoding","               (no longer supported by default due to Unisys patent enforcement)", " -c zip[:opts]	compress output with deflate encoding"," -c packbits	compress output with packbits encoding"," -c none	use no compression algorithm on output","","LZW and deflate options:"," #		set predictor value","For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",NULL};static voidusage(void){	char buf[BUFSIZ];	int i;	setbuf(stderr, buf);        fprintf(stderr, "%s\n\n", TIFFGetVersion());	for (i = 0; stuff[i] != NULL; i++)		fprintf(stderr, "%s\n", stuff[i]);	exit(-1);}static voidget_histogram(TIFF* in, Colorbox* box){	register unsigned char *inptr;	register int red, green, blue;	register uint32 j, i;	unsigned char *inputline;	inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));	if (inputline == NULL) {		fprintf(stderr, "No space for scanline buffer\n");		exit(-1);	}	box->rmin = box->gmin = box->bmin = 999;	box->rmax = box->gmax = box->bmax = -1;	box->total = imagewidth * imagelength;	{ register uint32 *ptr = &histogram[0][0][0];	  for (i = B_LEN*B_LEN*B_LEN; i-- > 0;)		*ptr++ = 0;	}	for (i = 0; i < imagelength; i++) {		if (TIFFReadScanline(in, inputline, i, 0) <= 0)			break;		inptr = inputline;		for (j = imagewidth; j-- > 0;) {			red = *inptr++ >> COLOR_SHIFT;			green = *inptr++ >> COLOR_SHIFT;			blue = *inptr++ >> COLOR_SHIFT;			if (red < box->rmin)				box->rmin = red;		        if (red > box->rmax)				box->rmax = red;		        if (green < box->gmin)				box->gmin = green;		        if (green > box->gmax)				box->gmax = green;		        if (blue < box->bmin)				box->bmin = blue;		        if (blue > box->bmax)				box->bmax = blue;		        histogram[red][green][blue]++;		}	}	_TIFFfree(inputline);}static Colorbox *largest_box(void){	register Colorbox *p, *b;	register uint32 size;	b = NULL;	size = 0;	for (p = usedboxes; p != NULL; p = p->next)		if ((p->rmax > p->rmin || p->gmax > p->gmin ||		    p->bmax > p->bmin) &&  p->total > size)		        size = (b = p)->total;	return (b);}static voidsplitbox(Colorbox* ptr){	uint32		hist2[B_LEN];	int		first, last;	register Colorbox	*new;	register uint32	*iptr, *histp;	register int	i, j;	register int	ir,ig,ib;	register uint32 sum, sum1, sum2;	enum { RED, GREEN, BLUE } axis;	/*	 * See which axis is the largest, do a histogram along that	 * axis.  Split at median point.  Contract both new boxes to	 * fit points and return	 */	i = ptr->rmax - ptr->rmin;	if (i >= ptr->gmax - ptr->gmin && i >= ptr->bmax - ptr->bmin)		axis = RED;	else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)		axis = GREEN;	else		axis = BLUE;	/* get histogram along longest axis */	switch (axis) {	case RED:		histp = &hist2[ptr->rmin];	        for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {			*histp = 0;			for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {				iptr = &histogram[ir][ig][ptr->bmin];				for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)					*histp += *iptr++;			}			histp++;	        }	        first = ptr->rmin;		last = ptr->rmax;	        break;	case GREEN:	        histp = &hist2[ptr->gmin];	        for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {			*histp = 0;			for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -