summaryrefslogtreecommitdiff
path: root/gs/imdi/cctiff.c
diff options
context:
space:
mode:
Diffstat (limited to 'gs/imdi/cctiff.c')
-rw-r--r--gs/imdi/cctiff.c2114
1 files changed, 1055 insertions, 1059 deletions
diff --git a/gs/imdi/cctiff.c b/gs/imdi/cctiff.c
index ee940de39..22a772158 100644
--- a/gs/imdi/cctiff.c
+++ b/gs/imdi/cctiff.c
@@ -1,5 +1,4 @@
-
-/*
+/*
* Color Correct a TIFF file, using an ICC Device link profile.
*
* Author: Graeme W. Gill
@@ -21,8 +20,8 @@
*/
/*
- This program is a framework that exercises the
- IMDI code, as well as a demonstration of simple
+ This program is a framework that exercises the
+ IMDI code, as well as a demonstration of simple
profile linking. It can also do the conversion using the
floating point code in ICCLIB as a reference.
@@ -45,20 +44,20 @@
void error(char *fmt, ...), warning(char *fmt, ...);
void usage(void) {
- fprintf(stderr,"Color Correct a TIFF file using an ICC device link profile, V%s\n",ARGYLL_VERSION_STR);
- fprintf(stderr,"Author: Graeme W. Gill, licensed under the GPL\n");
- fprintf(stderr,"usage: cctiff [-options] devlinkprofile.icm infile.tif outfile.tif\n");
- fprintf(stderr,"usage: cctiff [-options] -l inprofile.icm outprofile.icm infile.tif outfile.tif\n");
- fprintf(stderr," -v Verbose\n");
- fprintf(stderr," -c Combine linearisation curves into one transform\n");
- fprintf(stderr," -p Use slow precise correction\n");
- fprintf(stderr," -k Check fast result against precise, and report\n");
- fprintf(stderr," -l Link input and output profiles\n");
- fprintf(stderr," -i in_intent p = perceptual, r = relative colorimetric,\n");
- fprintf(stderr," s = saturation, a = absolute colorimetric\n");
- fprintf(stderr," -o out_intent p = perceptual, r = relative colorimetric,\n");
- fprintf(stderr," s = saturation, a = absolute colorimetric\n");
- exit(1);
+ fprintf(stderr,"Color Correct a TIFF file using an ICC device link profile, V%s\n",ARGYLL_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill, licensed under the GPL\n");
+ fprintf(stderr,"usage: cctiff [-options] devlinkprofile.icm infile.tif outfile.tif\n");
+ fprintf(stderr,"usage: cctiff [-options] -l inprofile.icm outprofile.icm infile.tif outfile.tif\n");
+ fprintf(stderr," -v Verbose\n");
+ fprintf(stderr," -c Combine linearisation curves into one transform\n");
+ fprintf(stderr," -p Use slow precise correction\n");
+ fprintf(stderr," -k Check fast result against precise, and report\n");
+ fprintf(stderr," -l Link input and output profiles\n");
+ fprintf(stderr," -i in_intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute colorimetric\n");
+ fprintf(stderr," -o out_intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute colorimetric\n");
+ exit(1);
}
/* Convert an ICC colorspace to the corresponding possible TIFF Photometric tags. */
@@ -68,130 +67,129 @@ ColorSpaceSignature2TiffPhotometric(
uint16 tags[10], /* Pointer to return array, up to 10 */
icColorSpaceSignature cspace /* Input ICC colorspace */
) {
- switch(cspace) {
- case icSigGrayData:
- tags[0] = PHOTOMETRIC_MINISBLACK;
- return 1;
- case icSigRgbData:
+ switch(cspace) {
+ case icSigGrayData:
+ tags[0] = PHOTOMETRIC_MINISBLACK;
+ return 1;
+ case icSigRgbData:
#ifdef TREAT_CMY_AS_RGB
- case icSigCmyData:
+ case icSigCmyData:
#endif
- tags[0] = PHOTOMETRIC_RGB;
- return 1;
+ tags[0] = PHOTOMETRIC_RGB;
+ return 1;
#ifndef TREAT_CMY_AS_RGB
- case icSigCmyData:
+ case icSigCmyData:
#endif
- case icSigCmykData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- return 1;
- case icSigYCbCrData:
- tags[0] = PHOTOMETRIC_YCBCR;
- return 1;
- case icSigLabData:
- tags[0] = PHOTOMETRIC_CIELAB;
+ case icSigCmykData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ return 1;
+ case icSigYCbCrData:
+ tags[0] = PHOTOMETRIC_YCBCR;
+ return 1;
+ case icSigLabData:
+ tags[0] = PHOTOMETRIC_CIELAB;
#ifdef PHOTOMETRIC_ICCLAB
- tags[1] = PHOTOMETRIC_ICCLAB;
- tags[2] = PHOTOMETRIC_ITULAB;
+ tags[1] = PHOTOMETRIC_ICCLAB;
+ tags[2] = PHOTOMETRIC_ITULAB;
#endif
- return 3;
-
- case icSigXYZData:
- case icSigLuvData:
- case icSigYxyData:
- case icSigHsvData:
- case icSigHlsData:
- return 0;
-
- case icSig2colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 2; /* Cheat */
- return 1;
-
- case icSig3colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 3; /* Cheat */
- return 1;
-
- case icSig4colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 4; /* Cheat */
- return 1;
-
- case icSig5colorData:
- case icSigMch5Data:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 5; /* Cheat */
- return 1;
-
- case icSig6colorData:
- case icSigMch6Data:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 6; /* Cheat */
- return 1;
-
- case icSig7colorData:
- case icSigMch7Data:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 7; /* Cheat */
- return 1;
-
- case icSig8colorData:
- case icSigMch8Data:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 8; /* Cheat */
- return 1;
-
- case icSig9colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 9; /* Cheat */
- return 1;
-
- case icSig10colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 10; /* Cheat */
- return 1;
-
- case icSig11colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 11; /* Cheat */
- return 1;
-
- case icSig12colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 12; /* Cheat */
- return 1;
-
- case icSig13colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 13; /* Cheat */
- return 1;
-
- case icSig14colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 14; /* Cheat */
- return 1;
-
- case icSig15colorData:
- tags[0] = PHOTOMETRIC_SEPARATED;
- tags[1] = 15; /* Cheat */
- return 1;
-
- default:
- return 0;
- }
- return 0;
+ return 3;
+
+ case icSigXYZData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ return 0;
+
+ case icSig2colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 2; /* Cheat */
+ return 1;
+
+ case icSig3colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 3; /* Cheat */
+ return 1;
+
+ case icSig4colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 4; /* Cheat */
+ return 1;
+
+ case icSig5colorData:
+ case icSigMch5Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 5; /* Cheat */
+ return 1;
+
+ case icSig6colorData:
+ case icSigMch6Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 6; /* Cheat */
+ return 1;
+
+ case icSig7colorData:
+ case icSigMch7Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 7; /* Cheat */
+ return 1;
+
+ case icSig8colorData:
+ case icSigMch8Data:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 8; /* Cheat */
+ return 1;
+
+ case icSig9colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 9; /* Cheat */
+ return 1;
+
+ case icSig10colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 10; /* Cheat */
+ return 1;
+
+ case icSig11colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 11; /* Cheat */
+ return 1;
+
+ case icSig12colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 12; /* Cheat */
+ return 1;
+
+ case icSig13colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 13; /* Cheat */
+ return 1;
+
+ case icSig14colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 14; /* Cheat */
+ return 1;
+
+ case icSig15colorData:
+ tags[0] = PHOTOMETRIC_SEPARATED;
+ tags[1] = 15; /* Cheat */
+ return 1;
+
+ default:
+ return 0;
+ }
+ return 0;
}
-
/* Compute the length of a double nul terminated string, including */
/* the nuls. */
static int zzstrlen(char *s) {
- int i;
- for (i = 0;; i++) {
- if (s[i] == '\000' && s[i+1] == '\000')
- return i+2;
- }
- return 0;
+ int i;
+ for (i = 0;; i++) {
+ if (s[i] == '\000' && s[i+1] == '\000')
+ return i+2;
+ }
+ return 0;
}
/* Convert an ICC colorspace to the corresponding TIFF Inkset tag */
@@ -203,196 +201,196 @@ icColorSpaceSignature cspace,
int *len, /* Return length of ASCII inknames */
char **inknames /* Return ASCII inknames if non NULL */
) {
- switch(cspace) {
- case icSigCmyData:
- return 0xffff; /* ~~9999 */
- if (inknames != NULL) {
- *inknames = "cyan\000magenta\000yellow\000\000";
- *len = zzstrlen(*inknames);
- }
- return 0; /* Not CMYK */
- case icSigCmykData:
- if (inknames != NULL) {
- *inknames = NULL; /* No inknames */
- *len = 0;
- }
- return INKSET_CMYK;
-
- case icSigGrayData:
- case icSigRgbData:
- case icSigYCbCrData:
- case icSigLabData:
- case icSigXYZData:
- case icSigLuvData:
- case icSigYxyData:
- case icSigHsvData:
- case icSigHlsData:
- case icSig2colorData:
- case icSig3colorData:
- case icSig4colorData:
- case icSig5colorData:
- case icSigMch5Data:
- return 0xffff;
-
- case icSig6colorData:
- case icSigMch6Data:
- /* This is a cheat and a hack. Should really make sure that icclink */
- /* transfers the right information from the destination */
- /* profile, and then copies it to the device profile, */
- /* allowing cctiff to read it. */
- if (inknames != NULL) {
- *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000\000";
- *len = zzstrlen(*inknames);
- }
- return 0; /* Not CMYK */
-
- case icSig7colorData:
- case icSigMch7Data:
- return 0xffff;
-
- case icSig8colorData:
- case icSigMch8Data:
- /* This is a cheat and a hack. Should really make sure that icclink */
- /* transfers the right information from the destination */
- /* profile, and then copies it to the device profile, */
- /* allowing cctiff to read it. */
- if (inknames != NULL) {
- *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000lightcyan\000lightmagenta\000\000";
- *len = zzstrlen(*inknames);
- }
- return 0; /* Not CMYK */
- case icSig9colorData:
- case icSig10colorData:
- case icSig11colorData:
- case icSig12colorData:
- case icSig13colorData:
- case icSig14colorData:
- case icSig15colorData:
- default:
- return 0xffff;
- }
- return 0xffff;
+ switch(cspace) {
+ case icSigCmyData:
+ return 0xffff; /* ~~9999 */
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return 0; /* Not CMYK */
+ case icSigCmykData:
+ if (inknames != NULL) {
+ *inknames = NULL; /* No inknames */
+ *len = 0;
+ }
+ return INKSET_CMYK;
+
+ case icSigGrayData:
+ case icSigRgbData:
+ case icSigYCbCrData:
+ case icSigLabData:
+ case icSigXYZData:
+ case icSigLuvData:
+ case icSigYxyData:
+ case icSigHsvData:
+ case icSigHlsData:
+ case icSig2colorData:
+ case icSig3colorData:
+ case icSig4colorData:
+ case icSig5colorData:
+ case icSigMch5Data:
+ return 0xffff;
+
+ case icSig6colorData:
+ case icSigMch6Data:
+ /* This is a cheat and a hack. Should really make sure that icclink */
+ /* transfers the right information from the destination */
+ /* profile, and then copies it to the device profile, */
+ /* allowing cctiff to read it. */
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return 0; /* Not CMYK */
+
+ case icSig7colorData:
+ case icSigMch7Data:
+ return 0xffff;
+
+ case icSig8colorData:
+ case icSigMch8Data:
+ /* This is a cheat and a hack. Should really make sure that icclink */
+ /* transfers the right information from the destination */
+ /* profile, and then copies it to the device profile, */
+ /* allowing cctiff to read it. */
+ if (inknames != NULL) {
+ *inknames = "cyan\000magenta\000yellow\000black\000orange\000green\000lightcyan\000lightmagenta\000\000";
+ *len = zzstrlen(*inknames);
+ }
+ return 0; /* Not CMYK */
+ case icSig9colorData:
+ case icSig10colorData:
+ case icSig11colorData:
+ case icSig12colorData:
+ case icSig13colorData:
+ case icSig14colorData:
+ case icSig15colorData:
+ default:
+ return 0xffff;
+ }
+ return 0xffff;
}
char *
Photometric2str(
int pmtc
) {
- static char buf[80];
- switch (pmtc) {
- case PHOTOMETRIC_MINISWHITE:
- return "Subtractive Gray";
- case PHOTOMETRIC_MINISBLACK:
- return "Additive Gray";
- case PHOTOMETRIC_RGB:
- return "RGB";
- case PHOTOMETRIC_PALETTE:
- return "Indexed";
- case PHOTOMETRIC_MASK:
- return "Transparency Mask";
- case PHOTOMETRIC_SEPARATED:
- return "Separated";
- case PHOTOMETRIC_YCBCR:
- return "YCbCr";
- case PHOTOMETRIC_CIELAB:
- return "CIELab";
+ static char buf[80];
+ switch (pmtc) {
+ case PHOTOMETRIC_MINISWHITE:
+ return "Subtractive Gray";
+ case PHOTOMETRIC_MINISBLACK:
+ return "Additive Gray";
+ case PHOTOMETRIC_RGB:
+ return "RGB";
+ case PHOTOMETRIC_PALETTE:
+ return "Indexed";
+ case PHOTOMETRIC_MASK:
+ return "Transparency Mask";
+ case PHOTOMETRIC_SEPARATED:
+ return "Separated";
+ case PHOTOMETRIC_YCBCR:
+ return "YCbCr";
+ case PHOTOMETRIC_CIELAB:
+ return "CIELab";
#ifdef PHOTOMETRIC_ICCLAB
- case PHOTOMETRIC_ICCLAB:
- return "ICCLab";
- case PHOTOMETRIC_ITULAB:
- return "ITULab";
+ case PHOTOMETRIC_ICCLAB:
+ return "ICCLab";
+ case PHOTOMETRIC_ITULAB:
+ return "ITULab";
#endif
- case PHOTOMETRIC_LOGL:
- return "CIELog2L";
- case PHOTOMETRIC_LOGLUV:
- return "CIELog2Luv";
- }
- sprintf(buf,"Unknonw Tag %d",pmtc);
- return buf;
+ case PHOTOMETRIC_LOGL:
+ return "CIELog2L";
+ case PHOTOMETRIC_LOGLUV:
+ return "CIELog2Luv";
+ }
+ sprintf(buf,"Unknonw Tag %d",pmtc);
+ return buf;
}
/* Callbacks used to initialise imdi */
/* Information needed from a profile */
struct _profinfo {
- char name[100];
- icmFile *fp;
- icc *c;
- icmHeader *h;
- icRenderingIntent intent;
- icmLuBase *luo; /* Base Lookup type object */
- icmLuAlgType alg; /* Type of lookup algorithm */
- int chan; /* Device channels */
+ char name[100];
+ icmFile *fp;
+ icc *c;
+ icmHeader *h;
+ icRenderingIntent intent;
+ icmLuBase *luo; /* Base Lookup type object */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+ int chan; /* Device channels */
}; typedef struct _profinfo profinfo;
/* Context for imdi setup callbacks */
typedef struct {
- /* Overall parameters */
- int verb; /* Non-zero if verbose */
- icColorSpaceSignature ins, outs; /* Input/Output spaces */
- int id, od; /* Input/Output dimensions */
- int icombine; /* Non-zero if input curves are to be combined */
- int ocombine; /* Non-zero if output curves are to be combined */
- int link; /* Non-zero if input and output profiles are to be linked */
-
- profinfo dev; /* Device link profile */
- profinfo in; /* Device to PCS profile */
- profinfo out; /* PCS to Device profile */
+ /* Overall parameters */
+ int verb; /* Non-zero if verbose */
+ icColorSpaceSignature ins, outs; /* Input/Output spaces */
+ int id, od; /* Input/Output dimensions */
+ int icombine; /* Non-zero if input curves are to be combined */
+ int ocombine; /* Non-zero if output curves are to be combined */
+ int link; /* Non-zero if input and output profiles are to be linked */
+
+ profinfo dev; /* Device link profile */
+ profinfo in; /* Device to PCS profile */
+ profinfo out; /* PCS to Device profile */
} sucntx;
/* Input curve function */
double input_curve(
- void *cntx,
- int ch,
- double in_val
+ void *cntx,
+ int ch,
+ double in_val
) {
- sucntx *rx = (sucntx *)cntx;
- int i;
- double vals[MAX_CHAN];
-
- if (rx->icombine)
- return in_val;
-
- if (rx->link) {
-
- for (i = 0; i < rx->id; i++)
- vals[i] = 0.0;
- vals[ch] = in_val;
-
- switch(rx->in.alg) {
- case icmMonoFwdType: {
- icmLuMono *lu = (icmLuMono *)rx->in.luo; /* Safe to coerce */
- lu->fwd_curve(lu, vals, vals);
- break;
- }
- case icmMatrixFwdType: {
- icmLuMatrix *lu = (icmLuMatrix *)rx->in.luo; /* Safe to coerce */
- lu->fwd_curve(lu, vals, vals);
- break;
- }
- case icmLutType: {
- icmLuLut *lu = (icmLuLut *)rx->in.luo; /* Safe to coerce */
- /* Since not PCS, in_abs and matrix cannot be valid, */
- /* so input curve on own is ok to use. */
- lu->input(lu, vals, vals);
- break;
- }
- default:
- error("Unexpected algorithm type in input curve");
- }
- } else {
- icmLuLut *lu = (icmLuLut *)rx->dev.luo; /* Safe to coerce */
-
- for (i = 0; i < rx->id; i++)
- vals[i] = 0.0;
- vals[ch] = in_val;
-
- /* Since input not PCS, in_abs and matrix cannot be valid, */
- /* so input curve on own is ok to use. */
- lu->input(lu, vals, vals);
-
- }
- return vals[ch];
+ sucntx *rx = (sucntx *)cntx;
+ int i;
+ double vals[MAX_CHAN];
+
+ if (rx->icombine)
+ return in_val;
+
+ if (rx->link) {
+
+ for (i = 0; i < rx->id; i++)
+ vals[i] = 0.0;
+ vals[ch] = in_val;
+
+ switch(rx->in.alg) {
+ case icmMonoFwdType: {
+ icmLuMono *lu = (icmLuMono *)rx->in.luo; /* Safe to coerce */
+ lu->fwd_curve(lu, vals, vals);
+ break;
+ }
+ case icmMatrixFwdType: {
+ icmLuMatrix *lu = (icmLuMatrix *)rx->in.luo; /* Safe to coerce */
+ lu->fwd_curve(lu, vals, vals);
+ break;
+ }
+ case icmLutType: {
+ icmLuLut *lu = (icmLuLut *)rx->in.luo; /* Safe to coerce */
+ /* Since not PCS, in_abs and matrix cannot be valid, */
+ /* so input curve on own is ok to use. */
+ lu->input(lu, vals, vals);
+ break;
+ }
+ default:
+ error("Unexpected algorithm type in input curve");
+ }
+ } else {
+ icmLuLut *lu = (icmLuLut *)rx->dev.luo; /* Safe to coerce */
+
+ for (i = 0; i < rx->id; i++)
+ vals[i] = 0.0;
+ vals[ch] = in_val;
+
+ /* Since input not PCS, in_abs and matrix cannot be valid, */
+ /* so input curve on own is ok to use. */
+ lu->input(lu, vals, vals);
+
+ }
+ return vals[ch];
}
/* Multi-dim table function */
@@ -401,98 +399,98 @@ void *cntx,
double *out_vals,
double *in_vals
) {
- sucntx *rx = (sucntx *)cntx;
- double pcsv[3];
- int i;
-
- if (rx->link) {
- double vals[MAX_CHAN];
-
- switch(rx->in.alg) {
- case icmMonoFwdType: {
- icmLuMono *lu = (icmLuMono *)rx->in.luo; /* Safe to coerce */
- if (rx->icombine) {
- lu->fwd_curve(lu, vals, in_vals);
- lu->fwd_map(lu, pcsv, vals);
- } else {
- lu->fwd_map(lu, pcsv, in_vals);
- }
- lu->fwd_abs(lu, pcsv, pcsv);
- break;
- }
- case icmMatrixFwdType: {
- icmLuMatrix *lu = (icmLuMatrix *)rx->in.luo; /* Safe to coerce */
- if (rx->icombine) {
- lu->fwd_curve(lu, vals, in_vals);
- lu->fwd_matrix(lu, pcsv, vals);
- } else {
- lu->fwd_matrix(lu, pcsv, in_vals);
- }
- lu->fwd_abs(lu, pcsv, pcsv);
- break;
- }
- case icmLutType: {
- icmLuLut *lu = (icmLuLut *)rx->in.luo; /* Safe to coerce */
- if (rx->icombine) {
- /* Since not PCS, in_abs and matrix cannot be valid, */
- /* so input curve on own is ok to use. */
- lu->input(lu, vals, in_vals);
- lu->clut(lu, pcsv, vals);
- } else {
- lu->clut(lu, pcsv, in_vals);
- }
- lu->output(lu, pcsv, pcsv);
- lu->out_abs(lu, pcsv, pcsv);
- break;
- }
- default:
- error("Unexpected algorithm type in clut lookup");
- }
-
- switch(rx->out.alg) {
- case icmMonoBwdType: {
- icmLuMono *lu = (icmLuMono *)rx->out.luo; /* Safe to coerce */
- lu->bwd_abs(lu, pcsv, pcsv);
- lu->bwd_map(lu, out_vals, pcsv);
- if (rx->ocombine) {
- lu->bwd_curve(lu, out_vals, out_vals);
- }
- break;
- }
- case icmMatrixBwdType: {
- icmLuMatrix *lu = (icmLuMatrix *)rx->out.luo; /* Safe to coerce */
- lu->bwd_abs(lu, pcsv, pcsv);
- lu->bwd_matrix(lu, out_vals, pcsv);
- if (rx->ocombine) {
- lu->bwd_curve(lu, out_vals, out_vals);
- }
- break;
- }
- case icmLutType: {
- icmLuLut *lu = (icmLuLut *)rx->out.luo; /* Safe to coerce */
- lu->in_abs(lu, pcsv, pcsv);
- lu->matrix(lu, pcsv, pcsv);
- lu->input(lu, pcsv, pcsv);
- lu->clut(lu, out_vals, pcsv);
- if (rx->ocombine) {
- lu->output(lu, out_vals, out_vals);
- /* Since not PCS, out_abs is never used */
- }
- break;
- }
-
- default:
- error("Unexpected algorithm type in clut lookup");
- }
- } else {
- icmLuLut *lu = (icmLuLut *)rx->dev.luo; /* Safe to coerce */
-
- if (rx->icombine && rx->ocombine) {
- lu->lookup((icmLuBase *)lu, out_vals, in_vals); /* Do everything here */
- } else {
- lu->clut(lu, out_vals, in_vals);
- }
- }
+ sucntx *rx = (sucntx *)cntx;
+ double pcsv[3];
+ int i;
+
+ if (rx->link) {
+ double vals[MAX_CHAN];
+
+ switch(rx->in.alg) {
+ case icmMonoFwdType: {
+ icmLuMono *lu = (icmLuMono *)rx->in.luo; /* Safe to coerce */
+ if (rx->icombine) {
+ lu->fwd_curve(lu, vals, in_vals);
+ lu->fwd_map(lu, pcsv, vals);
+ } else {
+ lu->fwd_map(lu, pcsv, in_vals);
+ }
+ lu->fwd_abs(lu, pcsv, pcsv);
+ break;
+ }
+ case icmMatrixFwdType: {
+ icmLuMatrix *lu = (icmLuMatrix *)rx->in.luo; /* Safe to coerce */
+ if (rx->icombine) {
+ lu->fwd_curve(lu, vals, in_vals);
+ lu->fwd_matrix(lu, pcsv, vals);
+ } else {
+ lu->fwd_matrix(lu, pcsv, in_vals);
+ }
+ lu->fwd_abs(lu, pcsv, pcsv);
+ break;
+ }
+ case icmLutType: {
+ icmLuLut *lu = (icmLuLut *)rx->in.luo; /* Safe to coerce */
+ if (rx->icombine) {
+ /* Since not PCS, in_abs and matrix cannot be valid, */
+ /* so input curve on own is ok to use. */
+ lu->input(lu, vals, in_vals);
+ lu->clut(lu, pcsv, vals);
+ } else {
+ lu->clut(lu, pcsv, in_vals);
+ }
+ lu->output(lu, pcsv, pcsv);
+ lu->out_abs(lu, pcsv, pcsv);
+ break;
+ }
+ default:
+ error("Unexpected algorithm type in clut lookup");
+ }
+
+ switch(rx->out.alg) {
+ case icmMonoBwdType: {
+ icmLuMono *lu = (icmLuMono *)rx->out.luo; /* Safe to coerce */
+ lu->bwd_abs(lu, pcsv, pcsv);
+ lu->bwd_map(lu, out_vals, pcsv);
+ if (rx->ocombine) {
+ lu->bwd_curve(lu, out_vals, out_vals);
+ }
+ break;
+ }
+ case icmMatrixBwdType: {
+ icmLuMatrix *lu = (icmLuMatrix *)rx->out.luo; /* Safe to coerce */
+ lu->bwd_abs(lu, pcsv, pcsv);
+ lu->bwd_matrix(lu, out_vals, pcsv);
+ if (rx->ocombine) {
+ lu->bwd_curve(lu, out_vals, out_vals);
+ }
+ break;
+ }
+ case icmLutType: {
+ icmLuLut *lu = (icmLuLut *)rx->out.luo; /* Safe to coerce */
+ lu->in_abs(lu, pcsv, pcsv);
+ lu->matrix(lu, pcsv, pcsv);
+ lu->input(lu, pcsv, pcsv);
+ lu->clut(lu, out_vals, pcsv);
+ if (rx->ocombine) {
+ lu->output(lu, out_vals, out_vals);
+ /* Since not PCS, out_abs is never used */
+ }
+ break;
+ }
+
+ default:
+ error("Unexpected algorithm type in clut lookup");
+ }
+ } else {
+ icmLuLut *lu = (icmLuLut *)rx->dev.luo; /* Safe to coerce */
+
+ if (rx->icombine && rx->ocombine) {
+ lu->lookup((icmLuBase *)lu, out_vals, in_vals); /* Do everything here */
+ } else {
+ lu->clut(lu, out_vals, in_vals);
+ }
+ }
}
/* Output curve function */
@@ -501,690 +499,688 @@ void *cntx,
int ch,
double in_val
) {
- sucntx *rx = (sucntx *)cntx;
- int i;
- double vals[MAX_CHAN];
-
- if (rx->ocombine)
- return in_val;
-
- if (rx->link) {
- for (i = 0; i < rx->od; i++)
- vals[i] = 0.0;
- vals[ch] = in_val;
-
- switch(rx->out.alg) {
- case icmMonoBwdType: {
- icmLuMono *lu = (icmLuMono *)rx->out.luo; /* Safe to coerce */
- lu->bwd_curve(lu, vals, vals);
- break;
- }
- case icmMatrixBwdType: {
- icmLuMatrix *lu = (icmLuMatrix *)rx->out.luo; /* Safe to coerce */
- lu->bwd_curve(lu, vals, vals);
- break;
- }
- case icmLutType: {
- icmLuLut *lu = (icmLuLut *)rx->out.luo; /* Safe to coerce */
- lu->output(lu, vals, vals);
- /* Since not PCS, out_abs is never used */
- break;
- }
- default:
- error("Unexpected algorithm type in devop_devo()");
- }
-
- } else {
- icmLuLut *lu = (icmLuLut *)rx->dev.luo; /* Safe to coerce */
-
- for (i = 0; i < rx->od; i++)
- vals[i] = 0.0;
- vals[ch] = in_val;
-
- /* Since output not PCS, out_abs cannot be valid, */
- lu->output(lu, vals, vals);
-
- }
- return vals[ch];
+ sucntx *rx = (sucntx *)cntx;
+ int i;
+ double vals[MAX_CHAN];
+
+ if (rx->ocombine)
+ return in_val;
+
+ if (rx->link) {
+ for (i = 0; i < rx->od; i++)
+ vals[i] = 0.0;
+ vals[ch] = in_val;
+
+ switch(rx->out.alg) {
+ case icmMonoBwdType: {
+ icmLuMono *lu = (icmLuMono *)rx->out.luo; /* Safe to coerce */
+ lu->bwd_curve(lu, vals, vals);
+ break;
+ }
+ case icmMatrixBwdType: {
+ icmLuMatrix *lu = (icmLuMatrix *)rx->out.luo; /* Safe to coerce */
+ lu->bwd_curve(lu, vals, vals);
+ break;
+ }
+ case icmLutType: {
+ icmLuLut *lu = (icmLuLut *)rx->out.luo; /* Safe to coerce */
+ lu->output(lu, vals, vals);
+ /* Since not PCS, out_abs is never used */
+ break;
+ }
+ default:
+ error("Unexpected algorithm type in devop_devo()");
+ }
+
+ } else {
+ icmLuLut *lu = (icmLuLut *)rx->dev.luo; /* Safe to coerce */
+
+ for (i = 0; i < rx->od; i++)
+ vals[i] = 0.0;
+ vals[ch] = in_val;
+
+ /* Since output not PCS, out_abs cannot be valid, */
+ lu->output(lu, vals, vals);
+
+ }
+ return vals[ch];
}
-
int
main(int argc, char *argv[]) {
- int fa,nfa; /* argument we're looking at */
- char in_name[100]; /* Raster file name */
- char out_name[100]; /* Raster file name */
- int slow = 0;
- int check = 0;
- int i, rv = 0;
-
- TIFF *rh = NULL, *wh = NULL;
- int x, y, width, height; /* Size of image */
- uint16 samplesperpixel, bitspersample;
- int no_pmtc; /* Number of input photometrics */
- uint16 photometric, pmtc[10]; /* Photometrics of input file, and input profile */
- uint16 pconfig; /* Planar configuration */
- uint16 resunits;
- float resx, resy;
- tdata_t *inbuf, *outbuf, *checkbuf;
-
- /* IMDI */
- imdi *s = NULL;
- sucntx su; /* Setup context */
- unsigned char *inp[MAX_CHAN];
- unsigned char *outp[MAX_CHAN];
- int clutres = 33;
-
- /* Error check */
- int mxerr = 0;
- double avgerr = 0.0;
- double avgcount = 0.0;
-
- if (argc < 2)
- usage();
-
- su.verb = 0;
- su.icombine = 0;
- su.ocombine = 0;
- su.link = 0;
- su.in.intent = icmDefaultIntent;
- su.out.intent = icmDefaultIntent;
-
- /* 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();
-
- /* Slow, Precise */
- else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
- slow = 1;
- }
-
- /* Combine per channel curves */
- else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
- su.icombine = 1;
- su.ocombine = 1;
- }
-
- /* Check curves */
- else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
- check = 1;
- }
-
- /* Link profiles */
- else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
- su.link = 1;
- }
-
- /* Input profile Intent */
- else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
- fa = nfa;
- if (na == NULL) usage();
- switch (na[0]) {
- case 'p':
- case 'P':
- su.in.intent = icPerceptual;
- break;
- case 'r':
- case 'R':
- su.in.intent = icRelativeColorimetric;
- break;
- case 's':
- case 'S':
- su.in.intent = icSaturation;
- break;
- case 'a':
- case 'A':
- su.in.intent = icAbsoluteColorimetric;
- break;
- default:
- usage();
- }
- }
-
- /* Output profile Intent */
- else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
- fa = nfa;
- if (na == NULL) usage();
- switch (na[0]) {
- case 'p':
- case 'P':
- su.out.intent = icPerceptual;
- break;
- case 'r':
- case 'R':
- su.out.intent = icRelativeColorimetric;
- break;
- case 's':
- case 'S':
- su.out.intent = icSaturation;
- break;
- case 'a':
- case 'A':
- su.out.intent = icAbsoluteColorimetric;
- break;
- default:
- usage();
- }
- }
-
- /* Verbosity */
- else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
- su.verb = 1;
- }
-
- else
- usage();
- } else
- break;
- }
-
- if (su.link) {
- if (fa >= argc || argv[fa][0] == '-') usage();
- strcpy(su.in.name,argv[fa++]);
-
- if (fa >= argc || argv[fa][0] == '-') usage();
- strcpy(su.out.name,argv[fa++]);
- } else {
- if (fa >= argc || argv[fa][0] == '-') usage();
- strcpy(su.dev.name,argv[fa++]);
- }
-
- if (fa >= argc || argv[fa][0] == '-') usage();
- strcpy(in_name,argv[fa++]);
-
- if (fa >= argc || argv[fa][0] == '-') usage();
- strcpy(out_name,argv[fa++]);
-
- /* - - - - - - - - - - - - - - - - */
-
- if (su.link) {
- icColorSpaceSignature natpcs;
-
- /* Open up the input device profile for reading */
- if ((su.in.fp = new_icmFileStd_name(su.in.name,"r")) == NULL)
- error ("Can't open file '%s'",su.in.name);
-
- if ((su.in.c = new_icc()) == NULL)
- error ("Creation of Input profile ICC object failed");
-
- /* Read header etc. */
- if ((rv = su.in.c->read(su.in.c,su.in.fp,0)) != 0)
- error ("%d, %s on file '%s'",rv,su.in.c->err,su.in.name);
- su.in.h = su.in.c->header;
-
- /* Check that it is a suitable device input icc */
- if (su.in.h->deviceClass != icSigInputClass
- && su.in.h->deviceClass != icSigDisplayClass
- && su.in.h->deviceClass != icSigOutputClass
- && su.in.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
- error("Input profile isn't a device profile");
-
- /* Get a conversion object */
- if ((su.in.luo = su.in.c->get_luobj(su.in.c, icmFwd, su.in.intent,
- icSigLabData, icmLuOrdNorm)) == NULL)
- error ("%d, %s for profile '%s'",su.in.c->errc, su.in.c->err, su.in.name);
-
- /* Get details of conversion (Arguments may be NULL if info not needed) */
- su.in.luo->spaces(su.in.luo, &su.ins, &su.id, NULL, NULL, &su.in.alg, NULL, NULL, NULL);
-
- /* Get native PCS space */
- su.in.luo->lutspaces(su.in.luo, NULL, NULL, NULL, NULL, &natpcs);
-
- if (natpcs == icSigXYZData) {
- su.icombine = 1; /* XYZ is to non-linear to be a benefit */
- }
-
- /* Open up the output device profile for reading */
- if ((su.out.fp = new_icmFileStd_name(su.out.name,"r")) == NULL)
- error ("Can't open file '%s'",su.out.name);
-
- if ((su.out.c = new_icc()) == NULL)
- error ("Creation of Output profile ICC object failed");
-
- /* Read header etc. */
- if ((rv = su.out.c->read(su.out.c,su.out.fp,0)) != 0)
- error ("%d, %s on file '%s'",rv,su.out.c->err,su.out.name);
- su.out.h = su.out.c->header;
-
- /* Check that it is a suitable device output icc */
- if (su.out.h->deviceClass != icSigInputClass
- && su.out.h->deviceClass != icSigDisplayClass
- && su.out.h->deviceClass != icSigOutputClass
- && su.out.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
- error("Output profile isn't a device profile");
-
- /* Get a conversion object */
- if ((su.out.luo = su.out.c->get_luobj(su.out.c, icmBwd, su.out.intent,
- icSigLabData, icmLuOrdNorm)) == NULL)
- error ("%d, %s for profile '%s'",su.out.c->errc, su.out.c->err, su.out.name);
-
- /* Get details of conversion (Arguments may be NULL if info not needed) */
- su.out.luo->spaces(su.out.luo, NULL, NULL, &su.outs, &su.od, &su.out.alg, NULL, NULL, NULL);
-
- /* Get native PCS space */
- su.out.luo->lutspaces(su.out.luo, NULL, NULL, NULL, NULL, &natpcs);
-
- if (natpcs == icSigXYZData) {
- su.ocombine = 1; /* XYZ is to non-linear to be a benefit */
- }
-
- /* See discussion in imdi/imdi_gen.c for ideal numbers */
- /* Use "high quality" resolution numbers */
- switch (su.id) {
- case 0:
- error ("Illegal number of input chanels");
- case 1:
- clutres = 256;
- break;
- case 2:
- clutres = 256;
- break;
- case 3:
- clutres = 33;
- break;
- case 4:
- clutres = 18;
- break;
- case 5:
- clutres = 16;
- break;
- case 6:
- clutres = 9;
- break;
- case 7:
- clutres = 7;
- break;
- case 8:
- clutres = 6;
- break;
- deault: /* > 8 chan */
- clutres = 3;
- break;
- }
-
- } else {
- icmLut *lut; /* ICC LUT table */
- icmLuLut *luluo; /* LUT lookup object */
-
- /* Open up the device link profile for reading */
- if ((su.dev.fp = new_icmFileStd_name(su.dev.name,"r")) == NULL)
- error ("Can't open file '%s'",su.dev.name);
-
- if ((su.dev.c = new_icc()) == NULL)
- error ("Creation of ICC object failed");
-
- if ((rv = su.dev.c->read(su.dev.c, su.dev.fp, 0)) != 0)
- error ("%d, %s",rv,su.dev.c->err);
- su.dev.h = su.dev.c->header;
-
- if (su.verb) {
- icmFile *op;
- if ((op = new_icmFileStd_fp(stdout)) == NULL)
- error ("Can't open stdout");
- su.dev.h->dump(su.dev.h, op, 1);
- op->del(op);
- }
-
- /* Check that the profile is appropriate */
- if (su.dev.h->deviceClass != icSigLinkClass)
- error("Profile isn't a device link profile");
-
- /* Get a conversion object */
- if ((su.dev.luo = su.dev.c->get_luobj(su.dev.c, icmFwd, icmDefaultIntent,
- icmSigDefaultData, icmLuOrdNorm)) == NULL)
- error ("%d, %s",su.dev.c->errc, su.dev.c->err);
-
- /* Get details of conversion (Arguments may be NULL if info not needed) */
- su.dev.luo->spaces(su.dev.luo, &su.ins, &su.id, &su.outs, &su.od, &su.dev.alg, NULL, NULL, NULL);
-
- if (su.dev.alg != icmLutType)
- error ("DeviceLink profile doesn't have Lut !");
-
- luluo = (icmLuLut *)su.dev.luo; /* Safe to coerce */
- luluo->get_info(luluo, &lut, NULL, NULL, NULL); /* Get some details */
- clutres = lut->clutPoints; /* Desired table resolution */
- }
-
- /* - - - - - - - - - - - - - - - */
- /* Open up input tiff file ready for reading */
- /* Got arguments, so setup to process the file */
- if ((rh = TIFFOpen(in_name, "r")) == NULL)
- error("error opening read file '%s'",in_name);
-
- TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
- TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
-
- TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
- if (bitspersample != 8 && bitspersample != 16) {
- error("TIFF Input file must be 8 or 16 bit/channel");
- }
-
- TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);
- if ((no_pmtc = ColorSpaceSignature2TiffPhotometric(pmtc, su.ins)) == 0)
- error("ICC input colorspace '%s' can't be handled by a TIFF file!",
- icm2str(icmColorSpaceSignature, su.ins));
- for (i = 0; i < no_pmtc; i++) {
- if (pmtc[i] == photometric)
- break; /* Matches */
- }
- if (i >= no_pmtc) {
- switch (no_pmtc) {
- case 1:
- error("ICC input colorspace '%s' doesn't match TIFF photometric '%s'!",
- icm2str(icmColorSpaceSignature, su.ins), Photometric2str(pmtc[0]));
- case 2:
- error("ICC input colorspace '%s' doesn't match TIFF photometric '%s' or '%s'!",
- icm2str(icmColorSpaceSignature, su.ins), Photometric2str(pmtc[0]),
- Photometric2str(pmtc[1]));
- default:
- error("ICC input colorspace '%s' doesn't match TIFF photometric '%s', '%s' or '%s'!",
- icm2str(icmColorSpaceSignature, su.ins), Photometric2str(pmtc[0]),
- Photometric2str(pmtc[1]), Photometric2str(pmtc[2]));
- }
- }
-
- TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
- if (su.id != samplesperpixel)
- error ("TIFF Input file has %d input channels mismatched to colorspace '%s'",
- samplesperpixel, icm2str(icmColorSpaceSignature, su.ins));
-
- TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
- if (pconfig != PLANARCONFIG_CONTIG)
- error ("TIFF Input file must be planar");
-
- TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits);
- TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
- TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);
-
- /* - - - - - - - - - - - - - - - */
- if ((wh = TIFFOpen(out_name, "w")) == NULL)
- error("Can\'t create TIFF file '%s'!",out_name);
-
- TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, width);
- TIFFSetField(wh, TIFFTAG_IMAGELENGTH, height);
- TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
- TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, su.od);
- TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, bitspersample);
- TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
- if ((no_pmtc = ColorSpaceSignature2TiffPhotometric(pmtc, su.outs)) == 0)
- error("TIFF file can't handle output colorspace '%s'!",
- icm2str(icmColorSpaceSignature, su.outs));
- TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, pmtc[0]); /* Use first returned */
- if (pmtc[0] == PHOTOMETRIC_SEPARATED) {
- int iset;
- int inlen;
- char *inames;
- iset = ColorSpaceSignature2TiffInkset(su.outs, &inlen, &inames);
- if (iset != 0xffff && inlen > 0 && inames != NULL) {
- TIFFSetField(wh, TIFFTAG_INKSET, iset);
- if (inames != NULL) {
- TIFFSetField(wh, TIFFTAG_INKNAMES, inlen, inames);
- }
- }
- }
- TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
- if (resunits) {
- TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits);
- TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx);
- TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy);
- }
- TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "Color corrected by Argyll");
-
- /* - - - - - - - - - - - - - - - */
- /* Setup the imdi */
-
- if (!slow) {
- s = new_imdi(
- su.id, /* Number of input dimensions */
- su.od, /* Number of output dimensions */
- /* Input pixel representation */
- bitspersample == 8 ? pixint8 : pixint16,
- /* Output pixel representation */
- 0x0, /* Treat every channel as unsigned */
- bitspersample == 8 ? pixint8 : pixint16,
- 0x0, /* Treat every channel as unsigned */
- clutres, /* Desired table resolution */
- input_curve, /* Callback functions */
- md_table,
- output_curve,
- (void *)&su /* Context to callbacks */
- );
-
- if (s == NULL)
- error("new_imdi failed");
- }
-
- /* - - - - - - - - - - - - - - - */
- /* Process colors to translate */
- /* (Should fix this to process a group of lines at a time ?) */
-
- inbuf = _TIFFmalloc(TIFFScanlineSize(rh));
- outbuf = _TIFFmalloc(TIFFScanlineSize(wh));
- if (check)
- checkbuf = _TIFFmalloc(TIFFScanlineSize(wh));
-
- inp[0] = (unsigned char *)inbuf;
- outp[0] = (unsigned char *)outbuf;
-
- if (!slow) { /* Fast */
- for (y = 0; y < height; y++) {
-
- /* Read in the next line */
- if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
- error ("Failed to read TIFF line %d",y);
-
- /* Do fast conversion */
- s->interp(s, (void **)outp, (void **)inp, width);
-
- if (check) {
- /* Do floating point conversion */
- for (x = 0; x < width; x++) {
- int i;
- double in[MAX_CHAN], out[MAX_CHAN];
-
- if (bitspersample == 8)
- for (i = 0; i < su.id; i++)
- in[i] = ((unsigned char *)inbuf)[x * su.id + i]/255.0;
- else
- for (i = 0; i < su.id; i++)
- in[i] = ((unsigned short *)inbuf)[x * su.id + i]/65535.0;
-
- if (su.link) {
- if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- } else {
- if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- }
-
- if (bitspersample == 8)
- for (i = 0; i < su.od; i++)
- ((unsigned char *)checkbuf)[x * su.od + i] = (int)(out[i] * 255.0 + 0.5);
- else
- for (i = 0; i < su.od; i++)
- ((unsigned short *)checkbuf)[x * su.od + i] = (int)(out[i] * 65535.0 + 0.5);
- }
- /* Compute the errors */
- for (x = 0; x < (width * su.od); x++) {
- int err;
- if (bitspersample == 8)
- err = ((unsigned char *)outbuf)[x] - ((unsigned char *)checkbuf)[x];
- else
- err = ((unsigned short *)outbuf)[x] - ((unsigned short *)checkbuf)[x];
- if (err < 0)
- err = -err;
- if (err > mxerr)
- mxerr = err;
- avgerr += (double)err;
- avgcount++;
- }
- }
-
- if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
- error ("Failed to write TIFF line %d",y);
-
- }
-
- } else { /* Slow but precise */
- if (bitspersample == 8) {
- for (y = 0; y < height; y++) {
-
- /* Read in the next line */
- if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
- error ("Failed to read TIFF line %d",y);
-
- /* Do floating point conversion */
- for (x = 0; x < width; x++) {
- int i;
- double in[MAX_CHAN], out[MAX_CHAN];
-
- for (i = 0; i < su.id; i++) {
- in[i] = ((unsigned char *)inbuf)[x * su.id + i]/255.0;
- }
-
- if (su.link) {
- if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- } else {
- if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- }
-
- for (i = 0; i < su.od; i++) {
- double outi = out[i];
- if (outi < 0.0) /* Protect against sillies */
- outi = 0.0;
- else if (outi > 1.0)
- outi = 1.0;
- ((unsigned char *)outbuf)[x * su.od + i] = (int)(outi * 255.0 + 0.5);
- }
- }
- if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
- error ("Failed to write TIFF line %d",y);
- }
- } else if (bitspersample == 16) {
- for (y = 0; y < height; y++) {
-
- /* Read in the next line */
- if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
- error ("Failed to read TIFF line %d",y);
-
- /* Do floating point conversion */
- for (x = 0; x < width; x++) {
- int i;
- double in[MAX_CHAN], out[MAX_CHAN];
-
- for (i = 0; i < su.id; i++) {
- in[i] = ((unsigned short *)inbuf)[x * su.id + i]/65535.0;
- }
-
- if (su.link) {
- if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- } else {
- if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
- error ("%d, %s",su.dev.c->errc,su.dev.c->err);
- }
-
- for (i = 0; i < su.od; i++) {
- double outi = out[i];
- if (outi < 0.0) /* Protect against sillies */
- outi = 0.0;
- else if (outi > 1.0)
- outi = 1.0;
- ((unsigned short *)outbuf)[x * su.od + i] = (int)(outi * 65535.0 + 0.5);
- }
- }
- if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
- error ("Failed to write TIFF line %d",y);
- }
- }
- }
-
- if (check) {
- printf("Worst error = %d bits, average error = %f bits\n", mxerr, avgerr/avgcount);
- if (bitspersample == 8)
- printf("Worst error = %f%%, average error = %f%%\n",
- mxerr/2.55, avgerr/(2.55 * avgcount));
- else
- printf("Worst error = %f%%, average error = %f%%\n",
- mxerr/655.35, avgerr/(655.35 * avgcount));
- }
-
- /* Done with lookup object */
- if (s != NULL)
- s->done(s);
-
- if (su.link) {
- su.in.luo->del(su.in.luo);
- su.in.c->del(su.in.c);
- su.in.fp->del(su.in.fp);
- su.out.luo->del(su.out.luo);
- su.out.c->del(su.out.c);
- su.out.fp->del(su.out.fp);
- } else {
- su.dev.luo->del(su.dev.luo);
- su.dev.c->del(su.dev.c);
- su.dev.fp->del(su.dev.fp);
- }
-
- _TIFFfree(inbuf);
- _TIFFfree(outbuf);
- if (check)
- _TIFFfree(checkbuf);
-
- TIFFClose(rh); /* Close Input file */
- TIFFClose(wh); /* Close Output file */
-
- return 0;
+ int fa,nfa; /* argument we're looking at */
+ char in_name[100]; /* Raster file name */
+ char out_name[100]; /* Raster file name */
+ int slow = 0;
+ int check = 0;
+ int i, rv = 0;
+
+ TIFF *rh = NULL, *wh = NULL;
+ int x, y, width, height; /* Size of image */
+ uint16 samplesperpixel, bitspersample;
+ int no_pmtc; /* Number of input photometrics */
+ uint16 photometric, pmtc[10]; /* Photometrics of input file, and input profile */
+ uint16 pconfig; /* Planar configuration */
+ uint16 resunits;
+ float resx, resy;
+ tdata_t *inbuf, *outbuf, *checkbuf;
+
+ /* IMDI */
+ imdi *s = NULL;
+ sucntx su; /* Setup context */
+ unsigned char *inp[MAX_CHAN];
+ unsigned char *outp[MAX_CHAN];
+ int clutres = 33;
+
+ /* Error check */
+ int mxerr = 0;
+ double avgerr = 0.0;
+ double avgcount = 0.0;
+
+ if (argc < 2)
+ usage();
+
+ su.verb = 0;
+ su.icombine = 0;
+ su.ocombine = 0;
+ su.link = 0;
+ su.in.intent = icmDefaultIntent;
+ su.out.intent = icmDefaultIntent;
+
+ /* 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();
+
+ /* Slow, Precise */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ slow = 1;
+ }
+
+ /* Combine per channel curves */
+ else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
+ su.icombine = 1;
+ su.ocombine = 1;
+ }
+
+ /* Check curves */
+ else if (argv[fa][1] == 'k' || argv[fa][1] == 'K') {
+ check = 1;
+ }
+
+ /* Link profiles */
+ else if (argv[fa][1] == 'l' || argv[fa][1] == 'L') {
+ su.link = 1;
+ }
+
+ /* Input profile Intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'p':
+ case 'P':
+ su.in.intent = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ su.in.intent = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ su.in.intent = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ su.in.intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Output profile Intent */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'p':
+ case 'P':
+ su.out.intent = icPerceptual;
+ break;
+ case 'r':
+ case 'R':
+ su.out.intent = icRelativeColorimetric;
+ break;
+ case 's':
+ case 'S':
+ su.out.intent = icSaturation;
+ break;
+ case 'a':
+ case 'A':
+ su.out.intent = icAbsoluteColorimetric;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Verbosity */
+ else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
+ su.verb = 1;
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (su.link) {
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(su.in.name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(su.out.name,argv[fa++]);
+ } else {
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(su.dev.name,argv[fa++]);
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(in_name,argv[fa++]);
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(out_name,argv[fa++]);
+
+ /* - - - - - - - - - - - - - - - - */
+
+ if (su.link) {
+ icColorSpaceSignature natpcs;
+
+ /* Open up the input device profile for reading */
+ if ((su.in.fp = new_icmFileStd_name(su.in.name,"r")) == NULL)
+ error ("Can't open file '%s'",su.in.name);
+
+ if ((su.in.c = new_icc()) == NULL)
+ error ("Creation of Input profile ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = su.in.c->read(su.in.c,su.in.fp,0)) != 0)
+ error ("%d, %s on file '%s'",rv,su.in.c->err,su.in.name);
+ su.in.h = su.in.c->header;
+
+ /* Check that it is a suitable device input icc */
+ if (su.in.h->deviceClass != icSigInputClass
+ && su.in.h->deviceClass != icSigDisplayClass
+ && su.in.h->deviceClass != icSigOutputClass
+ && su.in.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
+ error("Input profile isn't a device profile");
+
+ /* Get a conversion object */
+ if ((su.in.luo = su.in.c->get_luobj(su.in.c, icmFwd, su.in.intent,
+ icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s for profile '%s'",su.in.c->errc, su.in.c->err, su.in.name);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ su.in.luo->spaces(su.in.luo, &su.ins, &su.id, NULL, NULL, &su.in.alg, NULL, NULL, NULL);
+
+ /* Get native PCS space */
+ su.in.luo->lutspaces(su.in.luo, NULL, NULL, NULL, NULL, &natpcs);
+
+ if (natpcs == icSigXYZData) {
+ su.icombine = 1; /* XYZ is to non-linear to be a benefit */
+ }
+
+ /* Open up the output device profile for reading */
+ if ((su.out.fp = new_icmFileStd_name(su.out.name,"r")) == NULL)
+ error ("Can't open file '%s'",su.out.name);
+
+ if ((su.out.c = new_icc()) == NULL)
+ error ("Creation of Output profile ICC object failed");
+
+ /* Read header etc. */
+ if ((rv = su.out.c->read(su.out.c,su.out.fp,0)) != 0)
+ error ("%d, %s on file '%s'",rv,su.out.c->err,su.out.name);
+ su.out.h = su.out.c->header;
+
+ /* Check that it is a suitable device output icc */
+ if (su.out.h->deviceClass != icSigInputClass
+ && su.out.h->deviceClass != icSigDisplayClass
+ && su.out.h->deviceClass != icSigOutputClass
+ && su.out.h->deviceClass != icSigColorSpaceClass) /* For sRGB etc. */
+ error("Output profile isn't a device profile");
+
+ /* Get a conversion object */
+ if ((su.out.luo = su.out.c->get_luobj(su.out.c, icmBwd, su.out.intent,
+ icSigLabData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s for profile '%s'",su.out.c->errc, su.out.c->err, su.out.name);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ su.out.luo->spaces(su.out.luo, NULL, NULL, &su.outs, &su.od, &su.out.alg, NULL, NULL, NULL);
+
+ /* Get native PCS space */
+ su.out.luo->lutspaces(su.out.luo, NULL, NULL, NULL, NULL, &natpcs);
+
+ if (natpcs == icSigXYZData) {
+ su.ocombine = 1; /* XYZ is to non-linear to be a benefit */
+ }
+
+ /* See discussion in imdi/imdi_gen.c for ideal numbers */
+ /* Use "high quality" resolution numbers */
+ switch (su.id) {
+ case 0:
+ error ("Illegal number of input chanels");
+ case 1:
+ clutres = 256;
+ break;
+ case 2:
+ clutres = 256;
+ break;
+ case 3:
+ clutres = 33;
+ break;
+ case 4:
+ clutres = 18;
+ break;
+ case 5:
+ clutres = 16;
+ break;
+ case 6:
+ clutres = 9;
+ break;
+ case 7:
+ clutres = 7;
+ break;
+ case 8:
+ clutres = 6;
+ break;
+ deault: /* > 8 chan */
+ clutres = 3;
+ break;
+ }
+
+ } else {
+ icmLut *lut; /* ICC LUT table */
+ icmLuLut *luluo; /* LUT lookup object */
+
+ /* Open up the device link profile for reading */
+ if ((su.dev.fp = new_icmFileStd_name(su.dev.name,"r")) == NULL)
+ error ("Can't open file '%s'",su.dev.name);
+
+ if ((su.dev.c = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = su.dev.c->read(su.dev.c, su.dev.fp, 0)) != 0)
+ error ("%d, %s",rv,su.dev.c->err);
+ su.dev.h = su.dev.c->header;
+
+ if (su.verb) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ su.dev.h->dump(su.dev.h, op, 1);
+ op->del(op);
+ }
+
+ /* Check that the profile is appropriate */
+ if (su.dev.h->deviceClass != icSigLinkClass)
+ error("Profile isn't a device link profile");
+
+ /* Get a conversion object */
+ if ((su.dev.luo = su.dev.c->get_luobj(su.dev.c, icmFwd, icmDefaultIntent,
+ icmSigDefaultData, icmLuOrdNorm)) == NULL)
+ error ("%d, %s",su.dev.c->errc, su.dev.c->err);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ su.dev.luo->spaces(su.dev.luo, &su.ins, &su.id, &su.outs, &su.od, &su.dev.alg, NULL, NULL, NULL);
+
+ if (su.dev.alg != icmLutType)
+ error ("DeviceLink profile doesn't have Lut !");
+
+ luluo = (icmLuLut *)su.dev.luo; /* Safe to coerce */
+ luluo->get_info(luluo, &lut, NULL, NULL, NULL); /* Get some details */
+ clutres = lut->clutPoints; /* Desired table resolution */
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Open up input tiff file ready for reading */
+ /* Got arguments, so setup to process the file */
+ if ((rh = TIFFOpen(in_name, "r")) == NULL)
+ error("error opening read file '%s'",in_name);
+
+ TIFFGetField(rh, TIFFTAG_IMAGEWIDTH, &width);
+ TIFFGetField(rh, TIFFTAG_IMAGELENGTH, &height);
+
+ TIFFGetField(rh, TIFFTAG_BITSPERSAMPLE, &bitspersample);
+ if (bitspersample != 8 && bitspersample != 16) {
+ error("TIFF Input file must be 8 or 16 bit/channel");
+ }
+
+ TIFFGetField(rh, TIFFTAG_PHOTOMETRIC, &photometric);
+ if ((no_pmtc = ColorSpaceSignature2TiffPhotometric(pmtc, su.ins)) == 0)
+ error("ICC input colorspace '%s' can't be handled by a TIFF file!",
+ icm2str(icmColorSpaceSignature, su.ins));
+ for (i = 0; i < no_pmtc; i++) {
+ if (pmtc[i] == photometric)
+ break; /* Matches */
+ }
+ if (i >= no_pmtc) {
+ switch (no_pmtc) {
+ case 1:
+ error("ICC input colorspace '%s' doesn't match TIFF photometric '%s'!",
+ icm2str(icmColorSpaceSignature, su.ins), Photometric2str(pmtc[0]));
+ case 2:
+ error("ICC input colorspace '%s' doesn't match TIFF photometric '%s' or '%s'!",
+ icm2str(icmColorSpaceSignature, su.ins), Photometric2str(pmtc[0]),
+ Photometric2str(pmtc[1]));
+ default:
+ error("ICC input colorspace '%s' doesn't match TIFF photometric '%s', '%s' or '%s'!",
+ icm2str(icmColorSpaceSignature, su.ins), Photometric2str(pmtc[0]),
+ Photometric2str(pmtc[1]), Photometric2str(pmtc[2]));
+ }
+ }
+
+ TIFFGetField(rh, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
+ if (su.id != samplesperpixel)
+ error ("TIFF Input file has %d input channels mismatched to colorspace '%s'",
+ samplesperpixel, icm2str(icmColorSpaceSignature, su.ins));
+
+ TIFFGetField(rh, TIFFTAG_PLANARCONFIG, &pconfig);
+ if (pconfig != PLANARCONFIG_CONTIG)
+ error ("TIFF Input file must be planar");
+
+ TIFFGetField(rh, TIFFTAG_RESOLUTIONUNIT, &resunits);
+ TIFFGetField(rh, TIFFTAG_XRESOLUTION, &resx);
+ TIFFGetField(rh, TIFFTAG_YRESOLUTION, &resy);
+
+ /* - - - - - - - - - - - - - - - */
+ if ((wh = TIFFOpen(out_name, "w")) == NULL)
+ error("Can\'t create TIFF file '%s'!",out_name);
+
+ TIFFSetField(wh, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField(wh, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField(wh, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField(wh, TIFFTAG_SAMPLESPERPIXEL, su.od);
+ TIFFSetField(wh, TIFFTAG_BITSPERSAMPLE, bitspersample);
+ TIFFSetField(wh, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ if ((no_pmtc = ColorSpaceSignature2TiffPhotometric(pmtc, su.outs)) == 0)
+ error("TIFF file can't handle output colorspace '%s'!",
+ icm2str(icmColorSpaceSignature, su.outs));
+ TIFFSetField(wh, TIFFTAG_PHOTOMETRIC, pmtc[0]); /* Use first returned */
+ if (pmtc[0] == PHOTOMETRIC_SEPARATED) {
+ int iset;
+ int inlen;
+ char *inames;
+ iset = ColorSpaceSignature2TiffInkset(su.outs, &inlen, &inames);
+ if (iset != 0xffff && inlen > 0 && inames != NULL) {
+ TIFFSetField(wh, TIFFTAG_INKSET, iset);
+ if (inames != NULL) {
+ TIFFSetField(wh, TIFFTAG_INKNAMES, inlen, inames);
+ }
+ }
+ }
+ TIFFSetField(wh, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+ if (resunits) {
+ TIFFSetField(wh, TIFFTAG_RESOLUTIONUNIT, resunits);
+ TIFFSetField(wh, TIFFTAG_XRESOLUTION, resx);
+ TIFFSetField(wh, TIFFTAG_YRESOLUTION, resy);
+ }
+ TIFFSetField(wh, TIFFTAG_IMAGEDESCRIPTION, "Color corrected by Argyll");
+
+ /* - - - - - - - - - - - - - - - */
+ /* Setup the imdi */
+
+ if (!slow) {
+ s = new_imdi(
+ su.id, /* Number of input dimensions */
+ su.od, /* Number of output dimensions */
+ /* Input pixel representation */
+ bitspersample == 8 ? pixint8 : pixint16,
+ /* Output pixel representation */
+ 0x0, /* Treat every channel as unsigned */
+ bitspersample == 8 ? pixint8 : pixint16,
+ 0x0, /* Treat every channel as unsigned */
+ clutres, /* Desired table resolution */
+ input_curve, /* Callback functions */
+ md_table,
+ output_curve,
+ (void *)&su /* Context to callbacks */
+ );
+
+ if (s == NULL)
+ error("new_imdi failed");
+ }
+
+ /* - - - - - - - - - - - - - - - */
+ /* Process colors to translate */
+ /* (Should fix this to process a group of lines at a time ?) */
+
+ inbuf = _TIFFmalloc(TIFFScanlineSize(rh));
+ outbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+ if (check)
+ checkbuf = _TIFFmalloc(TIFFScanlineSize(wh));
+
+ inp[0] = (unsigned char *)inbuf;
+ outp[0] = (unsigned char *)outbuf;
+
+ if (!slow) { /* Fast */
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do fast conversion */
+ s->interp(s, (void **)outp, (void **)inp, width);
+
+ if (check) {
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ if (bitspersample == 8)
+ for (i = 0; i < su.id; i++)
+ in[i] = ((unsigned char *)inbuf)[x * su.id + i]/255.0;
+ else
+ for (i = 0; i < su.id; i++)
+ in[i] = ((unsigned short *)inbuf)[x * su.id + i]/65535.0;
+
+ if (su.link) {
+ if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ } else {
+ if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ }
+
+ if (bitspersample == 8)
+ for (i = 0; i < su.od; i++)
+ ((unsigned char *)checkbuf)[x * su.od + i] = (int)(out[i] * 255.0 + 0.5);
+ else
+ for (i = 0; i < su.od; i++)
+ ((unsigned short *)checkbuf)[x * su.od + i] = (int)(out[i] * 65535.0 + 0.5);
+ }
+ /* Compute the errors */
+ for (x = 0; x < (width * su.od); x++) {
+ int err;
+ if (bitspersample == 8)
+ err = ((unsigned char *)outbuf)[x] - ((unsigned char *)checkbuf)[x];
+ else
+ err = ((unsigned short *)outbuf)[x] - ((unsigned short *)checkbuf)[x];
+ if (err < 0)
+ err = -err;
+ if (err > mxerr)
+ mxerr = err;
+ avgerr += (double)err;
+ avgcount++;
+ }
+ }
+
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+
+ }
+
+ } else { /* Slow but precise */
+ if (bitspersample == 8) {
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ for (i = 0; i < su.id; i++) {
+ in[i] = ((unsigned char *)inbuf)[x * su.id + i]/255.0;
+ }
+
+ if (su.link) {
+ if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ } else {
+ if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ }
+
+ for (i = 0; i < su.od; i++) {
+ double outi = out[i];
+ if (outi < 0.0) /* Protect against sillies */
+ outi = 0.0;
+ else if (outi > 1.0)
+ outi = 1.0;
+ ((unsigned char *)outbuf)[x * su.od + i] = (int)(outi * 255.0 + 0.5);
+ }
+ }
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+ }
+ } else if (bitspersample == 16) {
+ for (y = 0; y < height; y++) {
+
+ /* Read in the next line */
+ if (TIFFReadScanline(rh, inbuf, y, 0) < 0)
+ error ("Failed to read TIFF line %d",y);
+
+ /* Do floating point conversion */
+ for (x = 0; x < width; x++) {
+ int i;
+ double in[MAX_CHAN], out[MAX_CHAN];
+
+ for (i = 0; i < su.id; i++) {
+ in[i] = ((unsigned short *)inbuf)[x * su.id + i]/65535.0;
+ }
+
+ if (su.link) {
+ if ((rv = su.in.luo->lookup(su.in.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ if ((rv = su.out.luo->lookup(su.out.luo, out, out)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ } else {
+ if ((rv = su.dev.luo->lookup(su.dev.luo, out, in)) > 1)
+ error ("%d, %s",su.dev.c->errc,su.dev.c->err);
+ }
+
+ for (i = 0; i < su.od; i++) {
+ double outi = out[i];
+ if (outi < 0.0) /* Protect against sillies */
+ outi = 0.0;
+ else if (outi > 1.0)
+ outi = 1.0;
+ ((unsigned short *)outbuf)[x * su.od + i] = (int)(outi * 65535.0 + 0.5);
+ }
+ }
+ if (TIFFWriteScanline(wh, outbuf, y, 0) < 0)
+ error ("Failed to write TIFF line %d",y);
+ }
+ }
+ }
+
+ if (check) {
+ printf("Worst error = %d bits, average error = %f bits\n", mxerr, avgerr/avgcount);
+ if (bitspersample == 8)
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/2.55, avgerr/(2.55 * avgcount));
+ else
+ printf("Worst error = %f%%, average error = %f%%\n",
+ mxerr/655.35, avgerr/(655.35 * avgcount));
+ }
+
+ /* Done with lookup object */
+ if (s != NULL)
+ s->done(s);
+
+ if (su.link) {
+ su.in.luo->del(su.in.luo);
+ su.in.c->del(su.in.c);
+ su.in.fp->del(su.in.fp);
+ su.out.luo->del(su.out.luo);
+ su.out.c->del(su.out.c);
+ su.out.fp->del(su.out.fp);
+ } else {
+ su.dev.luo->del(su.dev.luo);
+ su.dev.c->del(su.dev.c);
+ su.dev.fp->del(su.dev.fp);
+ }
+
+ _TIFFfree(inbuf);
+ _TIFFfree(outbuf);
+ if (check)
+ _TIFFfree(checkbuf);
+
+ TIFFClose(rh); /* Close Input file */
+ TIFFClose(wh); /* Close Output file */
+
+ return 0;
}
-
/* Basic printf type error() and warning() routines */
void
error(char *fmt, ...)
{
- va_list args;
-
- fprintf(stderr,"cctiff: Error - ");
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- fprintf(stderr, "\n");
- exit (-1);
+ va_list args;
+
+ fprintf(stderr,"cctiff: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
}
void
warning(char *fmt, ...)
{
- va_list args;
+ va_list args;
- fprintf(stderr,"cctiff: Warning - ");
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
- fprintf(stderr, "\n");
+ fprintf(stderr,"cctiff: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
}