ftp.nice.ch/pub/next/unix/graphics/tiffres.NIHS.bs.tar.gz#/tiffres.NIHS.bs/tiffres.c

This is tiffres.c in view mode; [Download] [Up]

/*	TIFFRES	-- Tiff Resolution utility
**				(c) Peter Langston <psl@acm.org> 2/95
** Version 1.2 6/15/95
**
**   I wrote this simple utility in frustration over the number of programs
** that either produce tiff files with no X and Y resolutions or that
** invert the specified resolutions (e.g. Icon, Pixelist ... oh, hi Keith). 
**
** No special libraries are needed for compilation.  I use:
**	Compile: cc -O -Wall -s -object tiffres.c -o tiffres
**
******************** Legal Gobbledegook *************************************
**   This program is freeware - you are free to use it for your own personal,
** non-commercial enjoyment.  For any other use (including transfer to other
** users), you must obtain my explicit permission.  This program is entirely
** free of any warranty or guarantee as to its appropriateness for any use.
**   Notwithstanding any implications from its status as freeware, this
** program is still mine (mine, all mine!) and I reserve all rights granted
** to me by my copyright on it.
**		Peter Langston <psl@acm.org> Seattle, WA  3 June, 1995
******************** E-O-L-G ************************************************
*/
#include	<libc.h>

#define	TIFFMAGIC	42
#define	TAG_XRES	282
#define	TAG_YRES	283
#define	TYPE_BYTE	1
#define	TYPE_ASCII	2
#define	TYPE_SHORT	3
#define	TYPE_LONG	4
#define	TYPE_RATIONAL	5

#define	SET_VAL	1
#define	GET_VAL	2

int	BigEnd;			/* 0 => little-endian */
int	Xmode, Ymode;		/* what we're doing... */
int	Vflg;			/* verbosity */
double	Xval, Yval;		/* new values */

int	tiffres(FILE *ifp, char *name);
void	getfield(char *name, char *ifde, FILE *ifp);
void	setfield(double val, char *ifde, FILE *ifp);
int	char2short(char *cp);
int	char2long(char *cp);
void	long2char(int l, char *cp);

void
syntax(char *prog)
{
	fprintf(stderr,
	 "Usage: %s [-r[=#]] [-v] [-x[=#]] [-y[=#]] tiff-file [...]\n", prog);
	fprintf(stderr, "-r\tprints the current x & y resolutions.\n");
	fprintf(stderr, "-r=400\tsets the x & y resolutions to 400 dpi.\n");
	fprintf(stderr, "-v\tincreases verbosity.\n");
	fprintf(stderr, "-x\tprints the current x resolution.\n");
	fprintf(stderr, "-y\tprints the current y resolution.\n");
	fprintf(stderr, "-x=12.3\tsets the x resolution to 12.3 dpi.\n");
	fprintf(stderr, "-y=300\tsets the y resolution to 300 dpi.\n");
	fprintf(stderr, "The exit status is a count of errors.\n");
	exit(2);
}

void
main(int argc, char *argv[])
{
	int i, f, retval = 0;
	FILE *ifp;

	Vflg = Xmode = Ymode = f = 0;
	for (i = 1; i < argc; i++) {
	    if (argv[i][0] == '-') {
		switch (argv[i][1]) {
		case 'r':			/* set/get X & Y resolutions */
		    if (argv[i][2] == '=') {
			Xval = Yval = atof(&argv[i][3]);
			Xmode |= SET_VAL;
			Ymode |= SET_VAL;
		    } else {
			Xmode |= GET_VAL;
			Ymode |= GET_VAL;
		    }
		    break;
		case 'v':			/* increment verbosity */
		    Vflg++;
		    break;
		case 'x':			/* set/get X resolution */
		    if (argv[i][2] == '=') {
			Xval = atof(&argv[i][3]);
			Xmode |= SET_VAL;
		    } else
			Xmode |= GET_VAL;
		    break;
		case 'y':			/* set/get Y resolution */
		    if (argv[i][2] == '=') {
			Yval = atof(&argv[i][3]);
			Ymode |= SET_VAL;
		    } else
			Ymode |= GET_VAL;
		    break;
		default:
		    syntax(argv[0]);
		}
	    } else {
		f++;
		ifp = fopen(argv[i], ((Xmode | Ymode) & SET_VAL)? "r+" : "r");
		if (!ifp) {
		    perror(argv[i]);
		    retval++;
		} else
		    retval += tiffres(ifp, argv[i]);
	    }
	}
	if (!f || (!Xmode && !Ymode))
	    syntax(argv[0]);
	exit(retval);
}

int
tiffres(FILE *ifp, char *name)
{
	char buf[12];
	int i, nument, ent;
	long offset;

	fseek(ifp, 0, 0);
	fread(buf, 1, 8, ifp);
	if (buf[0] == 'I' && buf[1] == 'I')
	    BigEnd = 0;
	else if (buf[0] == 'M' && buf[1] == 'M')
	    BigEnd = 1;
	else {
	    fprintf(stderr, "Error in %s: First 2 bytes bad.\n", name);
	    return(1); 
	}
	i = char2short(&buf[2]);
	if (i != TIFFMAGIC) {
	    fprintf(stderr, "Error in %s: Second 2 bytes not magic (%d).\n",
	     name, TIFFMAGIC);
	    return(1); 
	}
	i = char2long(&buf[4]);
	if (fseek(ifp, i, 0)) {
	    fprintf(stderr,
	     "Error in %s: Seek to %d (0x%x) failed\n", name, i, i);
	    return(1); 
	}
	for (;;) {	/* go through the Image File Directory */
	    fread(buf, 1, 2, ifp);
	    nument = char2short(&buf[0]);
	    for (ent = 0; ent < nument; ent++) {
		fread(buf, 1, 12, ifp);
		i = char2short(&buf[0]);
		if (Xmode && i == TAG_XRES) {
		    if (Xmode & GET_VAL)
			getfield("X resolution", buf, ifp);
		    if (Xmode & SET_VAL) {
			setfield(Xval, buf, ifp);
			if (Vflg)
			    getfield("Now X resolution", buf, ifp);
		    }
		}
		if (Ymode && i == TAG_YRES) {
		    if (Ymode & GET_VAL)
			getfield("Y resolution", buf, ifp);
		    if (Ymode & SET_VAL) {
			setfield(Yval, buf, ifp);
			if (Vflg)
			    getfield("Now Y resolution", buf, ifp);
		    }
		}
	    }
	    fread(buf, 1, 4, ifp);
	    offset = char2long(&buf[0]);
	    if (!offset)
		break;
	    fseek(ifp, offset, 0);
	}
	return(0);
}

void
getfield(char *name, char *ifde, FILE *ifp)
{
	char buf[1024];
	int here = ftell(ifp);
	int type = char2short(&ifde[2]);
	int count = char2long(&ifde[4]);
	int offset = char2long(&ifde[8]);

	if (Vflg)
	    printf("%s [type=%d count=%d offset=%d]",
	     name, type, count, offset);
	if (type == TYPE_BYTE) {
	    int n, i;

	    if (count <= 4)
		fseek(ifp, here - 4, 0);
	    else
		fseek(ifp, offset, 0);
	    for (; count > 0; ) {
		n = MIN(count, sizeof buf);
		count -= n;
		fread(buf, 1, n, ifp);
		for (i = 0; i < n; i++) {
		    if (Vflg)
			printf(" %d (0x%x)", buf[i] & 0xFF, buf[i] & 0xFF);
		    else
			printf("%d", buf[i] & 0xFF);
		}
	    }
	    printf("\n");
	} else if (type == TYPE_ASCII) {
	    printf("I don't know how to do the ASCII type yet.\n");
	} else if (type == TYPE_SHORT) {
	    printf("I don't know how to do the SHORT type yet.\n");
	} else if (type == TYPE_LONG) {
	    printf("I don't know how to do the LONG type yet.\n");
	} else if (type == TYPE_RATIONAL) {
	    int num, den;

	    for (fseek(ifp, offset, 0); --count >= 0; ) {
		fread(buf, 1, 8, ifp);
		num = char2long(&buf[0]);
		den = char2long(&buf[4]);
		if (Vflg)
		    printf(" %d/%d=%g", num, den, (float)num / (float)den);
		else
		    printf("%g", (float)num / (float)den);
	    }
	    printf("\n");
	} else
	    printf("I don't know how to do type %d.\n", type);
	fseek(ifp, here, 0);
}

void
setfield(double val, char *ifde, FILE *ifp)
{
	char buf[1024];
	int here = ftell(ifp);
	int type = char2short(&ifde[2]);
	int count = char2long(&ifde[4]);
	int offset = char2long(&ifde[8]);

	if (type == TYPE_BYTE) {
	    int n, i, v = val;

	    if (count <= 4)
		fseek(ifp, here - 4, 0);
	    else
		fseek(ifp, offset, 0);
	    for (i = MIN(count, sizeof buf); --i >= 0; buf[i] = v);
	    for (; count > 0; count -= n) {
		n = MIN(count, sizeof buf);
		fwrite(buf, 1, n, ifp);
	    }
	} else if (type == TYPE_ASCII) {
	    printf("I don't know how to do the ASCII type yet.\n");
	} else if (type == TYPE_SHORT) {
	    printf("I don't know how to do the SHORT type yet.\n");
	} else if (type == TYPE_LONG) {
	    printf("I don't know how to do the LONG type yet.\n");
	} else if (type == TYPE_RATIONAL) {
	    int num, den = 10000;

	    num = den * val;
	    long2char(num, buf);
	    long2char(den, &buf[4]);
	    for (fseek(ifp, offset, 0); --count >= 0; )
		fwrite(buf, 1, 8, ifp);
	} else
	    printf("I don't know how to do type %d.\n", type);
	fseek(ifp, here, 0);
}

int
char2short(char *cp)
{
	if (BigEnd)
	    return(((cp[0] & 0xFF) << 8) + (cp[1] & 0xFF));
	return(((cp[1] & 0xFF) << 8) + (cp[0] & 0xFF));
}

int
char2long(char *cp)
{
	if (BigEnd)
	    return(((cp[0] & 0xFF) << 24) + ((cp[1] & 0xFF) << 16)
	     + ((cp[2] & 0xFF) << 8) + (cp[3] & 0xFF));
	return(((cp[3] & 0xFF) << 24) + ((cp[2] & 0xFF) << 16)
	 + ((cp[1] & 0xFF) << 8) + (cp[0] & 0xFF));
}

void
long2char(int l, char *cp)
{
	int i;

	if (BigEnd)
	    for (i = 4; --i >= 0; )
		cp[i] = (l >> (24 - 8 * i)) & 0xFF;
	else
	    for (i = 4; --i >= 0; )
		cp[i] = (l >> (8 * i)) & 0xFF;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.