This is pnmgamma.c in view mode; [Download] [Up]
/* pnmgamma.c - perform gamma correction on a portable pixmap ** ** Copyright (C) 1991 by Bill Davidson and 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. */ #include <math.h> #include <ctype.h> #include "pnm.h" static void buildgamma ARGS(( xelval table[], xelval maxval, double gamma )); int main( argc, argv ) int argc; char* argv[]; { FILE* ifp; xel* xelrow; register xel* xP; xelval maxval; int argn, rows, cols, format, newformat, row; register int col; double rgamma, ggamma, bgamma; xelval* rtable; xelval* gtable; xelval* btable; char *usage = "<value> [pnmfile]\n\t\t<redvalue> <greenvalue> <bluevalue> [pnmfile]"; pnm_init( &argc, argv ); argn = 1; /* Parse gamma args. */ if ( argc == 2 || argc == 3 ) { rgamma = ggamma = bgamma = atof( argv[argn] ); ++argn; } else if ( argc == 4 || argc == 5 ) { rgamma = atof( argv[argn] ); ++argn; ggamma = atof( argv[argn] ); ++argn; bgamma = atof( argv[argn] ); ++argn; } else pm_usage( usage ); if ( rgamma <= 0.0 || ggamma <= 0.0 || bgamma <= 0.0 ) pm_usage( usage ); if ( argn != argc ) { ifp = pm_openr( argv[argn] ); ++argn; } else ifp = stdin; if ( argn != argc ) pm_usage( usage ); pnm_pbmmaxval = PNM_MAXMAXVAL; /* use larger value for better results */ pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); xelrow = pnm_allocrow( cols ); /* Promote PBM files to PGM. Not that it makes much sense to ** gamma-correct PBM files. */ if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) { newformat = PGM_TYPE; pm_message( "promoting to PGM" ); } else newformat = format; if ( rgamma != ggamma || ggamma != bgamma ) if ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE ) { newformat = PPM_TYPE; pm_message( "promoting to PPM" ); } /* Allocate space for the tables. */ rtable = (xelval*) malloc( (maxval+1) * sizeof(xelval) ); gtable = (xelval*) malloc( (maxval+1) * sizeof(xelval) ); btable = (xelval*) malloc( (maxval+1) * sizeof(xelval) ); if ( rtable == 0 || gtable == 0 || btable == 0 ) pm_error( "out of memory" ); /* Build the gamma corection tables. */ buildgamma( rtable, maxval, rgamma ); buildgamma( gtable, maxval, ggamma ); buildgamma( btable, maxval, bgamma ); pnm_writepnminit( stdout, cols, rows, maxval, newformat, 0 ); for ( row = 0; row < rows; ++row ) { pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); /* Promote to PPM if differing gammas were specified. */ if ( rgamma != ggamma || ggamma != bgamma ) if ( PNM_FORMAT_TYPE(format) != PPM_TYPE && PNM_FORMAT_TYPE(newformat) == PPM_TYPE ) pnm_promoteformatrow( xelrow, cols, maxval, format, maxval, newformat ); switch ( PNM_FORMAT_TYPE(newformat) ) { case PPM_TYPE: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) { register xelval r, g, b; r = PPM_GETR( *xP ); g = PPM_GETG( *xP ); b = PPM_GETB( *xP ); r = rtable[r]; g = gtable[g]; b = btable[b]; PPM_ASSIGN( *xP, r, g, b ); } break; default: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) { register xelval g; g = PNM_GET1( *xP ); g = gtable[g]; PNM_ASSIGN1( *xP, g ); } break; } pnm_writepnmrow( stdout, xelrow, cols, maxval, newformat, 0 ); } pm_close( ifp ); pm_close( stdout ); exit( 0 ); } /* ** Builds a gamma table of size maxval+1 for the given gamma value. ** ** This function depends on pow(3m). If you don't have it, you can ** simulate it with '#define pow(x,y) exp((y)*log(x))' provided that ** you have the exponential function exp(3m) and the natural logarithm ** function log(3m). I can't believe I actually remembered my log ** identities. */ #if __STDC__ static void buildgamma( xelval table[], xelval maxval, double gamma ) #else /*__STDC__*/ static void buildgamma( table, maxval, gamma ) xelval table[], maxval; double gamma; #endif /*__STDC__*/ { register int i, v; double one_over_gamma, ind, q; one_over_gamma = 1.0 / gamma; q = (double) maxval; for ( i = 0 ; i <= (int) maxval; ++i ) { ind = ( (double) i ) / q; v = ( q * pow( ind, one_over_gamma ) ) + 0.5; if ( v > (int) maxval ) v = maxval; table[i] = v; } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.