summaryrefslogtreecommitdiff
path: root/icc/icclu.c
diff options
context:
space:
mode:
Diffstat (limited to 'icc/icclu.c')
-rw-r--r--icc/icclu.c424
1 files changed, 424 insertions, 0 deletions
diff --git a/icc/icclu.c b/icc/icclu.c
new file mode 100644
index 0000000..ea32da0
--- /dev/null
+++ b/icc/icclu.c
@@ -0,0 +1,424 @@
+
+/*
+ * International Color Consortium Format Library (icclib)
+ * Profile color lookup utility.
+ *
+ * Author: Graeme W. Gill
+ * Date: 1999/11/29
+ * Version: 2.15
+ *
+ * Copyright 1998 - 2012 Graeme W. Gill
+ *
+ * This material is licensed with an "MIT" free use license:-
+ * see the License.txt file in this directory for licensing details.
+ */
+
+/* TTBD:
+ *
+ */
+
+/*
+
+ This file is intended to exercise the ability
+ of the icc library to translate colors through a profile.
+ It also serves as a concise example of how to do this.
+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <string.h>
+#include <math.h>
+#include "icc.h"
+
+void error(char *fmt, ...), warning(char *fmt, ...);
+
+void usage(void) {
+ fprintf(stderr,"Translate colors through an ICC profile, V%s\n",ICCLIB_VERSION_STR);
+ fprintf(stderr,"Author: Graeme W. Gill\n");
+ fprintf(stderr,"usage: icclu [-v level] [-f func] [-i intent] [-o order] profile\n");
+ fprintf(stderr," -v level Verbosity level 0 - 2 (default = 1)\n");
+ fprintf(stderr," -f function f = forward, b = backwards, g = gamut, p = preview\n");
+ fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n");
+ fprintf(stderr," s = saturation, a = absolute\n");
+// fprintf(stderr," P = absolute perceptual, S = absolute saturation\n");
+ fprintf(stderr," -p oride x = XYZ_PCS, l = Lab_PCS, y = Yxy,\n");
+ fprintf(stderr," -o order n = normal (priority: lut > matrix > monochrome)\n");
+ fprintf(stderr," r = reverse (priority: monochrome > matrix > lut)\n");
+ fprintf(stderr," -s scale Scale device range 0.0 - scale rather than 0.0 - 1.0\n");
+ fprintf(stderr,"\n");
+ fprintf(stderr," The colors to be translated should be fed into standard input,\n");
+ fprintf(stderr," one input color per line, white space separated.\n");
+ fprintf(stderr," A line starting with a # will be ignored.\n");
+ fprintf(stderr," A line not starting with a number will terminate the program.\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[]) {
+ int fa,nfa; /* argument we're looking at */
+ char prof_name[500];
+ icmFile *fp;
+ icc *icco;
+ int verb = 1;
+ double scale = 0.0; /* Device value scale factor */
+ int rv = 0;
+ int repYxy = 0; /* Report Yxy */
+ char buf[200];
+ double oin[MAX_CHAN], in[MAX_CHAN], out[MAX_CHAN];
+
+ icmLuBase *luo;
+ icColorSpaceSignature ins, outs; /* Type of input and output spaces */
+ int inn, outn; /* Number of components */
+ icmLuAlgType alg; /* Type of lookup algorithm */
+
+ /* Lookup parameters */
+ icmLookupFunc func = icmFwd; /* Default */
+ icRenderingIntent intent = icmDefaultIntent; /* Default */
+ icColorSpaceSignature pcsor = icmSigDefaultData; /* Default */
+ icmLookupOrder order = icmLuOrdNorm; /* Default */
+
+ if (argc < 2)
+ usage();
+
+ /* 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();
+
+ /* 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();
+ }
+ }
+
+ /* function */
+ else if (argv[fa][1] == 'f' || argv[fa][1] == 'F') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'f':
+ case 'F':
+ func = icmFwd;
+ break;
+ case 'b':
+ case 'B':
+ func = icmBwd;
+ break;
+ case 'g':
+ case 'G':
+ func = icmGamut;
+ break;
+ case 'p':
+ case 'P':
+ func = icmPreview;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Intent */
+ else if (argv[fa][1] == 'i' || argv[fa][1] == 'I') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'p':
+ intent = icPerceptual;
+ break;
+ case 'r':
+ intent = icRelativeColorimetric;
+ break;
+ case 's':
+ intent = icSaturation;
+ break;
+ case 'a':
+ intent = icAbsoluteColorimetric;
+ break;
+ /* Special function icclib intents */
+ case 'P':
+ intent = icmAbsolutePerceptual;
+ break;
+ case 'S':
+ intent = icmAbsoluteSaturation;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Search order */
+ else if (argv[fa][1] == 'o' || argv[fa][1] == 'O') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'n':
+ case 'N':
+ order = icmLuOrdNorm;
+ break;
+ case 'r':
+ case 'R':
+ order = icmLuOrdRev;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* PCS override */
+ else if (argv[fa][1] == 'p' || argv[fa][1] == 'P') {
+ fa = nfa;
+ if (na == NULL) usage();
+ switch (na[0]) {
+ case 'x':
+ case 'X':
+ pcsor = icSigXYZData;
+ repYxy = 0;
+ break;
+ case 'l':
+ case 'L':
+ pcsor = icSigLabData;
+ repYxy = 0;
+ break;
+ case 'y':
+ case 'Y':
+ pcsor = icSigXYZData;
+ repYxy = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ /* Device scale */
+ else if (argv[fa][1] == 's' || argv[fa][1] == 'S') {
+ fa = nfa;
+ if (na == NULL) usage();
+ scale = atof(na);
+ if (scale <= 0.0) usage();
+ }
+
+ else
+ usage();
+ } else
+ break;
+ }
+
+ if (fa >= argc || argv[fa][0] == '-') usage();
+ strcpy(prof_name,argv[fa]);
+
+ /* Open up the profile for reading */
+ if ((fp = new_icmFileStd_name(prof_name,"r")) == NULL)
+ error ("Can't open file '%s'",prof_name);
+
+ if ((icco = new_icc()) == NULL)
+ error ("Creation of ICC object failed");
+
+ if ((rv = icco->read(icco,fp,0)) != 0)
+ error ("%d, %s",rv,icco->err);
+
+ if (verb > 1) {
+ icmFile *op;
+ if ((op = new_icmFileStd_fp(stdout)) == NULL)
+ error ("Can't open stdout");
+ icco->header->dump(icco->header, op, 1);
+ op->del(op);
+ }
+
+ /* Get a conversion object */
+ if ((luo = icco->get_luobj(icco, func, intent, pcsor, order)) == NULL)
+ error ("%d, %s",icco->errc, icco->err);
+
+ /* Get details of conversion (Arguments may be NULL if info not needed) */
+ luo->spaces(luo, &ins, &inn, &outs, &outn, &alg, NULL, NULL, NULL, NULL);
+
+ if (repYxy) { /* report Yxy rather than XYZ */
+ if (ins == icSigXYZData)
+ ins = icSigYxyData;
+ if (outs == icSigXYZData)
+ outs = icSigYxyData;
+ }
+
+ /* Process colors to translate */
+ for (;;) {
+ int i,j;
+ char *bp, *nbp;
+
+ /* Init default input values */
+ for (i = 0; i < MAX_CHAN; i++) {
+ in[i] = oin[i] = 0.0;
+ }
+
+ /* Read in the next line */
+ if (fgets(buf, 200, stdin) == NULL)
+ break;
+ if (buf[0] == '#') {
+ if (verb > 0)
+ fprintf(stdout,"%s\n",buf);
+ continue;
+ }
+ /* For each input number */
+ for (bp = buf-1, nbp = buf, i = 0; i < MAX_CHAN; i++) {
+ bp = nbp;
+ in[i] = oin[i] = strtod(bp, &nbp);
+ if (nbp == bp)
+ break; /* Failed */
+ }
+ if (i == 0)
+ break;
+
+ /* If device data and scale */
+ if(scale > 0.0
+ && ins != icSigXYZData
+ && ins != icSigLabData
+ && ins != icSigLuvData
+ && ins != icSigYCbCrData
+ && ins != icSigYxyData
+ && ins != icSigHsvData
+ && ins != icSigHlsData) {
+ for (i = 0; i < MAX_CHAN; i++) {
+ in[i] /= scale;
+ }
+ }
+
+ if (repYxy && ins == icSigYxyData) {
+ double Y = in[0];
+ double x = in[1];
+ double y = in[2];
+ double z = 1.0 - x - y;
+ double sum;
+ if (y < 1e-6) {
+ in[0] = in[1] = in[2] = 0.0;
+ } else {
+ sum = Y/y;
+ in[0] = x * sum;
+ in[1] = Y;
+ in[2] = z * sum;
+ }
+ }
+
+ /* Do conversion */
+ if ((rv = luo->lookup(luo, out, in)) > 1)
+ error ("%d, %s",icco->errc,icco->err);
+
+ /* Output the results */
+ if (verb > 0) {
+ for (j = 0; j < inn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",oin[j]);
+ else
+ fprintf(stdout,"%f",oin[j]);
+ }
+ printf(" [%s] -> %s -> ", icm2str(icmColorSpaceSignature, ins),
+ icm2str(icmLuAlg, alg));
+ }
+
+ if (repYxy && outs == icSigYxyData) {
+ double X = out[0];
+ double Y = out[1];
+ double Z = out[2];
+ double sum = X + Y + Z;
+ if (sum < 1e-6) {
+ out[0] = out[1] = out[2] = 0.0;
+ } else {
+ out[0] = Y;
+ out[1] = X/sum;
+ out[2] = Y/sum;
+ }
+ }
+
+ /* If device data and scale */
+ if(scale > 0.0
+ && outs != icSigXYZData
+ && outs != icSigLabData
+ && outs != icSigLuvData
+ && outs != icSigYCbCrData
+ && outs != icSigYxyData
+ && outs != icSigHsvData
+ && outs != icSigHlsData) {
+ for (i = 0; i < MAX_CHAN; i++) {
+ out[i] *= scale;
+ }
+ }
+
+ for (j = 0; j < outn; j++) {
+ if (j > 0)
+ fprintf(stdout," %f",out[j]);
+ else
+ fprintf(stdout,"%f",out[j]);
+ }
+ if (verb > 0)
+ printf(" [%s]", icm2str(icmColorSpaceSignature, outs));
+
+ if (verb > 0 && rv != 0)
+ fprintf(stdout," (clip)");
+
+ fprintf(stdout,"\n");
+
+ }
+
+ /* Done with lookup object */
+ luo->del(luo);
+
+ icco->del(icco);
+
+ fp->del(fp);
+
+ return 0;
+}
+
+
+/* Basic printf type error() and warning() routines */
+
+void
+error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Error - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+ exit (-1);
+}
+
+void
+warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr,"icclu: Warning - ");
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}