[alt.sources] ppmbrighten.c and manual

brianm@sco.COM (Brian Moffet) (11/29/90)

This needs the pbm libraries and header files to compile.

------------ cut here ------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	ppmbrighten.1
#	ppmbrighten.c
# This archive created: Wed Nov 28 13:03:06 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'ppmbrighten.1'
then
	echo shar: "will not over-write existing file 'ppmbrighten.1'"
else
cat << \SHAR_EOF > 'ppmbrighten.1'
.TH ppmbrighten 1 "20 Nov 1990"
.SH NAME
ppmbrighten - change an images Saturation and Value from an HSV map
.SH SYNOPSIS
ppmbrighten [-n] [-s <+- saturation>] [-v <+- value>] <ppmfile>
.SH DESCRIPTION
Reads a portable pixmap as input.
Converts the image from RGB space to HSV space and changes
the Value by <+- value> as a percentage.
Likewise with the Saturation.
Doubling the Value would involve
.sp
ppmbrighten -v 100
.sp
to add 100 percent to the Value.
.PP
The 'n' option normalizes the Value to exist between 0 and 1
(normalized).
.SH "SEE ALSO"
pgmnorm(1), ppm(5)
.SH AUTHOR
Copyright (C) 1990 by Brian Moffet
Copyright (C) 1989 by Jef Poskanzer.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.  This software is provided "as is" without express or
implied warranty.
.SH NOTES
This program does not change the number of colors.
SHAR_EOF
fi
if test -f 'ppmbrighten.c'
then
	echo shar: "will not over-write existing file 'ppmbrighten.c'"
else
cat << \SHAR_EOF > 'ppmbrighten.c'
/* ppmbrighten.c - allow user control over Value and Saturation of PPM file
**
** Copyright (C) 1989 by Jef Poskanzer.
** Copyright (C) 1990 by Brian Moffet.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include "ppm.h"

#define	MULTI	1000
#define	FIND_MINMAX	1
#define	SET_VALUE	2
#define	SET_SATUR	4

main( argc, argv )
int argc;
char *argv[];
{
	FILE *fp = stdin;
	extern char *optarg;
	extern int optind;
	int value = 100, saturation = 100, c, error = 0;
	int min_value, max_value;
	int flags = 0;

	pixel *pixelP;
	pixval maxval;
	int rows, cols, format, index;


	while ((c = getopt( argc, argv, "s:v:n" )) != -1)
		switch (c) 
		{
			case 's':
				flags |= SET_SATUR;
				saturation = 100 + atoi( optarg );
				break;
			case 'v':
				flags |= SET_SATUR;
				value = 100 + atoi( optarg );
				break;
			case 'n':
				flags |= FIND_MINMAX;
				break;
			default:
				error = 1;
				break;
		}

	if (error)
	{
		fprintf( stderr,
		"Usage: %s [-s <+- saturation>] [-v <+- value>] <ppmfile>\n",
			 argv[0] );
		exit( 1 );
	}

	if (value < 0) value = 0;

	if (saturation < 0) saturation = 0;

	if (optind != argc)
		if ((fp = fopen( argv[optind], "r" )) == NULL )
		{
			fprintf( stderr, "Coundn't open %s for reading\n",
				argv[optind] );
			exit( 1 );
		}

	if (flags & FIND_MINMAX)
	{
		ppm_readppminit( fp, &cols, &rows, &maxval, &format );
		pixelP = ppm_allocrow( cols );
		max_value = 0;
		min_value = MULTI;
		for (index = 0; index < rows; index++)
		{
			int i;
			ppm_readppmrow( fp, pixelP, cols, maxval, format );
			for (i = 0; i < cols; i++)
			{
				int r, g, b;
				long R, G, B, H, S, V;

				r = PPM_GETR( pixelP[i] );
				g = PPM_GETG( pixelP[i] );
				b = PPM_GETB( pixelP[i] );

				R = (MULTI * r + maxval - 1) / maxval;
				G = (MULTI * g + maxval - 1) / maxval;
				B = (MULTI * b + maxval - 1) / maxval;

				GetHSV( R, G, B, &H, &S, &V );
				if ( V > max_value)	max_value = V;
				if ( V < min_value)	min_value = V;
			}
		}
		ppm_freerow( pixelP );
		fprintf( stderr, "Min is %4d\tMax = %4d\n",
						min_value, max_value );
		rewind( fp );
	}

	ppm_readppminit( fp, &cols, &rows, &maxval, &format );

	ppm_writeppminit( stdout, cols, rows, maxval );

	pixelP = ppm_allocrow( cols );

	if (pixelP == NULL)
	{
		fprintf( stderr, "Error allocating Pixel row\n" );
		exit( 3 );
	}

	for (index = 0; index < rows; index++)
	{
		int i;
		ppm_readppmrow( fp, pixelP, cols, maxval, format );
		for (i = 0; i < cols; i++)
		{
			int r, g, b;
			long R, G, B, H, S, V;

			r = PPM_GETR( pixelP[i] );
			g = PPM_GETG( pixelP[i] );
			b = PPM_GETB( pixelP[i] );

			R = (MULTI * r + maxval - 1) / maxval;
			G = (MULTI * g + maxval - 1) / maxval;
			B = (MULTI * b + maxval - 1) / maxval;

			GetHSV( R, G, B, &H, &S, &V );

			if (flags & FIND_MINMAX)
			{
				V -= min_value;
				V = (V * MULTI) /
					(MULTI - (min_value+MULTI-max_value));
			}

			S = ( S * saturation ) / 100;
			V = ( V * value ) / 100;

			if (V > MULTI)
				V = MULTI;
			if (S > MULTI)
				S = MULTI;

			GetRGB( H, S, V, &R, &G, &B );

			r = (R * maxval) / MULTI;
			g = (G * maxval) / MULTI;
			b = (B * maxval) / MULTI;

			PPM_ASSIGN( pixelP[i], r, g, b );
		}

		ppm_writeppmrow( stdout, pixelP, cols, maxval );
	}
	ppm_freerow( pixelP );

	if (fp != stdin)
		fclose( fp );
}

#define	min(x,y)	((x < y) ? x : y)
#define	max(x,y)	((x > y) ? x : y)

static int
GetHSV( r, g, b, h, s, v )
long r, g, b;
long *h, *s, *v;
{
	long t;

	*v = max( r, max( g, b ) );

	t = min( r, min( g, b ) );

	if ( *v == 0 )
		*s = 0;
	else
		*s = ( (*v - t)*MULTI ) / *v;

	if ( *s == 0 )
		*h = 0;
	else
	{
		long cr, cg, cb;
		cr = (MULTI * ( *v - r ))/( *v - t );
		cg = (MULTI * ( *v - g ))/( *v - t );
		cb = (MULTI * ( *v - b ))/( *v - t );

		if ( r == *v )
			*h = cb - cg;

		if ( g == *v )
			*h = (2*MULTI) + cr - cb;

		if ( b == *v )
			*h = (4*MULTI) + cg - cr;

		*h = *h * 60;
		if ( *h < 0 )
			*h += (360 * MULTI);
	}
}

static int
GetRGB( h, s, v, r, g, b )
long h, s, v;
long *r, *g, *b;
{
	if ( s == 0 )
	{
		*r = v;
		*g = v;
		*b = v;
	} else {
		long f, m, n, k;
		long i;

		if (h == (360 * MULTI))
			h = 0;
		h = h / 60;
		i = (h - (h % MULTI));
		f = h - i;
		m = (v * (MULTI - s)) / MULTI;
		n = (v * (MULTI - (s * f)/MULTI)) / MULTI;
		k = (v * (MULTI - (s * (MULTI - f))/MULTI)) / MULTI;

		switch (i)
		{
			case 0:
				*r = v;
				*g = k;
				*b = m;
				break;
			case MULTI:
				*r = n;
				*g = v;
				*b = m;
				break;
			case (2*MULTI):
				*r = m;
				*g = v;
				*b = k;
				break;
			case (3*MULTI):
				*r = m;
				*g = n;
				*b = v;
				break;
			case (4*MULTI):
				*r = k;
				*g = m;
				*b = v;
				break;
			case (5*MULTI):
				*r = v;
				*g = m;
				*b = n;
				break;
		}
	}
}
SHAR_EOF
fi
exit 0
#	End of shell archive

-- 
Brian Moffet	ext 6567	brianm@sco.com -or- ...!uunet!sco!brianm
"Processed American Cheese Food....  Dog Food, Cat Food, Cheese Food?"
	-- Dan St. Paul