|
Packit |
78deda |
/* pnmgamma.c - perform gamma correction on a PNM image
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Copyright (C) 1991 by Bill Davidson and Jef Poskanzer.
|
|
Packit |
78deda |
**
|
|
Packit |
78deda |
** Permission to use, copy, modify, and distribute this software and its
|
|
Packit |
78deda |
** documentation for any purpose and without fee is hereby granted, provided
|
|
Packit |
78deda |
** that the above copyright notice appear in all copies and that both that
|
|
Packit |
78deda |
** copyright notice and this permission notice appear in supporting
|
|
Packit |
78deda |
** documentation. This software is provided "as is" without express or
|
|
Packit |
78deda |
** implied warranty.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include <assert.h>
|
|
Packit |
78deda |
#include <math.h>
|
|
Packit |
78deda |
#include <ctype.h>
|
|
Packit |
78deda |
|
|
Packit |
78deda |
#include "pm_c_util.h"
|
|
Packit |
78deda |
#include "mallocvar.h"
|
|
Packit |
78deda |
#include "shhopt.h"
|
|
Packit |
78deda |
#include "pnm.h"
|
|
Packit |
78deda |
|
|
Packit |
78deda |
enum transferFunction {
|
|
Packit |
78deda |
XF_EXP,
|
|
Packit |
78deda |
XF_EXP_INVERSE,
|
|
Packit |
78deda |
XF_BT709RAMP,
|
|
Packit |
78deda |
XF_BT709RAMP_INVERSE,
|
|
Packit |
78deda |
XF_SRGBRAMP,
|
|
Packit |
78deda |
XF_SRGBRAMP_INVERSE,
|
|
Packit |
78deda |
XF_BT709_TO_SRGB,
|
|
Packit |
78deda |
XF_SRGB_TO_BT709
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
struct cmdlineInfo {
|
|
Packit |
78deda |
/* All the information the user supplied in the command line,
|
|
Packit |
78deda |
in a form easy for the program to use.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
const char * filespec; /* '-' if stdin */
|
|
Packit |
78deda |
enum transferFunction transferFunction;
|
|
Packit |
78deda |
float rgamma, ggamma, bgamma;
|
|
Packit |
78deda |
unsigned int maxval;
|
|
Packit |
78deda |
unsigned int makeNewMaxval;
|
|
Packit |
78deda |
};
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
interpretOldArguments(int const argc,
|
|
Packit |
78deda |
char ** const argv,
|
|
Packit |
78deda |
float const defaultGamma,
|
|
Packit |
78deda |
struct cmdlineInfo * const cmdlineP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Use the old syntax wherein the gamma values come from arguments.
|
|
Packit |
78deda |
If there is one argument, it's a gamma value for all three
|
|
Packit |
78deda |
components. If 3 arguments, it's separate gamma values. If
|
|
Packit |
78deda |
2, it's a single gamma value plus a file name. If 4, it's
|
|
Packit |
78deda |
separate gamma values plus a file name.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
if (argc-1 == 0) {
|
|
Packit |
78deda |
cmdlineP->rgamma = defaultGamma;
|
|
Packit |
78deda |
cmdlineP->ggamma = defaultGamma;
|
|
Packit |
78deda |
cmdlineP->bgamma = defaultGamma;
|
|
Packit |
78deda |
cmdlineP->filespec = "-";
|
|
Packit |
78deda |
} else if (argc-1 == 1) {
|
|
Packit |
78deda |
cmdlineP->rgamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->ggamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->bgamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->filespec = "-";
|
|
Packit |
78deda |
} else if (argc-1 == 2) {
|
|
Packit |
78deda |
cmdlineP->rgamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->ggamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->bgamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->filespec = argv[2];
|
|
Packit |
78deda |
} else if (argc-1 == 3) {
|
|
Packit |
78deda |
cmdlineP->rgamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->ggamma = atof(argv[2]);
|
|
Packit |
78deda |
cmdlineP->bgamma = atof(argv[3]);
|
|
Packit |
78deda |
cmdlineP->filespec = "-";
|
|
Packit |
78deda |
} else if (argc-1 == 4) {
|
|
Packit |
78deda |
cmdlineP->rgamma = atof(argv[1]);
|
|
Packit |
78deda |
cmdlineP->ggamma = atof(argv[2]);
|
|
Packit |
78deda |
cmdlineP->bgamma = atof(argv[3]);
|
|
Packit |
78deda |
cmdlineP->filespec = argv[4];
|
|
Packit |
78deda |
} else
|
|
Packit |
78deda |
pm_error("Wrong number of arguments. "
|
|
Packit |
78deda |
"You may have 0, 1, or 3 gamma values "
|
|
Packit |
78deda |
"plus zero or one filename");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdlineP->rgamma <= 0.0 ||
|
|
Packit |
78deda |
cmdlineP->ggamma <= 0.0 ||
|
|
Packit |
78deda |
cmdlineP->bgamma <= 0.0 )
|
|
Packit |
78deda |
pm_error("Invalid gamma value. Must be positive floating point "
|
|
Packit |
78deda |
"number.");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
getGammaFromOpts(struct cmdlineInfo * const cmdlineP,
|
|
Packit |
78deda |
bool const gammaSpec,
|
|
Packit |
78deda |
float const gammaOpt,
|
|
Packit |
78deda |
bool const rgammaSpec,
|
|
Packit |
78deda |
bool const ggammaSpec,
|
|
Packit |
78deda |
bool const bgammaSpec,
|
|
Packit |
78deda |
float const defaultGamma) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (gammaSpec)
|
|
Packit |
78deda |
if (gammaOpt < 0.0)
|
|
Packit |
78deda |
pm_error("Invalid gamma value %f. Must be positive.", gammaOpt);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (rgammaSpec) {
|
|
Packit |
78deda |
if (cmdlineP->rgamma < 0.0)
|
|
Packit |
78deda |
pm_error("Invalid red gamma value %f. Must be positive.",
|
|
Packit |
78deda |
cmdlineP->rgamma);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (gammaSpec)
|
|
Packit |
78deda |
cmdlineP->rgamma = gammaOpt;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->rgamma = defaultGamma;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
if (ggammaSpec) {
|
|
Packit |
78deda |
if (cmdlineP->ggamma < 0.0)
|
|
Packit |
78deda |
pm_error("Invalid green gamma value %f. Must be positive.",
|
|
Packit |
78deda |
cmdlineP->ggamma);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (gammaSpec)
|
|
Packit |
78deda |
cmdlineP->ggamma = gammaOpt;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->ggamma = defaultGamma;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
if (bgammaSpec) {
|
|
Packit |
78deda |
if (cmdlineP->bgamma < 0.0)
|
|
Packit |
78deda |
pm_error("Invalid blue gamma value %f. Must be positive.",
|
|
Packit |
78deda |
cmdlineP->bgamma);
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (gammaSpec)
|
|
Packit |
78deda |
cmdlineP->bgamma = gammaOpt;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->bgamma = defaultGamma;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
parseCommandLine(int argc, char ** argv,
|
|
Packit |
78deda |
struct cmdlineInfo * const cmdlineP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
optEntry *option_def;
|
|
Packit |
78deda |
/* Instructions to pm_optParseOptions3 on how to parse our options.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
optStruct3 opt;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
unsigned int bt709ramp, srgbramp, ungamma, bt709tosrgb, srgbtobt709;
|
|
Packit |
78deda |
unsigned int bt709tolinear, lineartobt709;
|
|
Packit |
78deda |
unsigned int gammaSpec, rgammaSpec, ggammaSpec, bgammaSpec;
|
|
Packit |
78deda |
float gammaOpt;
|
|
Packit |
78deda |
float defaultGamma;
|
|
Packit |
78deda |
unsigned int option_def_index;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
MALLOCARRAY_NOFAIL(option_def, 100);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
option_def_index = 0; /* incremented by OPTENT3 */
|
|
Packit |
78deda |
OPTENT3(0, "ungamma", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&ungamma, 0);
|
|
Packit |
78deda |
OPTENT3(0, "bt709tolinear", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&bt709tolinear, 0);
|
|
Packit |
78deda |
OPTENT3(0, "lineartobt709", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&lineartobt709, 0);
|
|
Packit |
78deda |
OPTENT3(0, "bt709ramp", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&bt709ramp, 0);
|
|
Packit |
78deda |
OPTENT3(0, "cieramp", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&bt709ramp, 0);
|
|
Packit |
78deda |
OPTENT3(0, "srgbramp", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&srgbramp, 0);
|
|
Packit |
78deda |
OPTENT3(0, "bt709tosrgb", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&bt709tosrgb, 0);
|
|
Packit |
78deda |
OPTENT3(0, "srgbtobt709", OPT_FLAG, NULL,
|
|
Packit |
78deda |
&srgbtobt709, 0);
|
|
Packit |
78deda |
OPTENT3(0, "maxval", OPT_UINT, &cmdlineP->maxval,
|
|
Packit |
78deda |
&cmdlineP->makeNewMaxval, 0);
|
|
Packit |
78deda |
OPTENT3(0, "gamma", OPT_FLOAT, &gammaOpt,
|
|
Packit |
78deda |
&gammaSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "rgamma", OPT_FLOAT, &cmdlineP->rgamma,
|
|
Packit |
78deda |
&rgammaSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "ggamma", OPT_FLOAT, &cmdlineP->ggamma,
|
|
Packit |
78deda |
&ggammaSpec, 0);
|
|
Packit |
78deda |
OPTENT3(0, "bgamma", OPT_FLOAT, &cmdlineP->bgamma,
|
|
Packit |
78deda |
&bgammaSpec, 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
opt.opt_table = option_def;
|
|
Packit |
78deda |
opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
|
|
Packit |
78deda |
opt.allowNegNum = TRUE;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
|
|
Packit |
78deda |
/* Uses and sets argc, argv, and some of *cmdline_p and others. */
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (bt709tolinear + lineartobt709 + bt709ramp + srgbramp +
|
|
Packit |
78deda |
bt709tosrgb + srgbtobt709 > 1)
|
|
Packit |
78deda |
pm_error("You may specify only one function option");
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
if (bt709tolinear) {
|
|
Packit |
78deda |
if (ungamma)
|
|
Packit |
78deda |
pm_error("You cannot specify -ungamma with -bt709tolinear");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_BT709RAMP_INVERSE;
|
|
Packit |
78deda |
} else if (lineartobt709) {
|
|
Packit |
78deda |
if (ungamma)
|
|
Packit |
78deda |
pm_error("You cannot specify -ungamma with -lineartobt709");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_BT709RAMP;
|
|
Packit |
78deda |
} else if (bt709tosrgb) {
|
|
Packit |
78deda |
if (ungamma)
|
|
Packit |
78deda |
pm_error("You cannot specify -ungamma with -bt709tosrgb");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_BT709_TO_SRGB;
|
|
Packit |
78deda |
} else if (srgbtobt709) {
|
|
Packit |
78deda |
if (ungamma)
|
|
Packit |
78deda |
pm_error("You cannot specify -ungamma with -srgbtobt709");
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_SRGB_TO_BT709;
|
|
Packit |
78deda |
} else if (bt709ramp) {
|
|
Packit |
78deda |
if (ungamma)
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_BT709RAMP_INVERSE;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_BT709RAMP;
|
|
Packit |
78deda |
} else if (srgbramp) {
|
|
Packit |
78deda |
if (ungamma)
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_SRGBRAMP_INVERSE;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_SRGBRAMP;
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (ungamma)
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_EXP_INVERSE;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
cmdlineP->transferFunction = XF_EXP;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (cmdlineP->makeNewMaxval) {
|
|
Packit |
78deda |
if (cmdlineP->maxval > PNM_OVERALLMAXVAL)
|
|
Packit |
78deda |
pm_error("Largest possible maxval is %u. You specified %u",
|
|
Packit |
78deda |
PNM_OVERALLMAXVAL, cmdlineP->maxval);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (cmdlineP->transferFunction) {
|
|
Packit |
78deda |
case XF_BT709RAMP:
|
|
Packit |
78deda |
case XF_BT709RAMP_INVERSE:
|
|
Packit |
78deda |
case XF_SRGB_TO_BT709:
|
|
Packit |
78deda |
defaultGamma = 1.0/0.45;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case XF_SRGBRAMP:
|
|
Packit |
78deda |
case XF_SRGBRAMP_INVERSE:
|
|
Packit |
78deda |
case XF_BT709_TO_SRGB:
|
|
Packit |
78deda |
/* The whole function is often approximated with
|
|
Packit |
78deda |
exponent 2.2 and no linear piece. We do the linear
|
|
Packit |
78deda |
piece, so we use the real exponent of 2.4.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
defaultGamma = 2.4;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
case XF_EXP:
|
|
Packit |
78deda |
case XF_EXP_INVERSE:
|
|
Packit |
78deda |
defaultGamma = 2.2;
|
|
Packit |
78deda |
break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (bt709tolinear || lineartobt709 || bt709tosrgb || srgbtobt709) {
|
|
Packit |
78deda |
/* Use the new syntax wherein the gamma values come from options,
|
|
Packit |
78deda |
not arguments. So if there's an argument, it's a file name.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
getGammaFromOpts(cmdlineP, gammaSpec, gammaOpt,
|
|
Packit |
78deda |
rgammaSpec, ggammaSpec, bgammaSpec, defaultGamma);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (argc-1 < 1)
|
|
Packit |
78deda |
cmdlineP->filespec = "-";
|
|
Packit |
78deda |
else {
|
|
Packit |
78deda |
cmdlineP->filespec = argv[1];
|
|
Packit |
78deda |
if (argc-1 > 1)
|
|
Packit |
78deda |
pm_error("Too many arguments (%u). With this function, there "
|
|
Packit |
78deda |
"is at most one argument: the file name", argc-1);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
} else {
|
|
Packit |
78deda |
if (gammaSpec || rgammaSpec || ggammaSpec || bgammaSpec)
|
|
Packit |
78deda |
pm_error("With this function, you specify the gamma values in "
|
|
Packit |
78deda |
"arguments, not with the -gamma, etc.");
|
|
Packit |
78deda |
interpretOldArguments(argc, argv, defaultGamma, cmdlineP);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
buildPowGamma(xelval table[],
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const gamma) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Build a gamma table of size maxval+1 for the given gamma value.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
This function depends on pow(3m). If you don't have it, you can
|
|
Packit |
78deda |
simulate it with '#define pow(x,y) exp((y)*log(x))' provided that
|
|
Packit |
78deda |
you have the exponential function exp(3m) and the natural logarithm
|
|
Packit |
78deda |
function log(3m). I can't believe I actually remembered my log
|
|
Packit |
78deda |
identities.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
xelval i;
|
|
Packit |
78deda |
double const oneOverGamma = 1.0 / gamma;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0 ; i <= maxval; ++i) {
|
|
Packit |
78deda |
double const normalized = ((double) i) / maxval;
|
|
Packit |
78deda |
/* Xel sample value normalized to 0..1 */
|
|
Packit |
78deda |
double const v = pow(normalized, oneOverGamma);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
table[i] = MIN((xelval)(v * newMaxval + 0.5), newMaxval);
|
|
Packit |
78deda |
/* denormalize, round and clip */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
buildBt709Gamma(xelval table[],
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const gamma) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Build a gamma table of size maxval+1 for the ITU Recommendation
|
|
Packit |
78deda |
BT.709 gamma transfer function.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'gamma' must be 1/0.45 for true Rec. 709.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
double const oneOverGamma = 1.0 / gamma;
|
|
Packit |
78deda |
xelval i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* This transfer function is linear for sample values 0
|
|
Packit |
78deda |
.. maxval*.018 and an exponential for larger sample values.
|
|
Packit |
78deda |
The exponential is slightly stretched and translated, though,
|
|
Packit |
78deda |
unlike the popular pure exponential gamma transfer function.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
xelval const linearCutoff = (xelval) (maxval * 0.018 + 0.5);
|
|
Packit |
78deda |
double const linearExpansion =
|
|
Packit |
78deda |
(1.099 * pow(0.018, oneOverGamma) - 0.099) / 0.018;
|
|
Packit |
78deda |
double const maxvalScaler = (double)newMaxval/maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i <= linearCutoff; ++i)
|
|
Packit |
78deda |
table[i] = i * linearExpansion * maxvalScaler + 0.5;
|
|
Packit |
78deda |
for (; i <= maxval; ++i) {
|
|
Packit |
78deda |
double const normalized = ((double) i) / maxval;
|
|
Packit |
78deda |
/* Xel sample value normalized to 0..1 */
|
|
Packit |
78deda |
double const v = 1.099 * pow(normalized, oneOverGamma) - 0.099;
|
|
Packit |
78deda |
table[i] = MIN((xelval)(v * newMaxval + 0.5), newMaxval);
|
|
Packit |
78deda |
/* denormalize, round, and clip */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
buildBt709GammaInverse(xelval table[],
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const gamma) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Build a gamma table of size maxval+1 for the Inverse of the ITU
|
|
Packit |
78deda |
Rec. BT.709 gamma transfer function.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'gamma' must be 1/0.45 for true Rec. 709.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
double const oneOverGamma = 1.0 / gamma;
|
|
Packit |
78deda |
xelval i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* This transfer function is linear for sample values 0
|
|
Packit |
78deda |
.. maxval*.018 and an exponential for larger sample values.
|
|
Packit |
78deda |
The exponential is slightly stretched and translated, though,
|
|
Packit |
78deda |
unlike the popular pure exponential gamma transfer function.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
xelval const linearCutoff = (xelval) (maxval * 0.018 + 0.5);
|
|
Packit |
78deda |
double const linearCompression =
|
|
Packit |
78deda |
0.018 / (1.099 * pow(0.018, oneOverGamma) - 0.099);
|
|
Packit |
78deda |
double const maxvalScaler = (double)newMaxval/maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i <= linearCutoff / linearCompression; ++i)
|
|
Packit |
78deda |
table[i] = i * linearCompression * maxvalScaler + 0.5;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (; i <= maxval; ++i) {
|
|
Packit |
78deda |
double const normalized = ((double) i) / maxval;
|
|
Packit |
78deda |
/* Xel sample value normalized to 0..1 */
|
|
Packit |
78deda |
double const v = pow((normalized + 0.099) / 1.099, gamma);
|
|
Packit |
78deda |
table[i] = MIN((xelval)(v * newMaxval + 0.5), newMaxval);
|
|
Packit |
78deda |
/* denormalize, round, and clip */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
buildSrgbGamma(xelval table[],
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const gamma) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Build a gamma table of size maxval+1 for the IEC SRGB gamma
|
|
Packit |
78deda |
transfer function (Standard IEC 61966-2-1).
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'gamma' must be 2.4 for true SRGB
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
double const oneOverGamma = 1.0 / gamma;
|
|
Packit |
78deda |
xelval i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* This transfer function is linear for sample values 0
|
|
Packit |
78deda |
.. maxval*.040405 and an exponential for larger sample values.
|
|
Packit |
78deda |
The exponential is slightly stretched and translated, though,
|
|
Packit |
78deda |
unlike the popular pure exponential gamma transfer function.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
xelval const linearCutoff = (xelval) maxval * 0.0031308 + 0.5;
|
|
Packit |
78deda |
double const linearExpansion =
|
|
Packit |
78deda |
(1.055 * pow(0.0031308, oneOverGamma) - 0.055) / 0.0031308;
|
|
Packit |
78deda |
double const maxvalScaler = (double)newMaxval/maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i <= linearCutoff; ++i)
|
|
Packit |
78deda |
table[i] = i * linearExpansion * maxvalScaler + 0.5;
|
|
Packit |
78deda |
for (; i <= maxval; ++i) {
|
|
Packit |
78deda |
double const normalized = ((double) i) / maxval;
|
|
Packit |
78deda |
/* Xel sample value normalized to 0..1 */
|
|
Packit |
78deda |
double const v = 1.055 * pow(normalized, oneOverGamma) - 0.055;
|
|
Packit |
78deda |
table[i] = MIN((xelval)(v * newMaxval + 0.5), newMaxval);
|
|
Packit |
78deda |
/* denormalize, round, and clip */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
buildSrgbGammaInverse(xelval table[],
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const gamma) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Build a gamma table of size maxval+1 for the Inverse of the IEC SRGB gamma
|
|
Packit |
78deda |
transfer function (Standard IEC 61966-2-1).
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'gamma' must be 2.4 for true SRGB
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
double const oneOverGamma = 1.0 / gamma;
|
|
Packit |
78deda |
xelval i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* This transfer function is linear for sample values 0
|
|
Packit |
78deda |
.. maxval*.040405 and an exponential for larger sample values.
|
|
Packit |
78deda |
The exponential is slightly stretched and translated, though,
|
|
Packit |
78deda |
unlike the popular pure exponential gamma transfer function.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
xelval const linearCutoff = (xelval) maxval * 0.0031308 + 0.5;
|
|
Packit |
78deda |
double const linearCompression =
|
|
Packit |
78deda |
0.0031308 / (1.055 * pow(0.0031308, oneOverGamma) - 0.055);
|
|
Packit |
78deda |
double const maxvalScaler = (double)newMaxval/maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i <= linearCutoff / linearCompression; ++i)
|
|
Packit |
78deda |
table[i] = i * linearCompression * maxvalScaler + 0.5;
|
|
Packit |
78deda |
for (; i <= maxval; ++i) {
|
|
Packit |
78deda |
double const normalized = ((double) i) / maxval;
|
|
Packit |
78deda |
/* Xel sample value normalized to 0..1 */
|
|
Packit |
78deda |
double const v = pow((normalized + 0.055) / 1.055, gamma);
|
|
Packit |
78deda |
table[i] = MIN((xelval)(v * newMaxval + 0.5), newMaxval);
|
|
Packit |
78deda |
/* denormalize, round, and clip */
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
buildBt709ToSrgbGamma(xelval table[],
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const gammaSrgb) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Build a gamma table of size maxval+1 for the combination of the
|
|
Packit |
78deda |
inverse of ITU Rec BT.709 and the forward SRGB gamma transfer
|
|
Packit |
78deda |
functions. I.e. this converts from Rec 709 to SRGB.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'gammaSrgb' must be 2.4 for true SRGB.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
double const oneOverGamma709 = 0.45;
|
|
Packit |
78deda |
double const gamma709 = 1.0 / oneOverGamma709;
|
|
Packit |
78deda |
double const oneOverGammaSrgb = 1.0 / gammaSrgb;
|
|
Packit |
78deda |
double const normalizer = 1.0 / maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* This transfer function is linear for sample values 0
|
|
Packit |
78deda |
.. maxval*.018 and an exponential for larger sample values.
|
|
Packit |
78deda |
The exponential is slightly stretched and translated, though,
|
|
Packit |
78deda |
unlike the popular pure exponential gamma transfer function.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
|
|
Packit |
78deda |
xelval const linearCutoff709 = (xelval) (maxval * 0.018 + 0.5);
|
|
Packit |
78deda |
double const linearCompression709 =
|
|
Packit |
78deda |
0.018 / (1.099 * pow(0.018, oneOverGamma709) - 0.099);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
double const linearCutoffSrgb = 0.0031308;
|
|
Packit |
78deda |
double const linearExpansionSrgb =
|
|
Packit |
78deda |
(1.055 * pow(0.0031308, oneOverGammaSrgb) - 0.055) / 0.0031308;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
xelval i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i <= maxval; ++i) {
|
|
Packit |
78deda |
double const normalized = i * normalizer;
|
|
Packit |
78deda |
/* Xel sample value normalized to 0..1 */
|
|
Packit |
78deda |
double radiance;
|
|
Packit |
78deda |
double srgb;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (i < linearCutoff709 / linearCompression709)
|
|
Packit |
78deda |
radiance = normalized * linearCompression709;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
radiance = pow((normalized + 0.099) / 1.099, gamma709);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(radiance <= 1.0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (radiance < linearCutoffSrgb * normalizer)
|
|
Packit |
78deda |
srgb = radiance * linearExpansionSrgb;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
srgb = 1.055 * pow(normalized, oneOverGammaSrgb) - 0.055;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(srgb <= 1.0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
table[i] = srgb * newMaxval + 0.5;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
buildSrgbToBt709Gamma(xelval table[],
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const gamma709) {
|
|
Packit |
78deda |
/*----------------------------------------------------------------------------
|
|
Packit |
78deda |
Build a gamma table of size maxval+1 for the combination of the
|
|
Packit |
78deda |
inverse of SRGB and the forward ITU Rec BT.709 gamma transfer
|
|
Packit |
78deda |
functions. I.e. this converts from SRGB to Rec 709.
|
|
Packit |
78deda |
|
|
Packit |
78deda |
'gamma709' must be 1/0.45 for true Rec. 709.
|
|
Packit |
78deda |
-----------------------------------------------------------------------------*/
|
|
Packit |
78deda |
double const oneOverGamma709 = 1.0 / gamma709;
|
|
Packit |
78deda |
double const gammaSrgb = 2.4;
|
|
Packit |
78deda |
double const oneOverGammaSrgb = 1.0 / gammaSrgb;
|
|
Packit |
78deda |
double const normalizer = 1.0 / maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* This transfer function is linear for sample values 0
|
|
Packit |
78deda |
.. maxval*.040405 and an exponential for larger sample values.
|
|
Packit |
78deda |
The exponential is slightly stretched and translated, though,
|
|
Packit |
78deda |
unlike the popular pure exponential gamma transfer function.
|
|
Packit |
78deda |
*/
|
|
Packit |
78deda |
xelval const linearCutoffSrgb = (xelval) maxval * 0.0031308 + 0.5;
|
|
Packit |
78deda |
double const linearCompressionSrgb =
|
|
Packit |
78deda |
0.0031308 / (1.055 * pow(0.0031308, oneOverGammaSrgb) - 0.055);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
xelval const linearCutoff709 = (xelval) (maxval * 0.018 + 0.5);
|
|
Packit |
78deda |
double const linearExpansion709 =
|
|
Packit |
78deda |
(1.099 * pow(0.018, oneOverGamma709) - 0.099) / 0.018;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
xelval i;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (i = 0; i <= maxval; ++i) {
|
|
Packit |
78deda |
double const normalized = i * normalizer;
|
|
Packit |
78deda |
/* Xel sample value normalized to 0..1 */
|
|
Packit |
78deda |
double radiance;
|
|
Packit |
78deda |
double bt709;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (i < linearCutoffSrgb / linearCompressionSrgb)
|
|
Packit |
78deda |
radiance = normalized * linearCompressionSrgb;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
radiance = pow((normalized + 0.099) / 1.099, gammaSrgb);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(radiance <= 1.0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (radiance < linearCutoff709 * normalizer)
|
|
Packit |
78deda |
bt709 = radiance * linearExpansion709;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
bt709 = 1.055 * pow(normalized, oneOverGamma709) - 0.055;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
assert(bt709 <= 1.0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
table[i] = bt709 * newMaxval + 0.5;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
createGammaTables(enum transferFunction const transferFunction,
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
xelval const newMaxval,
|
|
Packit |
78deda |
double const rgamma,
|
|
Packit |
78deda |
double const ggamma,
|
|
Packit |
78deda |
double const bgamma,
|
|
Packit |
78deda |
xelval ** const rtableP,
|
|
Packit |
78deda |
xelval ** const gtableP,
|
|
Packit |
78deda |
xelval ** const btableP) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Allocate space for the tables. */
|
|
Packit |
38c941 |
overflow_add(maxval, 1);
|
|
Packit |
78deda |
MALLOCARRAY(*rtableP, maxval+1);
|
|
Packit |
78deda |
MALLOCARRAY(*gtableP, maxval+1);
|
|
Packit |
78deda |
MALLOCARRAY(*btableP, maxval+1);
|
|
Packit |
78deda |
if (*rtableP == NULL || *gtableP == NULL || *btableP == NULL)
|
|
Packit |
78deda |
pm_error("Can't get memory to make gamma transfer tables");
|
|
Packit |
78deda |
|
|
Packit |
78deda |
/* Build the gamma corection tables. */
|
|
Packit |
78deda |
switch (transferFunction) {
|
|
Packit |
78deda |
case XF_BT709RAMP: {
|
|
Packit |
78deda |
buildBt709Gamma(*rtableP, maxval, newMaxval, rgamma);
|
|
Packit |
78deda |
buildBt709Gamma(*gtableP, maxval, newMaxval, ggamma);
|
|
Packit |
78deda |
buildBt709Gamma(*btableP, maxval, newMaxval, bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case XF_BT709RAMP_INVERSE: {
|
|
Packit |
78deda |
buildBt709GammaInverse(*rtableP, maxval, newMaxval, rgamma);
|
|
Packit |
78deda |
buildBt709GammaInverse(*gtableP, maxval, newMaxval, ggamma);
|
|
Packit |
78deda |
buildBt709GammaInverse(*btableP, maxval, newMaxval, bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case XF_SRGBRAMP: {
|
|
Packit |
78deda |
buildSrgbGamma(*rtableP, maxval, newMaxval, rgamma);
|
|
Packit |
78deda |
buildSrgbGamma(*gtableP, maxval, newMaxval, ggamma);
|
|
Packit |
78deda |
buildSrgbGamma(*btableP, maxval, newMaxval, bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case XF_SRGBRAMP_INVERSE: {
|
|
Packit |
78deda |
buildSrgbGammaInverse(*rtableP, maxval, newMaxval, rgamma);
|
|
Packit |
78deda |
buildSrgbGammaInverse(*gtableP, maxval, newMaxval, ggamma);
|
|
Packit |
78deda |
buildSrgbGammaInverse(*btableP, maxval, newMaxval, bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case XF_EXP: {
|
|
Packit |
78deda |
buildPowGamma(*rtableP, maxval, newMaxval, rgamma);
|
|
Packit |
78deda |
buildPowGamma(*gtableP, maxval, newMaxval, ggamma);
|
|
Packit |
78deda |
buildPowGamma(*btableP, maxval, newMaxval, bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case XF_EXP_INVERSE: {
|
|
Packit |
78deda |
buildPowGamma(*rtableP, maxval, newMaxval, 1.0/rgamma);
|
|
Packit |
78deda |
buildPowGamma(*gtableP, maxval, newMaxval, 1.0/ggamma);
|
|
Packit |
78deda |
buildPowGamma(*btableP, maxval, newMaxval, 1.0/bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case XF_BT709_TO_SRGB: {
|
|
Packit |
78deda |
buildBt709ToSrgbGamma(*rtableP, maxval, newMaxval, rgamma);
|
|
Packit |
78deda |
buildBt709ToSrgbGamma(*gtableP, maxval, newMaxval, ggamma);
|
|
Packit |
78deda |
buildBt709ToSrgbGamma(*btableP, maxval, newMaxval, bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case XF_SRGB_TO_BT709: {
|
|
Packit |
78deda |
buildSrgbToBt709Gamma(*rtableP, maxval, newMaxval, rgamma);
|
|
Packit |
78deda |
buildSrgbToBt709Gamma(*gtableP, maxval, newMaxval, ggamma);
|
|
Packit |
78deda |
buildSrgbToBt709Gamma(*btableP, maxval, newMaxval, bgamma);
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
static void
|
|
Packit |
78deda |
convertRaster(FILE * const ifP,
|
|
Packit |
78deda |
FILE * const ofP,
|
|
Packit |
78deda |
int const cols,
|
|
Packit |
78deda |
int const rows,
|
|
Packit |
78deda |
xelval const maxval,
|
|
Packit |
78deda |
int const format,
|
|
Packit |
78deda |
xelval const outputMaxval,
|
|
Packit |
78deda |
int const outputFormat,
|
|
Packit |
78deda |
xelval * const rtable,
|
|
Packit |
78deda |
xelval * const gtable,
|
|
Packit |
78deda |
xelval * const btable) {
|
|
Packit |
78deda |
|
|
Packit |
78deda |
xel * xelrow;
|
|
Packit |
78deda |
unsigned int row;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
xelrow = pnm_allocrow(cols);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
for (row = 0; row < rows; ++row) {
|
|
Packit |
78deda |
pnm_readpnmrow(ifP, xelrow, cols, maxval, format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_promoteformatrow(xelrow, cols, maxval, format,
|
|
Packit |
78deda |
maxval, outputFormat);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
switch (PNM_FORMAT_TYPE(outputFormat)) {
|
|
Packit |
78deda |
case PPM_TYPE: {
|
|
Packit |
78deda |
unsigned int col;
|
|
Packit |
78deda |
for (col = 0; col < cols; ++col) {
|
|
Packit |
78deda |
xelval const r = PPM_GETR(xelrow[col]);
|
|
Packit |
78deda |
xelval const g = PPM_GETG(xelrow[col]);
|
|
Packit |
78deda |
xelval const b = PPM_GETB(xelrow[col]);
|
|
Packit |
78deda |
PPM_ASSIGN(xelrow[col], rtable[r], gtable[g], btable[b]);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
case PGM_TYPE: {
|
|
Packit |
78deda |
unsigned int col;
|
|
Packit |
78deda |
for (col = 0; col < cols; ++col) {
|
|
Packit |
78deda |
xelval const xel = PNM_GET1(xelrow[col]);
|
|
Packit |
78deda |
PNM_ASSIGN1(xelrow[col], gtable[xel]);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
} break;
|
|
Packit |
78deda |
default:
|
|
Packit |
78deda |
pm_error("Internal error. Impossible format type");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pnm_writepnmrow(ofP, xelrow, cols, outputMaxval, outputFormat, 0);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
pnm_freerow(xelrow);
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
|
|
Packit |
78deda |
int
|
|
Packit |
78deda |
main(int argc, char *argv[]) {
|
|
Packit |
78deda |
struct cmdlineInfo cmdline;
|
|
Packit |
78deda |
FILE * ifP;
|
|
Packit |
78deda |
xelval maxval;
|
|
Packit |
78deda |
int rows, cols, format;
|
|
Packit |
78deda |
xelval outputMaxval;
|
|
Packit |
78deda |
int outputFormat;
|
|
Packit |
78deda |
xelval * rtable;
|
|
Packit |
78deda |
xelval * gtable;
|
|
Packit |
78deda |
xelval * btable;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_init(&argc, argv);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
parseCommandLine(argc, argv, &cmdline);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
ifP = pm_openr(cmdline.filespec);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_readpnminit(ifP, &cols, &rows, &maxval, &format);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (PNM_FORMAT_TYPE(format) == PPM_TYPE)
|
|
Packit |
78deda |
outputFormat = PPM_TYPE;
|
|
Packit |
78deda |
else if (cmdline.rgamma != cmdline.ggamma
|
|
Packit |
78deda |
|| cmdline.ggamma != cmdline.bgamma)
|
|
Packit |
78deda |
outputFormat = PPM_TYPE;
|
|
Packit |
78deda |
else
|
|
Packit |
78deda |
outputFormat = PGM_TYPE;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
if (PNM_FORMAT_TYPE(format) != outputFormat) {
|
|
Packit |
78deda |
if (outputFormat == PPM_TYPE)
|
|
Packit |
78deda |
pm_message("Promoting to PPM");
|
|
Packit |
78deda |
if (outputFormat == PGM_TYPE)
|
|
Packit |
78deda |
pm_message("Promoting to PGM");
|
|
Packit |
78deda |
}
|
|
Packit |
78deda |
|
|
Packit |
78deda |
outputMaxval = cmdline.makeNewMaxval ? cmdline.maxval : maxval;
|
|
Packit |
78deda |
|
|
Packit |
78deda |
createGammaTables(cmdline.transferFunction, maxval,
|
|
Packit |
78deda |
outputMaxval,
|
|
Packit |
78deda |
cmdline.rgamma, cmdline.ggamma, cmdline.bgamma,
|
|
Packit |
78deda |
&rtable, >able, &btable);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pnm_writepnminit(stdout, cols, rows, outputMaxval, outputFormat, 0);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
convertRaster(ifP, stdout, cols, rows, maxval, format,
|
|
Packit |
78deda |
outputMaxval, outputFormat,
|
|
Packit |
78deda |
rtable, gtable, btable);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
pm_close(ifP);
|
|
Packit |
78deda |
pm_close(stdout);
|
|
Packit |
78deda |
|
|
Packit |
78deda |
return 0;
|
|
Packit |
78deda |
}
|