diff options
Diffstat (limited to 'xicc/cam02plot.c')
-rw-r--r-- | xicc/cam02plot.c | 845 |
1 files changed, 845 insertions, 0 deletions
diff --git a/xicc/cam02plot.c b/xicc/cam02plot.c new file mode 100644 index 0000000..ca68b52 --- /dev/null +++ b/xicc/cam02plot.c @@ -0,0 +1,845 @@ + +/* + * International Color Consortium color transform expanded support + * + * Author: Graeme W. Gill + * Date: 11/11/2004 + * Version: 1.00 + * + * Copyright 2000-2004 Graeme W. Gill + * All rights reserved. + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License.txt file for licencing details. + * + */ + +/* + * This is some test code to test the CIECAM02 continuity. + * This test creates file "cam02plot.tif" containing values that + * have been converted to and back from CIECAM02 space. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "copyright.h" +#include "aconfig.h" +#include "numlib.h" +#include "icc.h" +#include "xcam.h" +#include "cam02.h" +#include "tiffio.h" +#include "cam02ref.h" + +#define DEFRES 100 /* Default cube resolution */ + + +#define NORMAL_XYZ2RGB +#undef NIEVE_XYZ2RGB +#undef COMPLEX_XYZ2RGB + +#define SCALE 1.0 /* Compress RGB by scale towards grey */ + +#ifndef _isnan +#define _isnan(x) ((x) != (x)) +#define _finite(x) ((x) == 0.0 || (x) * 1.0000001 != (x)) +#endif + +static void +Lab2XYZ(double *out, double *in) { + double L = in[0], a = in[1], b = in[2]; + double x,y,z,fx,fy,fz; + + if (L > 8.0) { + fy = (L + 16.0)/116.0; + y = pow(fy,3.0); + } else { + y = L/903.2963058; + fy = 7.787036979 * y + 16.0/116.0; + } + + fx = a/500.0 + fy; + if (fx > 24.0/116.0) + x = pow(fx,3.0); + else + x = (fx - 16.0/116.0)/7.787036979; + + fz = fy - b/200.0; + if (fz > 24.0/116.0) + z = pow(fz,3.0); + else + z = (fz - 16.0/116.0)/7.787036979; + + out[0] = x * 0.9642; + out[1] = y * 1.0000; + out[2] = z * 0.8249; +} + +/* CIE XYZ to perceptual Lab */ +static void +XYZ2Lab(double *out, double *in) { + double X = in[0], Y = in[1], Z = in[2]; + double x,y,z,fx,fy,fz; + + x = X/0.9642; + y = Y/1.0000; + z = Z/0.8249; + + if (x > 0.008856451586) + fx = pow(x,1.0/3.0); + else + fx = 7.787036979 * x + 16.0/116.0; + + if (y > 0.008856451586) + fy = pow(y,1.0/3.0); + else + fy = 7.787036979 * y + 16.0/116.0; + + if (z > 0.008856451586) + fz = pow(z,1.0/3.0); + else + fz = 7.787036979 * z + 16.0/116.0; + + out[0] = 116.0 * fy - 16.0; + out[1] = 500.0 * (fx - fy); + out[2] = 200.0 * (fy - fz); +} + +#ifdef NORMAL_XYZ2RGB + +static double sign(double x) { + if (x < 0.0) + return -1.0; + else + return 1.0; +} + +/* Version with reasonable clipping. Converts to Lab, */ +/* clips the Lab an then converts to sRGB */ +/* Convert from XYZ to sRGB */ +void XYZ2sRGB(double *out, double *in, int trace) { + double lab[3]; + double tmp[3]; + double scale = SCALE; /* Scale RGB towards grey */ + double mat[3][3] = + { + { 3.2410, -1.5374, -0.4986 }, + { -0.9692, 1.8760, 0.0416 }, + { 0.0556, -0.2040, 1.0570 } + }; + int i; + +// ~~999 + trace = 0; + + /* Copy from input */ + for(i = 0; i < 3; i++) + tmp[i] = in[i]; + + if (trace) printf("XYZ to RGB\n"); + if (trace) printf("input XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]); + /* Clip to reasonable range */ +// if (tmp[1] <= 0.0) +// tmp[0] = tmp[2] = 0.0; + XYZ2Lab(lab, tmp); + if (trace) printf("Lab %f %f %f\n",tmp[0],tmp[1],tmp[2]); + icmClipLab(lab, lab); + if (trace) printf("Clipped Lab %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* We're going to assume that L == 0 is always black */ + if (lab[0] <= 0.0) { + lab[1] = lab[2] = 0.0; + } + if (trace) printf("Clipped Lab2 %f %f %f\n",tmp[0],tmp[1],tmp[2]); + Lab2XYZ(tmp, lab); + if (trace) printf("XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]); + icmClipXYZ(tmp, tmp); + if (trace) printf("clipped XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Now convert to sRGB assuming D50 (??) white point */ + icmMulBy3x3(tmp, mat, tmp); + + /* Scale */ + for(i = 0; i < 3; i++) { + tmp[i] = ((tmp[i] - 0.5) * scale) + 0.5; + } + + if (trace) printf("raw RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Apply gamma */ + for(i = 0; i < 3; i++) { + if (tmp[i] < 0.00304) { + tmp[i] = tmp[i] * 12.92; + } else { + tmp[i] = 1.055 * pow(tmp[i], 1.0/2.4) - 0.055; + } + } + + if (trace) printf("gamma corrected RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + +#ifndef NEVER + /* Clip to nearest */ + for(i = 0; i < 3; i++) { + if (tmp[i] < 0.0) + tmp[i] = 0.0; + else if (tmp[i] > 1.0) + tmp[i] = 1.0; + } +#else + /* Clip towards center */ + { + double biggest = -100.0; + for(i = 0; i < 3; i++) { + tmp[i] -= 0.5; + if (fabs(tmp[i]) > biggest) + biggest = fabs(tmp[i]); + } + for(i = 0; i < 3; i++) { + if (biggest > 0.5) + tmp[i] *= 0.5/biggest; + tmp[i] += 0.5; + } + } +#endif + if (trace) printf("output clipped RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Copy to output */ + for(i = 0; i < 3; i++) + out[i] = tmp[i]; + +} + +#endif /* NORMAL_XYZ2RGB */ + +#ifdef NIEVE_XYZ2RGB + +/* Nieve version with RGB clipping */ +/* Convert from XYZ to sRGB */ +void XYZ2sRGB(double *out, double *in, int trace) { + double tmp[3]; + double scale = SCALE; /* Scale RGB towards grey */ + double mat[3][3] = + { + { 3.2410, -1.5374, -0.4986 }, + { -0.9692, 1.8760, 0.0416 }, + { 0.0556, -0.2040, 1.0570 } + }; + int i; + + if (trace) printf("XYZ to RGB\n"); + if (trace) printf("input XYZ %f %f %f\n",in[0],in[1],in[2]); + + /* Now convert to sRGB assuming D50 (??) white point */ + icmMulBy3x3(tmp, mat, in); + + /* Scale */ + for(i = 0; i < 3; i++) { + tmp[i] = ((tmp[i] - 0.5) * scale) + 0.5; + } + + if (trace) printf("raw RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Clip to nearest */ + for(i = 0; i < 3; i++) { + if (tmp[i] < 0.0) + tmp[i] = 0.0; + else if (tmp[i] > 1.0) + tmp[i] = 1.0; + } + + if (trace) printf("clipped RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Apply gamma */ + for(i = 0; i < 3; i++) { + if (tmp[i] < 0.00304) { + tmp[i] = tmp[i] * 12.92; + } else { + tmp[i] = 1.055 * pow(tmp[i], 1.0/2.4) - 0.055; + } + } + + if (trace) printf("output gamma corrected RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Copy to output */ + for(i = 0; i < 3; i++) + out[i] = tmp[i]; +} + +#endif /* NIEVE_XYZ2RGB */ + +#ifdef COMPLEX_XYZ2RGB + +/* Complex version using powell to ensure good clipping */ +/* Callback context */ +typedef struct { + double scale; + double lab[3]; + double imat[3][3]; +} ctx; + +double clipf(void *fdata, double tp[]) { + ctx *x = (ctx *)fdata; + double lab[3], tmp[3], tt; + int k; + double rv = 0.0; + +//printf("\n"); +//printf("~1 clipf got %f %f %f\n",tp[0],tp[1],tp[2]); + + /* Penalize for being out of gamut */ + for (k = 0; k < 3; k++) { + if (tp[k] < 0.0) { + tt = 100000.0 * (0.0 - tp[k]); + rv += tt * tt; + } else if (tp[k] > 1.0) { + tt = 100000.0 * (tp[k] - 1.0); + rv += tt * tt; + } + } +//printf("~1 rv out of gamut = %f\n",rv); + + /* Unscale it */ + for(k = 0; k < 3; k++) + tmp[k] = ((tp[k] - 0.5) / x->scale) + 0.5; +//printf("~1 unscale %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + icmMulBy3x3(tmp, x->imat, tmp); /* To XYZ */ +//printf("~1 xyz %f %f %f\n",tmp[0],tmp[1],tmp[2]); + XYZ2Lab(lab, tmp); /* To Lab */ +//printf("~1 lab = %f %f %f\n",lab[0],lab[1],lab[2]); +//printf("~1 target = %f %f %f\n",x->lab[0],x->lab[1],x->lab[2]); + + /* Compute an error to the goal */ + tt = 10000.0 * (lab[0] - x->lab[0]); + rv += tt * tt; + + tt = 1.0 * (lab[1] - x->lab[1]); + rv += tt * tt; + tt = 1.0 * (lab[2] - x->lab[2]); + rv += tt * tt; + +//printf("~1 rv = %f\n",rv); + + return rv; +} + +/* Convert from XYZ to sRGB */ +void XYZ2sRGB(double *out, double *in, int trace) { + double lab[3], tmp[3]; + double scale = SCALE; /* Scale RGB towards grey */ + double mat[3][3] = + { + { 3.2410, -1.5374, -0.4986 }, + { -0.9692, 1.8760, 0.0416 }, + { 0.0556, -0.2040, 1.0570 } + }; + int i; + + /* Copy from input */ + for(i = 0; i < 3; i++) + tmp[i] = in[i]; + + if (trace) printf("XYZ to RGB\n"); + + if (trace) printf("input XYZ %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + XYZ2Lab(lab, tmp); + + if (trace) printf("Lab %f %f %f\n",lab[0],lab[1],lab[2]); + + icmClipLab(lab, lab); + + if (trace) printf("Clipped Lab %f %f %f\n",lab[0],lab[1],lab[2]); + + /* Now convert to sRGB assuming D50 (??) white point */ + Lab2XYZ(tmp, lab); + icmMulBy3x3(tmp, mat, tmp); + + /* Scale */ + for(i = 0; i < 3; i++) { + tmp[i] = ((tmp[i] - 0.5) * scale) + 0.5; + } + + if (trace) printf("raw RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* See if it need clipping */ + for(i = 0; i < 3; i++) { + if (tmp[i] < 0.0 || tmp[i] > 1.0) + break; + } + /* It needs more clipping */ + if (i < 3) { + ctx x; + double ss[3] = { 0.1, 0.1, 0.1 }; + x.lab[0] = lab[0]; + x.lab[1] = lab[1]; + x.lab[2] = lab[2]; + x.scale = scale; + icmInverse3x3(x.imat, mat); + + if (powell(NULL, 3, tmp, ss, 1e-6, 1000, clipf, (void *)&x) < 0.0) + error("RGB clip failed"); + } + if (trace) printf("RGB clip %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Clip to nearest */ + for(i = 0; i < 3; i++) { + if (tmp[i] < 0.0) + tmp[i] = 0.0; + else if (tmp[i] > 1.0) + tmp[i] = 1.0; + } + if (trace) printf("clip to nearest RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Apply gamma */ + for(i = 0; i < 3; i++) { + if (tmp[i] < 0.00304) { + tmp[i] = tmp[i] * 12.92; + } else { + tmp[i] = 1.055 * pow(tmp[i], 1.0/2.4) - 0.055; + } + } + if (trace) printf("gamma corrected RGB %f %f %f\n",tmp[0],tmp[1],tmp[2]); + + /* Copy to output */ + for(i = 0; i < 3; i++) + out[i] = tmp[i]; + +} +#endif /* COMPLEX_XYZ2RGB */ + +void usage(char *diag) { + fprintf(stderr,"Create a 3D slice plot of XYZ/Lab <-> Jab, Version %s\n",ARGYLL_VERSION_STR); + fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n"); + if (diag != NULL) + fprintf(stderr,"Diagnostic '%s'\n",diag); + fprintf(stderr,"usage: cam02plot [-options] x y\n"); + fprintf(stderr,"'cam02plot -l -o' shows problem best\n"); + fprintf(stderr," -v level Verbosity level 0 - 2 (default = 1)\n"); + fprintf(stderr," -n Don't use Helmholtz-Kohlraush flag\n"); + fprintf(stderr," -f Use the reference CIECAM transform\n"); + fprintf(stderr," -r res Resolution (default %d)\n",DEFRES); + fprintf(stderr," -l Lab source cube (default XYZ source cube)\n"); + fprintf(stderr," -i XYZ/Lab -> Jab (default XYZ/Lab -> Lab)\n"); + fprintf(stderr," -o Jab -> XYZ -> RGB (defult Lab -> XYZ -> RGB\n"); + fprintf(stderr," -s XYZ/Lab -> ab scale as RGB\n"); + fprintf(stderr," -x Cross section plots\n"); + fprintf(stderr," x y Return input color for this coordinate\n"); + exit(1); +} + +int +main(int argc, char *argv[]) { + int fa,nfa; /* argument we're looking at */ + char *tiffname = "cam02plot.tif"; + TIFF *wh = NULL; + uint16 resunits = RESUNIT_INCH; + float resx = 75.0, resy = 75.0; + tdata_t *obuf; + unsigned char *ob; + int verb = 0; + int transl = 0; /* Translate x,y into input color */ + int tx = 0, ty = 0; /* coordinate to translate */ + int use_hk = 1; /* Use Helmholtz-Kohlraush flag */ + int use_ref = 0; /* Use reference transform rather than working code */ + int lab_plot = 0; /* Lab <-> Jab plot, else XYZ <-> Jab */ + int to_jab = 0; /* Convert to Jab, else convert to Lab */ + int from_jab = 0; /* Convert from Jab, else convert from Lab */ + int to_ss = 0; /* Convert from XYZ/Lab to abs scale ss */ + int xsect = 0; /* Cross section plots */ + + double white[9][3] = { + { 0.964242, 1.000000, 0.825124 }, /* 0: D50 */ + { 1.098494, 1.000000, 0.355908 }, /* 1: A */ + { 0.908731, 1.000000, 0.987233 }, /* 2: F5 */ + { 1.128981, 1.000000, 0.305862 }, /* 3: D25 */ + { 0.950471, 1.000000, 1.088828 }, /* 4: D65 */ + { 0.949662, 1.000000, 1.160438 }, /* 5: D80 */ + { 0.949662, 1.000000, 1.160438 }, /* 6: D80 */ + { 0.951297, 1.000000, 1.338196 }, /* 7: D85 */ + { 0.952480, 1.000000, 1.386693 } /* 8: D90 */ + }; + +#ifdef NEVER + double La[6] = { 10.0, 31.83, 100.0, 318.31, 1000.83, 3183.1 }; + + ViewingCondition Vc[4] = { + vc_average, + vc_dark, + vc_dim, + vc_cut_sheet + }; +#endif /* NEVER */ + + int i, j, k, m; + double xyz[3], Jab[3], rgb[3]; + cam02 *cam1, *cam2; + + int res = DEFRES; /* Resolution of scan through space */ + int ares; /* Array of 2d sub-rasters */ + int w, h; /* Width and height of raster */ + int x, y; + int sp = 5; /* Spacing beween resxres sub-images */ + + error_program = argv[0]; + + /* Process the arguments */ + for(fa = 1;fa < argc;fa++) { + nfa = fa; /* skip to nfa if next argument is used */ + if (argv[fa][0] == '-') { /* Look for any flags */ + char *na = NULL; /* next argument after flag, null if none */ + + if (argv[fa][2] != '\000') + na = &argv[fa][2]; /* next is directly after flag */ + else { + if ((fa+1) < argc) { + if (argv[fa+1][0] != '-') { + nfa = fa + 1; + na = argv[nfa]; /* next is seperate non-flag argument */ + } + } + } + + if (argv[fa][1] == '?') + usage("Requested usage"); + + /* Verbosity */ + else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') { + fa = nfa; + if (na == NULL) + verb = 2; + else { + if (na[0] == '0') + verb = 0; + else if (na[0] == '1') + verb = 1; + else if (na[0] == '2') + verb = 2; + else + usage("Illegal verbosity level"); + } + } + + else if (argv[fa][1] == 'r' || argv[fa][1] == 'R') { + fa = nfa; + if (na == NULL) + usage("Need resolution after -r"); + res = atoi(na); + if (res < 2 || res > 1000) + usage("Resolution is out of range"); + } + else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') { + use_hk = 0; + } + else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') { + use_ref = 1; + } + else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') { + lab_plot = 1; + } + else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') { + to_jab = 1; + } + else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') { + from_jab = 1; + } + else if (argv[fa][1] == 's' || argv[fa][1] == 'S') { + to_ss = 1; + } + else if (argv[fa][1] == 'x' || argv[fa][1] == 'X') { + xsect = 1; + } + else + usage("Unknown flag"); + } else + break; + } + + if ((fa+1) < argc) { + tx = atoi(argv[fa]); + ty = atoi(argv[fa+1]); + transl = 1; + } + + + /* Setup cam to convert to Jab */ + if (use_ref) + cam1 = new_cam02ref(); + else + cam1 = new_cam02(); + cam1->set_view( + cam1, + vc_average, /* Enumerated Viewing Condition */ + white[4], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */ + 1000.0, /* Adapting/Surround Luminance cd/m^2 */ + 0.20, /* Relative Luminance of Background to reference white */ + 0.0, /* Luminance of white in image - not used */ + 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */ + white[4], /* The Flare color coordinates (typically the Ambient color) */ + use_hk /* use Helmholtz-Kohlraush flag */ + ); + + /* Setup cam to convert from Jab */ + if (use_ref) + cam2 = new_cam02ref(); + else + cam2 = new_cam02(); + cam2->set_view( + cam2, + vc_average, /* Enumerated Viewing Condition */ + white[4], /* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */ + 1000.0, /* Adapting/Surround Luminance cd/m^2 */ + 0.20, /* Relative Luminance of Background to reference white */ + 0.0, /* Luminance of white in image - not used */ + 0.00, /* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */ + white[4], /* The Flare color coordinates (typically the Ambient color) */ + use_hk /* use Helmholtz-Kohlraush flag */ + ); + + /* Figure out the size of the raster */ + ares = (int)ceil(sqrt((double)res)); + if (verb) + printf("For res %d, ares = %d\n",res,ares); + + w = ares * res + sp * (ares+1); + h = ares * res + sp * (ares+1); + + if (to_ss) { + cam1->retss = 1; + } + + if (transl) { + int ix,iy,iz; + double dx,dy,dz; + double tmp[3], lab[3]; + + cam1->trace = 1; + cam2->trace = 1; + +//printf("~1 translate %d %d\n",tx,ty); + tx -= sp; /* Border at base */ + ty -= sp; + +//printf("~1 offset %d %d\n",tx,ty); + ix = tx % (res + sp); + iy = ty % (res + sp); + iz = (ty / (res + sp)) * ares + (tx / (res + sp)); + +//printf("~1 x y z = %d %d %d\n", ix,iy,iz); + + dx = ix/(res-1.0); + dy = iy/(res-1.0); + dz = iz/((ares * ares)-1.0); + +//printf("~1 X Y Z = %f %f %f\n", dx,dy,dz); + + /* Source range is extended L*a*b* type */ + if (lab_plot) { + if (xsect) { + lab[0] = 180.0 * dz - 40.0; + lab[1] = 300.0 * dy - 150.0; + lab[2] = 300.0 * dx - 150.0; + } else { + lab[0] = 180.0 * dx - 40.0; + lab[1] = 300.0 * dy - 150.0; + lab[2] = 300.0 * dz - 150.0; + } +//printf("~1 Lab = %f %f %f\n", lab[0],lab[1],lab[2]); + Lab2XYZ(tmp, lab); + printf("======================================================\n"); + printf("%d,%d -> Lab %f %f %f\n", tx+sp, ty+sp, lab[0],lab[1],lab[2]); + printf(" == XYZ %f %f %f\n", tmp[0],tmp[1],tmp[2]); + + /* Else source range is extended XYZ type */ + } else { + if (xsect) { + tmp[0] = 1.4 * dz - 0.2; + tmp[1] = 1.4 * dy - 0.2; + tmp[2] = 1.6 * dx - 0.2; + } else { + tmp[0] = 1.4 * dx - 0.2; + tmp[1] = 1.4 * dy - 0.2; + tmp[2] = 1.6 * dz - 0.2; + } + printf("%d,%d -> Input color XYZ %f %f %f\n", tx, ty, tmp[0],tmp[1],tmp[2]); + } + + if (to_ss) { + cam1->XYZ_to_cam(cam1, Jab, tmp); + printf(" XYZ -> ss %f %f %f\n", Jab[0],Jab[1],Jab[2]); + + /* Convert XYZ through cam and back, then to RGB */ + } else if (to_jab) { + cam1->XYZ_to_cam(cam1, Jab, tmp); + if (to_ss) { + printf(" XYZ -> ss %f %f %f\n", Jab[0],Jab[1],Jab[2]); + } else { + printf(" XYZ -> ss %f %f %f\n", Jab[0],Jab[1],Jab[2]); + } + + /* Else convert XYZ to L*a*b* */ + } else { + XYZ2Lab(Jab, tmp); + printf(" XYZ -> Lab %f %f %f\n", Jab[0],Jab[1],Jab[2]); + } + + /* Convert from Jab back to XYZ */ + if (from_jab) { + cam2->cam_to_XYZ(cam2, rgb, Jab); + printf(" Jab -> XYZ %f %f %f\n", rgb[0],rgb[1],rgb[2]); + + /* Else convert from Lab back to XYZ */ + } else { + Lab2XYZ(rgb, Jab); + printf(" Lab -> XYZ %f %f %f\n", rgb[0],rgb[1],rgb[2]); + } + + XYZ2Lab(tmp, rgb); + printf(" == Lab %f %f %f\n", tmp[0],tmp[1],tmp[2]); + + /* Interpret XYZ as RGB color */ + XYZ2sRGB(rgb, rgb, 1); + printf(" XYZ -> RGB %f %f %f\n", rgb[0],rgb[1],rgb[2]); + + cam1->trace = 0; + cam2->trace = 0; + + printf("\n"); + exit(0); + } + + if (verb) + printf("Raster width = %d, height = %d\n",w,h); + + /* Setup the tiff file */ + if ((wh = TIFFOpen(tiffname, "w")) == NULL) + error("Can\'t create TIFF file '%s'!",tiffname); + + TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, w); + TIFFSetField(wh, TIFFTAG_IMAGELENGTH, h); + TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, 8); + TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits); + TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx); + TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy); + TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "cam02plot"); + + obuf = _TIFFmalloc(TIFFScanlineSize(wh)); + ob = (unsigned char *)obuf; + + y = 0; + + /* Fill sp lines with black */ + for (x = 0, m = 0; m < w; m++) { + ob[x] = ob[x+1] = ob[x+2] = 0; + x += 3; + } + for (j = 0; j < sp; j++, y++) { + TIFFWriteScanline(wh, ob, y, 0); + } + + for (i = 0; i < ares; i++) { /* Vertical blocks (rows) */ + for (j = 0; j < res; j++, y++) { /* Vertical in block (y = Y/a*) */ + xyz[1] = j/(res-1.0); + x = 0; + + /* Fill sp pixels with black */ + for (m = 0; m < sp; m++) { + ob[x] = ob[x+1] = ob[x+2] = 0; + x += 3; + } + for (k = 0; k < ares; k++) { /* Horizontal blocks (columns) */ + int zv = i * ares + k; + if (zv >= res) { + /* Fill res pixels with black */ + for (m = 0; m < res; m++) { + ob[x] = ob[x+1] = ob[x+2] = 0; + x += 3; + } + } else { + xyz[2] = zv/(res-1.0); /* z = block = Z/b* */ + for (m = 0; m < res; m++) { /* Horizontal in block (x = X/L*) */ + double tmp[3], xyz2[3]; + xyz[0] = m/(res-1.0); + + if (lab_plot) { + if (xsect) { + tmp[0] = 180.0 * xyz[2] - 40.0; + tmp[1] = 300.0 * xyz[1] - 150.0; + tmp[2] = 300.0 * xyz[0] - 150.0; + } else { + tmp[0] = 180.0 * xyz[0] - 40.0; + tmp[1] = 300.0 * xyz[1] - 150.0; + tmp[2] = 300.0 * xyz[2] - 150.0; + } + Lab2XYZ(tmp, tmp); + + } else { + if (xsect) { + tmp[0] = 1.4 * xyz[2] - 0.2; + tmp[1] = 1.4 * xyz[1] - 0.2; + tmp[2] = 1.6 * xyz[0] - 0.2; + } else { + tmp[0] = 1.4 * xyz[0] - 0.2; + tmp[1] = 1.4 * xyz[1] - 0.2; + tmp[2] = 1.6 * xyz[2] - 0.2; + } + } + + /* Convert XYZ through cam and back, then to RGB */ + if (to_jab || to_ss) + cam1->XYZ_to_cam(cam1, Jab, tmp); + else + XYZ2Lab(Jab, tmp); + + if (to_ss) { + rgb[0] = Jab[0]; + rgb[1] = Jab[1]; + rgb[2] = Jab[2]; + } else { + if (from_jab) + cam2->cam_to_XYZ(cam2, xyz2, Jab); + else + Lab2XYZ(xyz2, Jab); + + XYZ2sRGB(rgb, xyz2, 0); + } + + /* Fill with pixel value */ + ob[x+0] = (int)(rgb[0] * 255.0 + 0.5); + ob[x+1] = (int)(rgb[1] * 255.0 + 0.5); + ob[x+2] = (int)(rgb[2] * 255.0 + 0.5); + x += 3; + } + } + /* Fill sp pixels with black */ + for (m = 0; m < sp; m++) { + ob[x] = ob[x+1] = ob[x+2] = 0; + x += 3; + } + } + TIFFWriteScanline(wh, ob, y, 0); + } + /* Fill sp lines with black */ + for (x = m = 0; m < w; m++) { + ob[x] = ob[x+1] = ob[x+2] = 0; + x += 3; + } + for (j = 0; j < sp; j++, y++) { + TIFFWriteScanline(wh, ob, y, 0); + } + } + + cam1->del(cam1); + cam2->del(cam2); + + /* Write TIFF file */ + TIFFClose(wh); + + return 0; +} + |