const char * UsageLines [] = {
	"Usage: p6contrast (contrast factor)",
	"Reads P6 PPM from standard input.",
	"For contrast factor > 1, contrast is increased at midrange",
	"brightness, reduced near black and white.",
	"For contrast factor < 1, contrast is reduced at midrange",
	"brightness, increased near black and white.",
	"Contrast factor is the slope of the brightness transfer curve",
	"at midrange.",
	"1.0 results in output same as input.",
	"Passes each color component (normalized to the range 0 <= x <= 1)",
	"through the transfer function:",
	"\t1/(1 + (1/x - 1)**(contrast factor) )",
	"This has the additional effect of intensifying color at midrange",
	"brightness (for contrast factor > 1).",
	"Writes same dimensions PPM to standard output.",
	"Example of usage in pipeline to convert scanned document (3600x2700)",
	"from jpeg to a one-page pdf:",
	"\tdjpeg \\",
	"\t| p6contrast 5 \\",
	"\t| pnmtops -equalpixels -dpi 360 \\",
	"\t| ps2pdf -dAutoFilterColorImages=false -sPAPERSIZE=letter - -",
	"March 8, 2009.  Newest is at gopher -p users/julianbr sdf.org",
	};
const int NumUsageLines = sizeof (UsageLines)/sizeof (UsageLines [0] );

/* Compile using -lm */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>


void ContrastData (int width, int height, float contrast)
	{
	int InputR, InputG, InputB, OutputR, OutputG, OutputB;
	int i, j;

	InputR = getchar ();
	for (i = 0; i < height; i++) {
		for (j = 0; j < width; j++) {
			if (InputR == EOF)
				InputG = EOF;
			else
				InputG = getchar ();
			if (InputG == EOF)
				InputB = EOF;
			else
				InputB = getchar ();
			if (InputB == EOF) {
				putchar (128);
				putchar (128);
				putchar (128);
				}
			else {
				if (InputR == 0)
					OutputR = 0;
				else if (InputR == 255)
					OutputR = 255;
				else
					OutputR = 255/(1 + exp (contrast
						*log (255./InputR - 1) ) ) + .5;
				if (InputG == 0)
					OutputG = 0;
				else if (InputG == 255)
					OutputG = 255;
				else
					OutputG = 255/(1 + exp (contrast
						*log (255./InputG - 1) ) ) + .5;
				if (InputB == 0)
					OutputB = 0;
				else if (InputB == 255)
					OutputB = 255;
				else
					OutputB = 255/(1 + exp (contrast
						*log (255./InputB - 1) ) ) + .5;
				putchar (OutputR);
				putchar (OutputG);
				putchar (OutputB);
				}
			if (InputB == EOF)
				InputR = EOF;
			else
				InputR = getchar ();
			}
		}
	if (InputB == EOF) {
		fprintf (stderr, "***p6contrast: Premature end");
		fprintf (stderr, " of input image data.\n");
		}
	if (InputR != EOF) {
		fprintf (stderr, "***p6contrast: Extra input");
		fprintf (stderr, " image data.\n");
		}
	}


void ContrastFile (float contrast)
	{
	int width, height, maxval;

	if (getchar () != 'P'
			|| getchar () != '6'
			|| scanf ("%d", & width) < 1
			|| width < 1
			|| scanf ("%d", & height) < 1
			|| height < 1
			|| scanf ("%d", & maxval) < 1
			|| maxval != 255
			|| getchar () == EOF) {
		fprintf (stderr, "***p6contrast: Improper input,");
		fprintf (stderr, " must be P6 with maxval 255.\n");
		}
	else {
		printf ("P6\n");
		printf ("%d %d\n", width, height);
		printf ("255\n");
		ContrastData (width, height, contrast);
		}
	}


int main (int argc, char * argv [] )
	{
	float contrast;
	int i;
	char c;

	if (argc < 2) {
		for (i = 0; i < NumUsageLines; i++)
			printf ("%s\n", UsageLines [i] );
		}
	else if (argc == 2) {
		if (sscanf (argv [1], "%f%c", & contrast, & c) != 1) {
			fprintf (stderr, "***p6contrast: Expecting number");
			fprintf (stderr, " for contrast factor, found");
			fprintf (stderr, " \"%s\".\n", argv [1] );
			}
		else
			ContrastFile (contrast);
		}
	else {
		fprintf (stderr, "Usage: p6constrast");
		fprintf (stderr, " (contrast factor)\n");
		}
	return 0;
	}