| 1 |
greg |
2.1 |
#ifndef lint
|
| 2 |
greg |
2.29 |
static const char RCSid[] = "$Id: macbethcal.c,v 2.28 2019/12/28 18:05:14 greg Exp $";
|
| 3 |
greg |
2.1 |
#endif
|
| 4 |
|
|
/*
|
| 5 |
|
|
* Calibrate a scanned MacBeth Color Checker Chart
|
| 6 |
|
|
*
|
| 7 |
greg |
2.14 |
* Produce a .cal file suitable for use with pcomb,
|
| 8 |
|
|
* or .cwp file suitable for use with pcwarp.
|
| 9 |
|
|
*
|
| 10 |
|
|
* Warping code depends on conformance of COLOR and W3VEC types.
|
| 11 |
greg |
2.1 |
*/
|
| 12 |
|
|
|
| 13 |
greg |
2.14 |
#include <math.h>
|
| 14 |
schorsch |
2.18 |
|
| 15 |
|
|
#include "platform.h"
|
| 16 |
greg |
2.27 |
#include "paths.h"
|
| 17 |
schorsch |
2.23 |
#include "rtio.h"
|
| 18 |
greg |
2.1 |
#include "color.h"
|
| 19 |
|
|
#include "resolu.h"
|
| 20 |
|
|
#include "pmap.h"
|
| 21 |
greg |
2.14 |
#include "warp3d.h"
|
| 22 |
schorsch |
2.23 |
#include "mx3.h"
|
| 23 |
greg |
2.1 |
|
| 24 |
greg |
2.4 |
/* MacBeth colors */
|
| 25 |
|
|
#define DarkSkin 0
|
| 26 |
|
|
#define LightSkin 1
|
| 27 |
|
|
#define BlueSky 2
|
| 28 |
|
|
#define Foliage 3
|
| 29 |
|
|
#define BlueFlower 4
|
| 30 |
|
|
#define BluishGreen 5
|
| 31 |
|
|
#define Orange 6
|
| 32 |
|
|
#define PurplishBlue 7
|
| 33 |
|
|
#define ModerateRed 8
|
| 34 |
|
|
#define Purple 9
|
| 35 |
|
|
#define YellowGreen 10
|
| 36 |
|
|
#define OrangeYellow 11
|
| 37 |
|
|
#define Blue 12
|
| 38 |
|
|
#define Green 13
|
| 39 |
|
|
#define Red 14
|
| 40 |
|
|
#define Yellow 15
|
| 41 |
|
|
#define Magenta 16
|
| 42 |
|
|
#define Cyan 17
|
| 43 |
|
|
#define White 18
|
| 44 |
|
|
#define Neutral8 19
|
| 45 |
|
|
#define Neutral65 20
|
| 46 |
|
|
#define Neutral5 21
|
| 47 |
|
|
#define Neutral35 22
|
| 48 |
|
|
#define Black 23
|
| 49 |
greg |
2.26 |
/* computed from 10nm spectral measurements */
|
| 50 |
greg |
2.4 |
/* CIE 1931 2 degree obs, equal-energy white */
|
| 51 |
greg |
2.1 |
float mbxyY[24][3] = {
|
| 52 |
greg |
2.26 |
{0.421236, 0.361196, 0.103392}, /* DarkSkin */
|
| 53 |
|
|
{0.40868, 0.358157, 0.352867}, /* LightSkin */
|
| 54 |
|
|
{0.265063, 0.271424, 0.185124}, /* BlueSky */
|
| 55 |
|
|
{0.362851, 0.43055, 0.132625}, /* Foliage */
|
| 56 |
|
|
{0.28888, 0.260851, 0.233138}, /* BlueFlower */
|
| 57 |
|
|
{0.277642, 0.365326, 0.416443}, /* BluishGreen */
|
| 58 |
|
|
{0.524965, 0.40068, 0.312039}, /* Orange */
|
| 59 |
|
|
{0.225018, 0.190392, 0.114999}, /* PurplishBlue */
|
| 60 |
|
|
{0.487199, 0.315372, 0.198616}, /* ModerateRed */
|
| 61 |
|
|
{0.314245, 0.227231, 0.0646047}, /* Purple */
|
| 62 |
|
|
{0.396202, 0.489732, 0.440724}, /* YellowGreen */
|
| 63 |
|
|
{0.493297, 0.435299, 0.43444}, /* OrangeYellow */
|
| 64 |
|
|
{0.198191, 0.149265, 0.0588122}, /* Blue */
|
| 65 |
|
|
{0.322838, 0.487601, 0.229258}, /* Green */
|
| 66 |
|
|
{0.561833, 0.321165, 0.126978}, /* Red */
|
| 67 |
|
|
{0.468113, 0.467021, 0.605289}, /* Yellow */
|
| 68 |
|
|
{0.397128, 0.248535, 0.201761}, /* Magenta */
|
| 69 |
|
|
{0.209552, 0.276256, 0.190917}, /* Cyan */
|
| 70 |
|
|
{0.337219, 0.339042, 0.912482}, /* White */
|
| 71 |
|
|
{0.333283, 0.335077, 0.588297}, /* Neutral.8 */
|
| 72 |
|
|
{0.332747, 0.334371, 0.3594}, /* Neutral.65 */
|
| 73 |
|
|
{0.331925, 0.334202, 0.19114}, /* Neutral.5 */
|
| 74 |
|
|
{0.330408, 0.332615, 0.0892964}, /* Neutral.35 */
|
| 75 |
|
|
{0.331841, 0.331405, 0.0319541}, /* Black */
|
| 76 |
greg |
2.1 |
};
|
| 77 |
|
|
|
| 78 |
|
|
COLOR mbRGB[24]; /* MacBeth RGB values */
|
| 79 |
|
|
|
| 80 |
|
|
#define NMBNEU 6 /* Number of MacBeth neutral colors */
|
| 81 |
greg |
2.4 |
short mbneu[NMBNEU] = {Black,Neutral35,Neutral5,Neutral65,Neutral8,White};
|
| 82 |
greg |
2.1 |
|
| 83 |
greg |
2.8 |
#define NEUFLGS (1L<<White|1L<<Neutral8|1L<<Neutral65| \
|
| 84 |
|
|
1L<<Neutral5|1L<<Neutral35|1L<<Black)
|
| 85 |
greg |
2.4 |
|
| 86 |
greg |
2.8 |
#define SATFLGS (1L<<Red|1L<<Green|1L<<Blue|1L<<Magenta|1L<<Yellow| \
|
| 87 |
|
|
1L<<Cyan|1L<<Orange|1L<<Purple|1L<<PurplishBlue| \
|
| 88 |
|
|
1L<<YellowGreen|1<<OrangeYellow|1L<<BlueFlower)
|
| 89 |
greg |
2.4 |
|
| 90 |
greg |
2.8 |
#define UNSFLGS (1L<<DarkSkin|1L<<LightSkin|1L<<BlueSky|1L<<Foliage| \
|
| 91 |
|
|
1L<<BluishGreen|1L<<ModerateRed)
|
| 92 |
greg |
2.7 |
|
| 93 |
greg |
2.8 |
#define REQFLGS NEUFLGS /* need these colors */
|
| 94 |
|
|
#define MODFLGS (NEUFLGS|UNSFLGS) /* should be in gamut */
|
| 95 |
|
|
|
| 96 |
greg |
2.9 |
#define RG_BORD 0 /* patch border */
|
| 97 |
|
|
#define RG_CENT 01 /* central region of patch */
|
| 98 |
|
|
#define RG_ORIG 02 /* original color region */
|
| 99 |
|
|
#define RG_CORR 04 /* corrected color region */
|
| 100 |
greg |
2.7 |
|
| 101 |
gwlarson |
2.16 |
#ifndef DISPCOM
|
| 102 |
greg |
2.29 |
#define DISPCOM "ximage -e auto -op \"%s\""
|
| 103 |
gwlarson |
2.16 |
#endif
|
| 104 |
|
|
|
| 105 |
greg |
2.11 |
int scanning = 1; /* scanned input (or recorded output)? */
|
| 106 |
greg |
2.14 |
double irrad = 1.0; /* irradiance multiplication factor */
|
| 107 |
|
|
int rawmap = 0; /* put out raw color mapping? */
|
| 108 |
greg |
2.11 |
|
| 109 |
greg |
2.1 |
int xmax, ymax; /* input image dimensions */
|
| 110 |
|
|
int bounds[4][2]; /* image coordinates of chart corners */
|
| 111 |
|
|
double imgxfm[3][3]; /* coordinate transformation matrix */
|
| 112 |
|
|
|
| 113 |
greg |
2.7 |
COLOR inpRGB[24]; /* measured or scanned input colors */
|
| 114 |
|
|
long inpflags = 0; /* flags of which colors were input */
|
| 115 |
greg |
2.8 |
long gmtflags = 0; /* flags of out-of-gamut colors */
|
| 116 |
greg |
2.1 |
|
| 117 |
greg |
2.2 |
COLOR bramp[NMBNEU][2]; /* brightness ramp (per primary) */
|
| 118 |
greg |
2.13 |
COLORMAT solmat; /* color mapping matrix */
|
| 119 |
|
|
COLOR colmin, colmax; /* gamut limits */
|
| 120 |
greg |
2.1 |
|
| 121 |
greg |
2.14 |
WARP3D *wcor = NULL; /* color space warp */
|
| 122 |
|
|
|
| 123 |
greg |
2.4 |
FILE *debugfp = NULL; /* debug output picture */
|
| 124 |
greg |
2.1 |
char *progname;
|
| 125 |
|
|
|
| 126 |
schorsch |
2.23 |
static void init(void);
|
| 127 |
|
|
static int chartndx(int x, int y, int *np);
|
| 128 |
|
|
static void getpicture(void);
|
| 129 |
|
|
static void getcolors(void);
|
| 130 |
|
|
static void bresp(COLOR y, COLOR x);
|
| 131 |
|
|
static void compute(void);
|
| 132 |
|
|
static void putmapping(void);
|
| 133 |
|
|
static void compsoln(COLOR cin[], COLOR cout[], int n);
|
| 134 |
|
|
static void cwarp(void);
|
| 135 |
|
|
static int cvtcolor(COLOR cout, COLOR cin);
|
| 136 |
|
|
static int cresp(COLOR cout, COLOR cin);
|
| 137 |
|
|
static void xyY2RGB(COLOR rgbout, float xyYin[3]);
|
| 138 |
|
|
static void picdebug(void);
|
| 139 |
|
|
static void clrdebug(void);
|
| 140 |
|
|
static void getpos(char *name, int bnds[2], FILE *fp);
|
| 141 |
|
|
static void pickchartpos(char *pfn);
|
| 142 |
greg |
2.1 |
|
| 143 |
schorsch |
2.23 |
|
| 144 |
|
|
int
|
| 145 |
|
|
main(
|
| 146 |
|
|
int argc,
|
| 147 |
|
|
char **argv
|
| 148 |
|
|
)
|
| 149 |
greg |
2.1 |
{
|
| 150 |
|
|
int i;
|
| 151 |
|
|
|
| 152 |
|
|
progname = argv[0];
|
| 153 |
greg |
2.7 |
for (i = 1; i < argc && argv[i][0] == '-'; i++)
|
| 154 |
|
|
switch (argv[i][1]) {
|
| 155 |
|
|
case 'd': /* debug output */
|
| 156 |
|
|
i++;
|
| 157 |
|
|
if (badarg(argc-i, argv+i, "s"))
|
| 158 |
|
|
goto userr;
|
| 159 |
|
|
if ((debugfp = fopen(argv[i], "w")) == NULL) {
|
| 160 |
|
|
perror(argv[i]);
|
| 161 |
|
|
exit(1);
|
| 162 |
|
|
}
|
| 163 |
schorsch |
2.18 |
SET_FILE_BINARY(debugfp);
|
| 164 |
greg |
2.7 |
newheader("RADIANCE", debugfp); /* start */
|
| 165 |
|
|
printargs(argc, argv, debugfp); /* header */
|
| 166 |
|
|
break;
|
| 167 |
|
|
case 'p': /* picture position */
|
| 168 |
|
|
if (badarg(argc-i-1, argv+i+1, "iiiiiiii"))
|
| 169 |
|
|
goto userr;
|
| 170 |
|
|
bounds[0][0] = atoi(argv[++i]);
|
| 171 |
|
|
bounds[0][1] = atoi(argv[++i]);
|
| 172 |
|
|
bounds[1][0] = atoi(argv[++i]);
|
| 173 |
|
|
bounds[1][1] = atoi(argv[++i]);
|
| 174 |
|
|
bounds[2][0] = atoi(argv[++i]);
|
| 175 |
|
|
bounds[2][1] = atoi(argv[++i]);
|
| 176 |
|
|
bounds[3][0] = atoi(argv[++i]);
|
| 177 |
|
|
bounds[3][1] = atoi(argv[++i]);
|
| 178 |
greg |
2.11 |
scanning = 2;
|
| 179 |
greg |
2.7 |
break;
|
| 180 |
gwlarson |
2.16 |
case 'P': /* pick position */
|
| 181 |
|
|
scanning = 3;
|
| 182 |
|
|
break;
|
| 183 |
greg |
2.14 |
case 'i': /* irradiance factor */
|
| 184 |
|
|
i++;
|
| 185 |
|
|
if (badarg(argc-i, argv+i, "f"))
|
| 186 |
|
|
goto userr;
|
| 187 |
|
|
irrad = atof(argv[i]);
|
| 188 |
|
|
break;
|
| 189 |
|
|
case 'm': /* raw map output */
|
| 190 |
|
|
rawmap = 1;
|
| 191 |
|
|
break;
|
| 192 |
greg |
2.7 |
case 'c': /* color input */
|
| 193 |
greg |
2.11 |
scanning = 0;
|
| 194 |
greg |
2.7 |
break;
|
| 195 |
|
|
default:
|
| 196 |
|
|
goto userr;
|
| 197 |
|
|
}
|
| 198 |
|
|
/* open files */
|
| 199 |
|
|
if (i < argc && freopen(argv[i], "r", stdin) == NULL) {
|
| 200 |
greg |
2.13 |
perror(argv[i]);
|
| 201 |
greg |
2.1 |
exit(1);
|
| 202 |
|
|
}
|
| 203 |
greg |
2.7 |
if (i+1 < argc && freopen(argv[i+1], "w", stdout) == NULL) {
|
| 204 |
greg |
2.13 |
perror(argv[i+1]);
|
| 205 |
greg |
2.1 |
exit(1);
|
| 206 |
|
|
}
|
| 207 |
greg |
2.11 |
if (scanning) { /* load input picture header */
|
| 208 |
schorsch |
2.18 |
SET_FILE_BINARY(stdin);
|
| 209 |
greg |
2.7 |
if (checkheader(stdin, COLRFMT, NULL) < 0 ||
|
| 210 |
|
|
fgetresolu(&xmax, &ymax, stdin) < 0) {
|
| 211 |
|
|
fprintf(stderr, "%s: bad input picture\n", progname);
|
| 212 |
|
|
exit(1);
|
| 213 |
|
|
}
|
| 214 |
gwlarson |
2.16 |
if (scanning == 3) {
|
| 215 |
|
|
if (i >= argc)
|
| 216 |
|
|
goto userr;
|
| 217 |
|
|
pickchartpos(argv[i]);
|
| 218 |
|
|
scanning = 2;
|
| 219 |
|
|
}
|
| 220 |
greg |
2.7 |
} else { /* else set default xmax and ymax */
|
| 221 |
|
|
xmax = 512;
|
| 222 |
|
|
ymax = 2*512/3;
|
| 223 |
greg |
2.1 |
}
|
| 224 |
greg |
2.11 |
if (scanning != 2) { /* use default boundaries */
|
| 225 |
greg |
2.1 |
bounds[0][0] = bounds[2][0] = .029*xmax + .5;
|
| 226 |
|
|
bounds[0][1] = bounds[1][1] = .956*ymax + .5;
|
| 227 |
|
|
bounds[1][0] = bounds[3][0] = .971*xmax + .5;
|
| 228 |
|
|
bounds[2][1] = bounds[3][1] = .056*ymax + .5;
|
| 229 |
|
|
}
|
| 230 |
|
|
init(); /* initialize */
|
| 231 |
greg |
2.11 |
if (scanning) /* get picture colors */
|
| 232 |
greg |
2.7 |
getpicture();
|
| 233 |
|
|
else
|
| 234 |
|
|
getcolors();
|
| 235 |
greg |
2.2 |
compute(); /* compute color mapping */
|
| 236 |
greg |
2.14 |
if (rawmap) { /* print out raw correspondence */
|
| 237 |
greg |
2.29 |
int j;
|
| 238 |
greg |
2.14 |
|
| 239 |
|
|
printf("# Color correspondence produced by:\n#\t\t");
|
| 240 |
|
|
printargs(argc, argv, stdout);
|
| 241 |
greg |
2.25 |
printf("#\tUsage: pcwarp %s uncorrected.hdr > corrected.hdr\n",
|
| 242 |
greg |
2.11 |
i+1 < argc ? argv[i+1] : "{this_file}");
|
| 243 |
greg |
2.25 |
printf("#\t Or: pcond [options] -m %s orig.hdr > output.hdr\n",
|
| 244 |
greg |
2.14 |
i+1 < argc ? argv[i+1] : "{this_file}");
|
| 245 |
|
|
for (j = 0; j < 24; j++)
|
| 246 |
|
|
printf("%f %f %f %f %f %f\n",
|
| 247 |
|
|
colval(inpRGB[j],RED), colval(inpRGB[j],GRN),
|
| 248 |
|
|
colval(inpRGB[j],BLU), colval(mbRGB[j],RED),
|
| 249 |
|
|
colval(mbRGB[j],GRN), colval(mbRGB[j],BLU));
|
| 250 |
|
|
if (scanning && debugfp != NULL)
|
| 251 |
|
|
cwarp(); /* color warp for debugging */
|
| 252 |
|
|
} else { /* print color mapping */
|
| 253 |
|
|
/* print header */
|
| 254 |
|
|
printf("{\n\tColor correction file computed by:\n\t\t");
|
| 255 |
|
|
printargs(argc, argv, stdout);
|
| 256 |
greg |
2.25 |
printf("\n\tUsage: pcomb -f %s uncorrected.hdr > corrected.hdr\n",
|
| 257 |
greg |
2.14 |
i+1 < argc ? argv[i+1] : "{this_file}");
|
| 258 |
|
|
if (!scanning)
|
| 259 |
greg |
2.25 |
printf("\t Or: pcond [options] -f %s orig.hdr > output.hdr\n",
|
| 260 |
greg |
2.14 |
i+1 < argc ? argv[i+1] : "{this_file}");
|
| 261 |
|
|
printf("}\n");
|
| 262 |
|
|
putmapping(); /* put out color mapping */
|
| 263 |
|
|
}
|
| 264 |
schorsch |
2.19 |
if (debugfp != NULL) { /* put out debug picture */
|
| 265 |
greg |
2.11 |
if (scanning)
|
| 266 |
greg |
2.7 |
picdebug();
|
| 267 |
|
|
else
|
| 268 |
|
|
clrdebug();
|
| 269 |
schorsch |
2.19 |
}
|
| 270 |
greg |
2.1 |
exit(0);
|
| 271 |
|
|
userr:
|
| 272 |
greg |
2.7 |
fprintf(stderr,
|
| 273 |
greg |
2.25 |
"Usage: %s [-d dbg.hdr][-P | -p xul yul xur yur xll yll xlr ylr][-i irrad][-m] input.hdr [output.{cal|cwp}]\n",
|
| 274 |
greg |
2.1 |
progname);
|
| 275 |
greg |
2.25 |
fprintf(stderr, " or: %s [-d dbg.hdr][-i irrad][-m] -c [xyY.dat [output.{cal|cwp}]]\n",
|
| 276 |
greg |
2.7 |
progname);
|
| 277 |
greg |
2.1 |
exit(1);
|
| 278 |
schorsch |
2.23 |
return 1; /* pro forma return */
|
| 279 |
greg |
2.1 |
}
|
| 280 |
|
|
|
| 281 |
|
|
|
| 282 |
schorsch |
2.23 |
static void
|
| 283 |
|
|
init(void) /* initialize */
|
| 284 |
greg |
2.1 |
{
|
| 285 |
|
|
double quad[4][2];
|
| 286 |
greg |
2.29 |
int i;
|
| 287 |
greg |
2.1 |
/* make coordinate transformation */
|
| 288 |
|
|
quad[0][0] = bounds[0][0];
|
| 289 |
|
|
quad[0][1] = bounds[0][1];
|
| 290 |
|
|
quad[1][0] = bounds[1][0];
|
| 291 |
|
|
quad[1][1] = bounds[1][1];
|
| 292 |
|
|
quad[2][0] = bounds[3][0];
|
| 293 |
|
|
quad[2][1] = bounds[3][1];
|
| 294 |
|
|
quad[3][0] = bounds[2][0];
|
| 295 |
|
|
quad[3][1] = bounds[2][1];
|
| 296 |
|
|
|
| 297 |
|
|
if (pmap_quad_rect(0., 0., 6., 4., quad, imgxfm) == PMAP_BAD) {
|
| 298 |
|
|
fprintf(stderr, "%s: bad chart boundaries\n", progname);
|
| 299 |
|
|
exit(1);
|
| 300 |
|
|
}
|
| 301 |
greg |
2.7 |
/* map MacBeth colors to RGB space */
|
| 302 |
greg |
2.14 |
for (i = 0; i < 24; i++) {
|
| 303 |
greg |
2.7 |
xyY2RGB(mbRGB[i], mbxyY[i]);
|
| 304 |
greg |
2.14 |
scalecolor(mbRGB[i], irrad);
|
| 305 |
|
|
}
|
| 306 |
greg |
2.1 |
}
|
| 307 |
|
|
|
| 308 |
|
|
|
| 309 |
schorsch |
2.23 |
static int
|
| 310 |
|
|
chartndx( /* find color number for position */
|
| 311 |
|
|
int x,
|
| 312 |
|
|
int y,
|
| 313 |
|
|
int *np
|
| 314 |
|
|
)
|
| 315 |
greg |
2.1 |
{
|
| 316 |
|
|
double ipos[3], cpos[3];
|
| 317 |
|
|
int ix, iy;
|
| 318 |
|
|
double fx, fy;
|
| 319 |
|
|
|
| 320 |
|
|
ipos[0] = x;
|
| 321 |
|
|
ipos[1] = y;
|
| 322 |
|
|
ipos[2] = 1;
|
| 323 |
|
|
mx3d_transform(ipos, imgxfm, cpos);
|
| 324 |
|
|
cpos[0] /= cpos[2];
|
| 325 |
|
|
cpos[1] /= cpos[2];
|
| 326 |
greg |
2.29 |
if ((cpos[0] < 0.) | (cpos[0] >= 6.) | (cpos[1] < 0.) | (cpos[1] >= 4.))
|
| 327 |
greg |
2.9 |
return(RG_BORD);
|
| 328 |
greg |
2.1 |
ix = cpos[0];
|
| 329 |
|
|
iy = cpos[1];
|
| 330 |
|
|
fx = cpos[0] - ix;
|
| 331 |
|
|
fy = cpos[1] - iy;
|
| 332 |
greg |
2.9 |
*np = iy*6 + ix;
|
| 333 |
greg |
2.29 |
if ((fx >= 0.35) & (fx < 0.65) & (fy >= 0.35) & (fy < 0.65))
|
| 334 |
greg |
2.9 |
return(RG_CENT);
|
| 335 |
greg |
2.29 |
if ((fx < 0.05) | (fx >= 0.95) | (fy < 0.05) | (fy >= 0.95))
|
| 336 |
greg |
2.9 |
return(RG_BORD);
|
| 337 |
|
|
if (fx >= 0.5) /* right side is corrected */
|
| 338 |
|
|
return(RG_CORR);
|
| 339 |
|
|
return(RG_ORIG); /* left side is original */
|
| 340 |
greg |
2.1 |
}
|
| 341 |
|
|
|
| 342 |
|
|
|
| 343 |
schorsch |
2.23 |
static void
|
| 344 |
|
|
getpicture(void) /* load in picture colors */
|
| 345 |
greg |
2.1 |
{
|
| 346 |
|
|
COLR *scanln;
|
| 347 |
|
|
COLOR pval;
|
| 348 |
|
|
int ccount[24];
|
| 349 |
|
|
double d;
|
| 350 |
greg |
2.9 |
int y, i;
|
| 351 |
greg |
2.29 |
int x;
|
| 352 |
greg |
2.1 |
|
| 353 |
|
|
scanln = (COLR *)malloc(xmax*sizeof(COLR));
|
| 354 |
|
|
if (scanln == NULL) {
|
| 355 |
|
|
perror(progname);
|
| 356 |
|
|
exit(1);
|
| 357 |
|
|
}
|
| 358 |
|
|
for (i = 0; i < 24; i++) {
|
| 359 |
greg |
2.7 |
setcolor(inpRGB[i], 0., 0., 0.);
|
| 360 |
greg |
2.1 |
ccount[i] = 0;
|
| 361 |
|
|
}
|
| 362 |
|
|
for (y = ymax-1; y >= 0; y--) {
|
| 363 |
|
|
if (freadcolrs(scanln, xmax, stdin) < 0) {
|
| 364 |
|
|
fprintf(stderr, "%s: error reading input picture\n",
|
| 365 |
|
|
progname);
|
| 366 |
|
|
exit(1);
|
| 367 |
|
|
}
|
| 368 |
greg |
2.9 |
for (x = 0; x < xmax; x++)
|
| 369 |
|
|
if (chartndx(x, y, &i) == RG_CENT) {
|
| 370 |
greg |
2.1 |
colr_color(pval, scanln[x]);
|
| 371 |
greg |
2.7 |
addcolor(inpRGB[i], pval);
|
| 372 |
greg |
2.1 |
ccount[i]++;
|
| 373 |
|
|
}
|
| 374 |
|
|
}
|
| 375 |
greg |
2.7 |
for (i = 0; i < 24; i++) { /* compute averages */
|
| 376 |
|
|
if (ccount[i] == 0)
|
| 377 |
|
|
continue;
|
| 378 |
|
|
d = 1./ccount[i];
|
| 379 |
|
|
scalecolor(inpRGB[i], d);
|
| 380 |
|
|
inpflags |= 1L<<i;
|
| 381 |
|
|
}
|
| 382 |
greg |
2.17 |
free((void *)scanln);
|
| 383 |
greg |
2.7 |
}
|
| 384 |
|
|
|
| 385 |
|
|
|
| 386 |
schorsch |
2.23 |
static void
|
| 387 |
|
|
getcolors(void) /* get xyY colors from standard input */
|
| 388 |
greg |
2.7 |
{
|
| 389 |
|
|
int gotwhite = 0;
|
| 390 |
|
|
COLOR whiteclr;
|
| 391 |
|
|
int n;
|
| 392 |
|
|
float xyYin[3];
|
| 393 |
|
|
|
| 394 |
|
|
while (fgetval(stdin, 'i', &n) == 1) { /* read colors */
|
| 395 |
schorsch |
2.20 |
if ((n < 0) | (n > 24) ||
|
| 396 |
greg |
2.7 |
fgetval(stdin, 'f', &xyYin[0]) != 1 ||
|
| 397 |
|
|
fgetval(stdin, 'f', &xyYin[1]) != 1 ||
|
| 398 |
|
|
fgetval(stdin, 'f', &xyYin[2]) != 1 ||
|
| 399 |
schorsch |
2.20 |
(xyYin[0] < 0.) | (xyYin[1] < 0.) ||
|
| 400 |
greg |
2.12 |
xyYin[0] + xyYin[1] > 1.) {
|
| 401 |
greg |
2.7 |
fprintf(stderr, "%s: bad color input data\n",
|
| 402 |
greg |
2.1 |
progname);
|
| 403 |
|
|
exit(1);
|
| 404 |
|
|
}
|
| 405 |
greg |
2.7 |
if (n == 0) { /* calibration white */
|
| 406 |
|
|
xyY2RGB(whiteclr, xyYin);
|
| 407 |
|
|
gotwhite++;
|
| 408 |
|
|
} else { /* standard color */
|
| 409 |
|
|
n--;
|
| 410 |
|
|
xyY2RGB(inpRGB[n], xyYin);
|
| 411 |
|
|
inpflags |= 1L<<n;
|
| 412 |
|
|
}
|
| 413 |
greg |
2.1 |
}
|
| 414 |
greg |
2.7 |
/* normalize colors */
|
| 415 |
|
|
if (!gotwhite) {
|
| 416 |
|
|
if (!(inpflags & 1L<<White)) {
|
| 417 |
|
|
fprintf(stderr, "%s: missing input for White\n",
|
| 418 |
|
|
progname);
|
| 419 |
|
|
exit(1);
|
| 420 |
|
|
}
|
| 421 |
|
|
setcolor(whiteclr,
|
| 422 |
|
|
colval(inpRGB[White],RED)/colval(mbRGB[White],RED),
|
| 423 |
|
|
colval(inpRGB[White],GRN)/colval(mbRGB[White],GRN),
|
| 424 |
|
|
colval(inpRGB[White],BLU)/colval(mbRGB[White],BLU));
|
| 425 |
|
|
}
|
| 426 |
|
|
for (n = 0; n < 24; n++)
|
| 427 |
|
|
if (inpflags & 1L<<n)
|
| 428 |
|
|
setcolor(inpRGB[n],
|
| 429 |
|
|
colval(inpRGB[n],RED)/colval(whiteclr,RED),
|
| 430 |
|
|
colval(inpRGB[n],GRN)/colval(whiteclr,GRN),
|
| 431 |
|
|
colval(inpRGB[n],BLU)/colval(whiteclr,BLU));
|
| 432 |
greg |
2.1 |
}
|
| 433 |
|
|
|
| 434 |
|
|
|
| 435 |
schorsch |
2.23 |
static void
|
| 436 |
|
|
bresp( /* piecewise linear interpolation of primaries */
|
| 437 |
|
|
COLOR y,
|
| 438 |
|
|
COLOR x
|
| 439 |
|
|
)
|
| 440 |
greg |
2.1 |
{
|
| 441 |
greg |
2.29 |
int i, n;
|
| 442 |
greg |
2.1 |
|
| 443 |
greg |
2.2 |
for (i = 0; i < 3; i++) {
|
| 444 |
greg |
2.5 |
for (n = 0; n < NMBNEU-2; n++)
|
| 445 |
|
|
if (colval(x,i) < colval(bramp[n+1][0],i))
|
| 446 |
|
|
break;
|
| 447 |
greg |
2.8 |
colval(y,i) = ((colval(bramp[n+1][0],i) - colval(x,i)) *
|
| 448 |
greg |
2.2 |
colval(bramp[n][1],i) +
|
| 449 |
|
|
(colval(x,i) - colval(bramp[n][0],i)) *
|
| 450 |
|
|
colval(bramp[n+1][1],i)) /
|
| 451 |
|
|
(colval(bramp[n+1][0],i) - colval(bramp[n][0],i));
|
| 452 |
|
|
}
|
| 453 |
greg |
2.1 |
}
|
| 454 |
|
|
|
| 455 |
|
|
|
| 456 |
schorsch |
2.23 |
static void
|
| 457 |
|
|
compute(void) /* compute color mapping */
|
| 458 |
greg |
2.1 |
{
|
| 459 |
greg |
2.8 |
COLOR clrin[24], clrout[24];
|
| 460 |
|
|
long cflags;
|
| 461 |
|
|
COLOR ctmp;
|
| 462 |
greg |
2.29 |
int i, n;
|
| 463 |
greg |
2.7 |
/* did we get what we need? */
|
| 464 |
|
|
if ((inpflags & REQFLGS) != REQFLGS) {
|
| 465 |
|
|
fprintf(stderr, "%s: missing required input colors\n",
|
| 466 |
|
|
progname);
|
| 467 |
|
|
exit(1);
|
| 468 |
greg |
2.2 |
}
|
| 469 |
greg |
2.1 |
/* compute piecewise luminance curve */
|
| 470 |
|
|
for (i = 0; i < NMBNEU; i++) {
|
| 471 |
greg |
2.7 |
copycolor(bramp[i][0], inpRGB[mbneu[i]]);
|
| 472 |
greg |
2.29 |
for (n = 3*(i>0); n--; )
|
| 473 |
greg |
2.24 |
if (colval(bramp[i][0],n) <=
|
| 474 |
|
|
colval(bramp[i-1][0],n)+1e-7) {
|
| 475 |
|
|
fprintf(stderr,
|
| 476 |
|
|
"%s: non-increasing neutral patch\n", progname);
|
| 477 |
|
|
exit(1);
|
| 478 |
|
|
}
|
| 479 |
greg |
2.2 |
copycolor(bramp[i][1], mbRGB[mbneu[i]]);
|
| 480 |
greg |
2.1 |
}
|
| 481 |
greg |
2.13 |
/* compute color space gamut */
|
| 482 |
|
|
if (scanning) {
|
| 483 |
|
|
copycolor(colmin, cblack);
|
| 484 |
|
|
copycolor(colmax, cwhite);
|
| 485 |
greg |
2.14 |
scalecolor(colmax, irrad);
|
| 486 |
greg |
2.13 |
} else
|
| 487 |
|
|
for (i = 0; i < 3; i++) {
|
| 488 |
|
|
colval(colmin,i) = colval(bramp[0][0],i) -
|
| 489 |
|
|
colval(bramp[0][1],i) *
|
| 490 |
|
|
(colval(bramp[1][0],i)-colval(bramp[0][0],i)) /
|
| 491 |
greg |
2.29 |
(colval(bramp[1][1],i)-colval(bramp[0][1],i));
|
| 492 |
greg |
2.13 |
colval(colmax,i) = colval(bramp[NMBNEU-2][0],i) +
|
| 493 |
|
|
(1.-colval(bramp[NMBNEU-2][1],i)) *
|
| 494 |
|
|
(colval(bramp[NMBNEU-1][0],i) -
|
| 495 |
|
|
colval(bramp[NMBNEU-2][0],i)) /
|
| 496 |
|
|
(colval(bramp[NMBNEU-1][1],i) -
|
| 497 |
|
|
colval(bramp[NMBNEU-2][1],i));
|
| 498 |
|
|
}
|
| 499 |
greg |
2.8 |
/* compute color mapping */
|
| 500 |
|
|
do {
|
| 501 |
|
|
cflags = inpflags & ~gmtflags;
|
| 502 |
|
|
n = 0; /* compute transform matrix */
|
| 503 |
|
|
for (i = 0; i < 24; i++)
|
| 504 |
|
|
if (cflags & 1L<<i) {
|
| 505 |
|
|
bresp(clrin[n], inpRGB[i]);
|
| 506 |
|
|
copycolor(clrout[n], mbRGB[i]);
|
| 507 |
|
|
n++;
|
| 508 |
|
|
}
|
| 509 |
|
|
compsoln(clrin, clrout, n);
|
| 510 |
greg |
2.29 |
for (i = 0; i < 24; i++) /* check gamut */
|
| 511 |
|
|
if (cflags & 1L<<i && cvtcolor(ctmp, inpRGB[i]))
|
| 512 |
|
|
gmtflags |= 1L<<i;
|
| 513 |
greg |
2.8 |
} while (cflags & gmtflags);
|
| 514 |
|
|
if (gmtflags & MODFLGS)
|
| 515 |
|
|
fprintf(stderr,
|
| 516 |
|
|
"%s: warning - some moderate colors are out of gamut\n",
|
| 517 |
|
|
progname);
|
| 518 |
greg |
2.2 |
}
|
| 519 |
|
|
|
| 520 |
|
|
|
| 521 |
schorsch |
2.23 |
static void
|
| 522 |
|
|
putmapping(void) /* put out color mapping */
|
| 523 |
greg |
2.2 |
{
|
| 524 |
|
|
static char cchar[3] = {'r', 'g', 'b'};
|
| 525 |
greg |
2.29 |
int i, j;
|
| 526 |
greg |
2.1 |
/* print brightness mapping */
|
| 527 |
greg |
2.2 |
for (j = 0; j < 3; j++) {
|
| 528 |
|
|
printf("%cxa(i) : select(i", cchar[j]);
|
| 529 |
|
|
for (i = 0; i < NMBNEU; i++)
|
| 530 |
|
|
printf(",%g", colval(bramp[i][0],j));
|
| 531 |
|
|
printf(");\n");
|
| 532 |
|
|
printf("%cya(i) : select(i", cchar[j]);
|
| 533 |
|
|
for (i = 0; i < NMBNEU; i++)
|
| 534 |
|
|
printf(",%g", colval(bramp[i][1],j));
|
| 535 |
|
|
printf(");\n");
|
| 536 |
|
|
printf("%cfi(n) = if(n-%g, %d, if(%cxa(n+1)-%c, n, %cfi(n+1)));\n",
|
| 537 |
|
|
cchar[j], NMBNEU-1.5, NMBNEU-1, cchar[j],
|
| 538 |
|
|
cchar[j], cchar[j]);
|
| 539 |
|
|
printf("%cndx = %cfi(1);\n", cchar[j], cchar[j]);
|
| 540 |
greg |
2.11 |
printf("%c%c = ((%cxa(%cndx+1)-%c)*%cya(%cndx) + ",
|
| 541 |
|
|
cchar[j], scanning?'n':'o', cchar[j],
|
| 542 |
|
|
cchar[j], cchar[j], cchar[j], cchar[j]);
|
| 543 |
greg |
2.2 |
printf("(%c-%cxa(%cndx))*%cya(%cndx+1)) /\n",
|
| 544 |
|
|
cchar[j], cchar[j], cchar[j],
|
| 545 |
|
|
cchar[j], cchar[j]);
|
| 546 |
|
|
printf("\t\t(%cxa(%cndx+1) - %cxa(%cndx)) ;\n",
|
| 547 |
|
|
cchar[j], cchar[j], cchar[j], cchar[j]);
|
| 548 |
|
|
}
|
| 549 |
greg |
2.1 |
/* print color mapping */
|
| 550 |
greg |
2.11 |
if (scanning) {
|
| 551 |
|
|
printf("r = ri(1); g = gi(1); b = bi(1);\n");
|
| 552 |
|
|
printf("ro = %g*rn + %g*gn + %g*bn ;\n",
|
| 553 |
|
|
solmat[0][0], solmat[0][1], solmat[0][2]);
|
| 554 |
|
|
printf("go = %g*rn + %g*gn + %g*bn ;\n",
|
| 555 |
|
|
solmat[1][0], solmat[1][1], solmat[1][2]);
|
| 556 |
|
|
printf("bo = %g*rn + %g*gn + %g*bn ;\n",
|
| 557 |
|
|
solmat[2][0], solmat[2][1], solmat[2][2]);
|
| 558 |
|
|
} else {
|
| 559 |
|
|
printf("r1 = ri(1); g1 = gi(1); b1 = bi(1);\n");
|
| 560 |
|
|
printf("r = %g*r1 + %g*g1 + %g*b1 ;\n",
|
| 561 |
|
|
solmat[0][0], solmat[0][1], solmat[0][2]);
|
| 562 |
|
|
printf("g = %g*r1 + %g*g1 + %g*b1 ;\n",
|
| 563 |
|
|
solmat[1][0], solmat[1][1], solmat[1][2]);
|
| 564 |
|
|
printf("b = %g*r1 + %g*g1 + %g*b1 ;\n",
|
| 565 |
|
|
solmat[2][0], solmat[2][1], solmat[2][2]);
|
| 566 |
|
|
}
|
| 567 |
greg |
2.1 |
}
|
| 568 |
|
|
|
| 569 |
|
|
|
| 570 |
schorsch |
2.23 |
static void
|
| 571 |
|
|
compsoln( /* solve 3xN system using least-squares */
|
| 572 |
|
|
COLOR cin[],
|
| 573 |
|
|
COLOR cout[],
|
| 574 |
|
|
int n
|
| 575 |
|
|
)
|
| 576 |
greg |
2.1 |
{
|
| 577 |
|
|
extern double mx3d_adjoint(), fabs();
|
| 578 |
|
|
double mat[3][3], invmat[3][3];
|
| 579 |
|
|
double det;
|
| 580 |
|
|
double colv[3], rowv[3];
|
| 581 |
greg |
2.29 |
int i, j, k;
|
| 582 |
greg |
2.1 |
|
| 583 |
greg |
2.8 |
if (n < 3) {
|
| 584 |
|
|
fprintf(stderr, "%s: too few colors to match!\n", progname);
|
| 585 |
greg |
2.1 |
exit(1);
|
| 586 |
|
|
}
|
| 587 |
greg |
2.4 |
if (n == 3)
|
| 588 |
|
|
for (i = 0; i < 3; i++)
|
| 589 |
|
|
for (j = 0; j < 3; j++)
|
| 590 |
|
|
mat[i][j] = colval(cin[j],i);
|
| 591 |
|
|
else { /* compute A^t A */
|
| 592 |
|
|
for (i = 0; i < 3; i++)
|
| 593 |
|
|
for (j = i; j < 3; j++) {
|
| 594 |
|
|
mat[i][j] = 0.;
|
| 595 |
|
|
for (k = 0; k < n; k++)
|
| 596 |
|
|
mat[i][j] += colval(cin[k],i) *
|
| 597 |
|
|
colval(cin[k],j);
|
| 598 |
|
|
}
|
| 599 |
|
|
for (i = 1; i < 3; i++) /* using symmetry */
|
| 600 |
|
|
for (j = 0; j < i; j++)
|
| 601 |
|
|
mat[i][j] = mat[j][i];
|
| 602 |
|
|
}
|
| 603 |
greg |
2.1 |
det = mx3d_adjoint(mat, invmat);
|
| 604 |
|
|
if (fabs(det) < 1e-4) {
|
| 605 |
|
|
fprintf(stderr, "%s: cannot compute color mapping\n",
|
| 606 |
|
|
progname);
|
| 607 |
|
|
solmat[0][0] = solmat[1][1] = solmat[2][2] = 1.;
|
| 608 |
|
|
solmat[0][1] = solmat[0][2] = solmat[1][0] =
|
| 609 |
|
|
solmat[1][2] = solmat[2][0] = solmat[2][1] = 0.;
|
| 610 |
|
|
return;
|
| 611 |
|
|
}
|
| 612 |
|
|
for (i = 0; i < 3; i++)
|
| 613 |
|
|
for (j = 0; j < 3; j++)
|
| 614 |
|
|
invmat[i][j] /= det;
|
| 615 |
|
|
for (i = 0; i < 3; i++) {
|
| 616 |
greg |
2.4 |
if (n == 3)
|
| 617 |
|
|
for (j = 0; j < 3; j++)
|
| 618 |
|
|
colv[j] = colval(cout[j],i);
|
| 619 |
|
|
else
|
| 620 |
|
|
for (j = 0; j < 3; j++) {
|
| 621 |
|
|
colv[j] = 0.;
|
| 622 |
|
|
for (k = 0; k < n; k++)
|
| 623 |
|
|
colv[j] += colval(cout[k],i) *
|
| 624 |
|
|
colval(cin[k],j);
|
| 625 |
|
|
}
|
| 626 |
greg |
2.3 |
mx3d_transform(colv, invmat, rowv);
|
| 627 |
greg |
2.1 |
for (j = 0; j < 3; j++)
|
| 628 |
greg |
2.3 |
solmat[i][j] = rowv[j];
|
| 629 |
greg |
2.1 |
}
|
| 630 |
|
|
}
|
| 631 |
|
|
|
| 632 |
greg |
2.3 |
|
| 633 |
schorsch |
2.23 |
static void
|
| 634 |
|
|
cwarp(void) /* compute color warp map */
|
| 635 |
greg |
2.14 |
{
|
| 636 |
greg |
2.29 |
int i;
|
| 637 |
greg |
2.14 |
|
| 638 |
|
|
if ((wcor = new3dw(W3EXACT)) == NULL)
|
| 639 |
|
|
goto memerr;
|
| 640 |
|
|
for (i = 0; i < 24; i++)
|
| 641 |
|
|
if (!add3dpt(wcor, inpRGB[i], mbRGB[i]))
|
| 642 |
|
|
goto memerr;
|
| 643 |
|
|
return;
|
| 644 |
|
|
memerr:
|
| 645 |
|
|
perror(progname);
|
| 646 |
|
|
exit(1);
|
| 647 |
|
|
}
|
| 648 |
|
|
|
| 649 |
|
|
|
| 650 |
schorsch |
2.23 |
static int
|
| 651 |
|
|
cvtcolor( /* convert color according to our mapping */
|
| 652 |
|
|
COLOR cout,
|
| 653 |
|
|
COLOR cin
|
| 654 |
|
|
)
|
| 655 |
greg |
2.1 |
{
|
| 656 |
greg |
2.8 |
COLOR ctmp;
|
| 657 |
greg |
2.13 |
int clipped;
|
| 658 |
greg |
2.8 |
|
| 659 |
greg |
2.14 |
if (wcor != NULL) {
|
| 660 |
|
|
clipped = warp3d(cout, cin, wcor);
|
| 661 |
|
|
clipped |= clipgamut(cout,bright(cout),CGAMUT,colmin,colmax);
|
| 662 |
|
|
} else if (scanning) {
|
| 663 |
greg |
2.11 |
bresp(ctmp, cin);
|
| 664 |
greg |
2.13 |
clipped = cresp(cout, ctmp);
|
| 665 |
greg |
2.11 |
} else {
|
| 666 |
greg |
2.13 |
clipped = cresp(ctmp, cin);
|
| 667 |
greg |
2.11 |
bresp(cout, ctmp);
|
| 668 |
|
|
}
|
| 669 |
greg |
2.13 |
return(clipped);
|
| 670 |
greg |
2.8 |
}
|
| 671 |
|
|
|
| 672 |
|
|
|
| 673 |
schorsch |
2.23 |
static int
|
| 674 |
|
|
cresp( /* transform color according to matrix */
|
| 675 |
|
|
COLOR cout,
|
| 676 |
|
|
COLOR cin
|
| 677 |
|
|
)
|
| 678 |
greg |
2.8 |
{
|
| 679 |
greg |
2.13 |
colortrans(cout, solmat, cin);
|
| 680 |
|
|
return(clipgamut(cout, bright(cout), CGAMUT, colmin, colmax));
|
| 681 |
greg |
2.1 |
}
|
| 682 |
|
|
|
| 683 |
|
|
|
| 684 |
schorsch |
2.23 |
static void
|
| 685 |
|
|
xyY2RGB( /* convert xyY to RGB */
|
| 686 |
|
|
COLOR rgbout,
|
| 687 |
greg |
2.29 |
float xyYin[3]
|
| 688 |
schorsch |
2.23 |
)
|
| 689 |
greg |
2.1 |
{
|
| 690 |
greg |
2.7 |
COLOR ctmp;
|
| 691 |
|
|
double d;
|
| 692 |
|
|
|
| 693 |
|
|
d = xyYin[2] / xyYin[1];
|
| 694 |
|
|
ctmp[0] = xyYin[0] * d;
|
| 695 |
|
|
ctmp[1] = xyYin[2];
|
| 696 |
|
|
ctmp[2] = (1. - xyYin[0] - xyYin[1]) * d;
|
| 697 |
greg |
2.12 |
/* allow negative values */
|
| 698 |
greg |
2.13 |
colortrans(rgbout, xyz2rgbmat, ctmp);
|
| 699 |
greg |
2.7 |
}
|
| 700 |
|
|
|
| 701 |
|
|
|
| 702 |
schorsch |
2.23 |
static void
|
| 703 |
|
|
picdebug(void) /* put out debugging picture */
|
| 704 |
greg |
2.7 |
{
|
| 705 |
greg |
2.8 |
static COLOR blkcol = BLKCOLOR;
|
| 706 |
greg |
2.1 |
COLOR *scan;
|
| 707 |
greg |
2.9 |
int y, i;
|
| 708 |
greg |
2.29 |
int x, rg;
|
| 709 |
greg |
2.1 |
|
| 710 |
|
|
if (fseek(stdin, 0L, 0) == EOF) {
|
| 711 |
|
|
fprintf(stderr, "%s: cannot seek on input picture\n", progname);
|
| 712 |
|
|
exit(1);
|
| 713 |
|
|
}
|
| 714 |
|
|
getheader(stdin, NULL, NULL); /* skip input header */
|
| 715 |
|
|
fgetresolu(&xmax, &ymax, stdin);
|
| 716 |
|
|
/* allocate scanline */
|
| 717 |
|
|
scan = (COLOR *)malloc(xmax*sizeof(COLOR));
|
| 718 |
|
|
if (scan == NULL) {
|
| 719 |
|
|
perror(progname);
|
| 720 |
|
|
exit(1);
|
| 721 |
|
|
}
|
| 722 |
|
|
/* finish debug header */
|
| 723 |
greg |
2.5 |
fputformat(COLRFMT, debugfp);
|
| 724 |
greg |
2.1 |
putc('\n', debugfp);
|
| 725 |
|
|
fprtresolu(xmax, ymax, debugfp);
|
| 726 |
greg |
2.7 |
/* write debug picture */
|
| 727 |
greg |
2.1 |
for (y = ymax-1; y >= 0; y--) {
|
| 728 |
|
|
if (freadscan(scan, xmax, stdin) < 0) {
|
| 729 |
|
|
fprintf(stderr, "%s: error rereading input picture\n",
|
| 730 |
|
|
progname);
|
| 731 |
|
|
exit(1);
|
| 732 |
|
|
}
|
| 733 |
|
|
for (x = 0; x < xmax; x++) {
|
| 734 |
greg |
2.9 |
rg = chartndx(x, y, &i);
|
| 735 |
|
|
if (rg == RG_CENT) {
|
| 736 |
greg |
2.13 |
if (!(1L<<i & gmtflags) || (x+y)&07) {
|
| 737 |
greg |
2.9 |
copycolor(scan[x], mbRGB[i]);
|
| 738 |
greg |
2.13 |
clipgamut(scan[x], bright(scan[x]),
|
| 739 |
greg |
2.14 |
CGAMUT, colmin, colmax);
|
| 740 |
greg |
2.13 |
} else
|
| 741 |
greg |
2.9 |
copycolor(scan[x], blkcol);
|
| 742 |
|
|
} else if (rg == RG_CORR)
|
| 743 |
greg |
2.1 |
cvtcolor(scan[x], scan[x]);
|
| 744 |
greg |
2.9 |
else if (rg != RG_ORIG)
|
| 745 |
greg |
2.8 |
copycolor(scan[x], blkcol);
|
| 746 |
greg |
2.1 |
}
|
| 747 |
|
|
if (fwritescan(scan, xmax, debugfp) < 0) {
|
| 748 |
|
|
fprintf(stderr, "%s: error writing debugging picture\n",
|
| 749 |
|
|
progname);
|
| 750 |
|
|
exit(1);
|
| 751 |
|
|
}
|
| 752 |
|
|
}
|
| 753 |
greg |
2.7 |
/* clean up */
|
| 754 |
|
|
fclose(debugfp);
|
| 755 |
greg |
2.17 |
free((void *)scan);
|
| 756 |
greg |
2.7 |
}
|
| 757 |
|
|
|
| 758 |
|
|
|
| 759 |
schorsch |
2.23 |
static void
|
| 760 |
|
|
clrdebug(void) /* put out debug picture from color input */
|
| 761 |
greg |
2.7 |
{
|
| 762 |
|
|
static COLR blkclr = BLKCOLR;
|
| 763 |
greg |
2.9 |
COLR mbclr[24], cvclr[24], orclr[24];
|
| 764 |
greg |
2.7 |
COLR *scan;
|
| 765 |
greg |
2.13 |
COLOR ctmp, ct2;
|
| 766 |
greg |
2.9 |
int y, i;
|
| 767 |
greg |
2.29 |
int x, rg;
|
| 768 |
greg |
2.7 |
/* convert colors */
|
| 769 |
|
|
for (i = 0; i < 24; i++) {
|
| 770 |
greg |
2.13 |
copycolor(ctmp, mbRGB[i]);
|
| 771 |
|
|
clipgamut(ctmp, bright(ctmp), CGAMUT, cblack, cwhite);
|
| 772 |
|
|
setcolr(mbclr[i], colval(ctmp,RED),
|
| 773 |
|
|
colval(ctmp,GRN), colval(ctmp,BLU));
|
| 774 |
greg |
2.7 |
if (inpflags & 1L<<i) {
|
| 775 |
greg |
2.13 |
copycolor(ctmp, inpRGB[i]);
|
| 776 |
|
|
clipgamut(ctmp, bright(ctmp), CGAMUT, cblack, cwhite);
|
| 777 |
|
|
setcolr(orclr[i], colval(ctmp,RED),
|
| 778 |
greg |
2.7 |
colval(ctmp,GRN), colval(ctmp,BLU));
|
| 779 |
greg |
2.14 |
if (rawmap)
|
| 780 |
|
|
copycolr(cvclr[i], mbclr[i]);
|
| 781 |
|
|
else {
|
| 782 |
|
|
bresp(ctmp, inpRGB[i]);
|
| 783 |
|
|
colortrans(ct2, solmat, ctmp);
|
| 784 |
|
|
clipgamut(ct2, bright(ct2), CGAMUT,
|
| 785 |
|
|
cblack, cwhite);
|
| 786 |
|
|
setcolr(cvclr[i], colval(ct2,RED),
|
| 787 |
|
|
colval(ct2,GRN),
|
| 788 |
|
|
colval(ct2,BLU));
|
| 789 |
|
|
}
|
| 790 |
greg |
2.7 |
}
|
| 791 |
|
|
}
|
| 792 |
|
|
/* allocate scanline */
|
| 793 |
|
|
scan = (COLR *)malloc(xmax*sizeof(COLR));
|
| 794 |
|
|
if (scan == NULL) {
|
| 795 |
|
|
perror(progname);
|
| 796 |
|
|
exit(1);
|
| 797 |
|
|
}
|
| 798 |
|
|
/* finish debug header */
|
| 799 |
|
|
fputformat(COLRFMT, debugfp);
|
| 800 |
|
|
putc('\n', debugfp);
|
| 801 |
|
|
fprtresolu(xmax, ymax, debugfp);
|
| 802 |
|
|
/* write debug picture */
|
| 803 |
|
|
for (y = ymax-1; y >= 0; y--) {
|
| 804 |
greg |
2.9 |
for (x = 0; x < xmax; x++) {
|
| 805 |
|
|
rg = chartndx(x, y, &i);
|
| 806 |
|
|
if (rg == RG_CENT) {
|
| 807 |
greg |
2.8 |
if (!(1L<<i & gmtflags) || (x+y)&07)
|
| 808 |
|
|
copycolr(scan[x], mbclr[i]);
|
| 809 |
|
|
else
|
| 810 |
|
|
copycolr(scan[x], blkclr);
|
| 811 |
greg |
2.9 |
} else if (rg == RG_BORD || !(1L<<i & inpflags))
|
| 812 |
|
|
copycolr(scan[x], blkclr);
|
| 813 |
|
|
else if (rg == RG_ORIG)
|
| 814 |
|
|
copycolr(scan[x], orclr[i]);
|
| 815 |
|
|
else /* rg == RG_CORR */
|
| 816 |
greg |
2.7 |
copycolr(scan[x], cvclr[i]);
|
| 817 |
greg |
2.9 |
}
|
| 818 |
greg |
2.7 |
if (fwritecolrs(scan, xmax, debugfp) < 0) {
|
| 819 |
|
|
fprintf(stderr, "%s: error writing debugging picture\n",
|
| 820 |
|
|
progname);
|
| 821 |
|
|
exit(1);
|
| 822 |
|
|
}
|
| 823 |
|
|
}
|
| 824 |
|
|
/* clean up */
|
| 825 |
|
|
fclose(debugfp);
|
| 826 |
greg |
2.17 |
free((void *)scan);
|
| 827 |
gwlarson |
2.16 |
}
|
| 828 |
|
|
|
| 829 |
|
|
|
| 830 |
schorsch |
2.23 |
static void
|
| 831 |
|
|
getpos( /* get boundary position */
|
| 832 |
|
|
char *name,
|
| 833 |
|
|
int bnds[2],
|
| 834 |
|
|
FILE *fp
|
| 835 |
|
|
)
|
| 836 |
gwlarson |
2.16 |
{
|
| 837 |
|
|
char buf[64];
|
| 838 |
|
|
|
| 839 |
|
|
fprintf(stderr, "\tSelect corner: %s\n", name);
|
| 840 |
|
|
if (fgets(buf, sizeof(buf), fp) == NULL ||
|
| 841 |
|
|
sscanf(buf, "%d %d", &bnds[0], &bnds[1]) != 2) {
|
| 842 |
|
|
fprintf(stderr, "%s: read error from display process\n",
|
| 843 |
|
|
progname);
|
| 844 |
|
|
exit(1);
|
| 845 |
|
|
}
|
| 846 |
|
|
}
|
| 847 |
|
|
|
| 848 |
|
|
|
| 849 |
schorsch |
2.23 |
static void
|
| 850 |
|
|
pickchartpos( /* display picture and pick chart location */
|
| 851 |
|
|
char *pfn
|
| 852 |
|
|
)
|
| 853 |
gwlarson |
2.16 |
{
|
| 854 |
schorsch |
2.22 |
char combuf[PATH_MAX];
|
| 855 |
gwlarson |
2.16 |
FILE *pfp;
|
| 856 |
|
|
|
| 857 |
|
|
sprintf(combuf, DISPCOM, pfn);
|
| 858 |
|
|
if ((pfp = popen(combuf, "r")) == NULL) {
|
| 859 |
|
|
perror(combuf);
|
| 860 |
|
|
exit(1);
|
| 861 |
|
|
}
|
| 862 |
|
|
fputs("Use middle mouse button to select chart corners:\n", stderr);
|
| 863 |
|
|
getpos("upper left (dark skin)", bounds[0], pfp);
|
| 864 |
|
|
getpos("upper right (bluish green)", bounds[1], pfp);
|
| 865 |
|
|
getpos("lower left (white)", bounds[2], pfp);
|
| 866 |
|
|
getpos("lower right (black)", bounds[3], pfp);
|
| 867 |
|
|
fputs("Got it -- quit display program.\n", stderr);
|
| 868 |
|
|
pclose(pfp);
|
| 869 |
greg |
2.1 |
}
|