707 lines
22 KiB
C
707 lines
22 KiB
C
|
|
/*
|
|
* ArgyllCMS.
|
|
* Apply a device calibration to an ICC profile.
|
|
*
|
|
* Author: Graeme W. Gill
|
|
* Date: 2009/8/31
|
|
* Version: 1.00
|
|
*
|
|
* Copyright 2009 Graeme W. Gill
|
|
*
|
|
* This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
|
|
* see the License.txt file for licencing details.
|
|
*/
|
|
|
|
/* TTBD:
|
|
*
|
|
* Would be good if remove restores shared curves, rather than
|
|
* leaving duplicates.
|
|
*
|
|
* Could stash the whole cal file in a text tag.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include "copyright.h"
|
|
#include "aconfig.h"
|
|
#include "cgats.h"
|
|
#include "numlib.h"
|
|
#include "rspl.h"
|
|
#include "conv.h"
|
|
#include "xicc.h"
|
|
|
|
#undef DEBUG
|
|
|
|
#ifdef DEBUG
|
|
#undef DBG
|
|
#define DBG(xxx) printf xxx ;
|
|
#else
|
|
#undef DBG
|
|
#define DBG(xxx)
|
|
#endif
|
|
|
|
|
|
typedef icmLut1 icmLut; /* Will only work for icSigLut16Type & icSigLut8Type */
|
|
|
|
void usage(char *diag, ...) {
|
|
int i;
|
|
fprintf(stderr,"Apply device calibration to an ICC profile, Version %s\n",ARGYLL_VERSION_STR);
|
|
fprintf(stderr,"Author: Graeme W. Gill, licensed under the AGPL Version 3\n");
|
|
if (diag != NULL) {
|
|
va_list args;
|
|
fprintf(stderr," Diagnostic: ");
|
|
va_start(args, diag);
|
|
vfprintf(stderr, diag, args);
|
|
va_end(args);
|
|
fprintf(stderr,"\n");
|
|
}
|
|
fprintf(stderr,"usage: %s [-options] [calfile.cal] inprof%s [outprof%s]\n","applycal",ICC_FILE_EXT,ICC_FILE_EXT);
|
|
fprintf(stderr," -v Verbose mode\n");
|
|
fprintf(stderr," -a Apply or re-apply calibration (default)\n");
|
|
fprintf(stderr," -u Remove calibration\n");
|
|
fprintf(stderr," -c Check calibration\n");
|
|
fprintf(stderr," calfile.cal Calibration file to apply\n");
|
|
fprintf(stderr," inprof%s ICC profile to read\n",ICC_FILE_EXT);
|
|
fprintf(stderr," outprof%s modified ICC profile to write\n",ICC_FILE_EXT);
|
|
exit(2);
|
|
}
|
|
|
|
/* A primary signature and its backup */
|
|
struct _tagsigpair {
|
|
icTagSignature prim;
|
|
icTagSignature back;
|
|
int chan;
|
|
int dir; /* 0 = none or out, 1 = in */
|
|
}; typedef struct _tagsigpair tagsigpair;
|
|
|
|
int
|
|
main(int argc, char *argv[]) {
|
|
int fa,nfa; /* argument we're looking at */
|
|
static char cal_name[MAXNAMEL+1];
|
|
static char in_name[MAXNAMEL+1];
|
|
static char out_name[MAXNAMEL+1];
|
|
xcal *cal = NULL; /* Calibration to apply */
|
|
icmFile *rd_fp = NULL, *wr_fp = NULL;
|
|
icmErr err = { 0, { '\000'} };
|
|
icc *icco;
|
|
int apply = 1;
|
|
int remove = 0;
|
|
int check = 0;
|
|
int verb = 0;
|
|
int found = -1;
|
|
int rv;
|
|
|
|
|
|
if (argc < 3)
|
|
usage("Too few arguments");
|
|
|
|
/* 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("Usage requested");
|
|
|
|
else if (argv[fa][1] == 'v' || argv[fa][1] == 'V')
|
|
verb = 1;
|
|
|
|
else if (argv[fa][1] == 'a' || argv[fa][1] == 'A') {
|
|
apply = 1;
|
|
remove = 0;
|
|
check = 0;
|
|
}
|
|
|
|
else if (argv[fa][1] == 'u' || argv[fa][1] == 'U') {
|
|
apply = 0;
|
|
remove = 1;
|
|
check = 0;
|
|
}
|
|
|
|
else if (argv[fa][1] == 'c' || argv[fa][1] == 'C') {
|
|
apply = 0;
|
|
remove = 0;
|
|
check = 1;
|
|
}
|
|
|
|
else
|
|
usage("Unknown option '%s'",argv[fa][1]);
|
|
|
|
} else
|
|
break;
|
|
}
|
|
|
|
if (apply) {
|
|
if (fa >= argc || argv[fa][0] == '-') usage("Missing calibration filename");
|
|
strncpy(cal_name,argv[fa++],MAXNAMEL); cal_name[MAXNAMEL] = '\000';
|
|
}
|
|
|
|
if (fa >= argc || argv[fa][0] == '-') usage("Missing input profile filename");
|
|
strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
|
|
|
|
|
|
if (apply || remove) {
|
|
if (fa >= argc || argv[fa][0] == '-') usage("Missing output profile name");
|
|
strncpy(out_name,argv[fa++],MAXNAMEL); out_name[MAXNAMEL] = '\000';
|
|
}
|
|
if (fa < argc) usage("Extra argument '%s'",argv[fa]);
|
|
|
|
DBG(("apply %d, remove %d, check %d, calfile '%s', infile '%s', outfile '%s'\n",apply,remove,check,cal_name,in_name,out_name));
|
|
|
|
if (apply) {
|
|
/* Open up the calibration file */
|
|
if ((cal = new_xcal()) == NULL)
|
|
error("new_xcal failed");
|
|
if ((cal->read(cal, cal_name)) != 0)
|
|
error("%s",cal->e.m);
|
|
}
|
|
|
|
/* Open up the profile for reading */
|
|
if ((rd_fp = new_icmFileStd_name(&err,in_name,"r")) == NULL)
|
|
error ("Can't open file '%s' (0x%x, '%s')",in_name,err.c,err.m);
|
|
|
|
if ((icco = new_icc(&err)) == NULL)
|
|
error ("Creation of ICC object failed (0x%x, '%s')",err.c,err.m);
|
|
|
|
/* Read header etc. */
|
|
if ((rv = icco->read(icco,rd_fp,0)) != 0)
|
|
error ("%d, %s",rv,icco->e.m);
|
|
|
|
/* Read every tag */
|
|
if (icco->read_all_tags(icco) != 0) {
|
|
error("Unable to read all tags: %d, %s",icco->e.c,icco->e.m);
|
|
}
|
|
|
|
rd_fp->del(rd_fp);
|
|
|
|
/* ======================================= */
|
|
{
|
|
tagsigpair sigs[] = { /* Signatures to modify and their backups */
|
|
{ icSigProfileDescriptionTag, icmMakeTag('A','R','0','T'), 0, 0 },
|
|
{ icSigAToB0Tag, icmMakeTag('A','R','1','0'), 0, 1 },
|
|
{ icSigAToB1Tag, icmMakeTag('A','R','2','0'), 0, 1 },
|
|
{ icSigAToB2Tag, icmMakeTag('A','R','3','0'), 0, 1 },
|
|
{ icSigBToA0Tag, icmMakeTag('A','R','4','0'), 0, 0 },
|
|
{ icSigBToA1Tag, icmMakeTag('A','R','5','0'), 0, 0 },
|
|
{ icSigBToA2Tag, icmMakeTag('A','R','6','0'), 0, 0 },
|
|
{ icSigRedTRCTag, icmMakeTag('A','R','7','0'), 0, 0 },
|
|
{ icSigGreenTRCTag, icmMakeTag('A','R','7','1'), 1, 0 },
|
|
{ icSigBlueTRCTag, icmMakeTag('A','R','7','2'), 2, 0 },
|
|
{ icSigGrayTRCTag, icmMakeTag('A','R','8','0'), 0, 0 },
|
|
{ 0, 0, 0 }
|
|
};
|
|
tagsigpair linksigs[] = { /* Signatures to modify */
|
|
{ icSigProfileDescriptionTag, icmMakeTag('A','R','0','T'), 0 },
|
|
{ icSigAToB0Tag, icmMakeTag('A','R','9','1'), 1 },
|
|
{ icSigAToB0Tag, icmMakeTag('A','R','9','0'), 0 },
|
|
{ 0, 0, 0 }
|
|
};
|
|
tagsigpair *ssigp, *sigp;
|
|
int ntags = 0; /* Number of tags done */
|
|
icmBase *dtags[50]; /* Address of tags done */
|
|
int inp = 0; /* NZ for input calibration */
|
|
unsigned int i, j;
|
|
|
|
if (icco->header->deviceClass == icSigInputClass && cal->devclass != icSigInputClass) {
|
|
warning("Non-input calibration being applied to an input profile");
|
|
}
|
|
|
|
|
|
if (check) {
|
|
DBG(("Checking...\n"));
|
|
|
|
for (sigp = linksigs; sigp->prim != 0; sigp++) {
|
|
icmBase *primt;
|
|
|
|
if (sigp->prim != icSigProfileDescriptionTag)
|
|
continue;
|
|
|
|
if ((primt = icco->read_tag(icco, sigp->prim)) == NULL)
|
|
error("Can't find icSigProfileDescriptionTag in profile");
|
|
|
|
/* See if we have a backup */
|
|
if (icco->read_tag(icco, sigp->back) != NULL)
|
|
found = 1;
|
|
else
|
|
found = 0;
|
|
}
|
|
DBG(("found = %d\n",found));
|
|
if (found < 0)
|
|
error("Internal, didn't look for ProfileDescriptionTag");
|
|
|
|
if (verb) {
|
|
if (found)
|
|
printf("Profile has had calibration applied\n");
|
|
else
|
|
printf("Profile has NOT had calibration applied\n");
|
|
}
|
|
} else if (apply) {
|
|
DBG(("Applying...\n"));
|
|
|
|
if (icco->header->deviceClass == icSigInputClass
|
|
|| icco->header->deviceClass == icSigDisplayClass
|
|
|| icco->header->deviceClass == icSigOutputClass) {
|
|
|
|
DBG(("Input, display or output profile\n"));
|
|
|
|
/* Check colorspace is compatible */
|
|
if (cal->colspace != icco->header->colorSpace)
|
|
error("Calibration space %s doesn't match profile %s",
|
|
icm2str(icmColorSpaceSig, cal->colspace),
|
|
icm2str(icmColorSpaceSig, icco->header->colorSpace));
|
|
|
|
ssigp = sigs;
|
|
/* Note the cal direction */
|
|
if (cal->devclass == icSigInputClass)
|
|
inp = 1;
|
|
else
|
|
inp = 0;
|
|
|
|
} else if (icco->header->deviceClass == icSigLinkClass) {
|
|
DBG(("Device link profile\n"));
|
|
|
|
/* Check colorspace is compatible */
|
|
if (cal->colspace != icco->header->pcs)
|
|
error("Calibration space %s doesn't match profile %s",
|
|
icm2str(icmColorSpaceSig, cal->colspace),
|
|
icm2str(icmColorSpaceSig, icco->header->pcs));
|
|
ssigp = linksigs;
|
|
/* Note the cal direction */
|
|
if (cal->devclass == icSigInputClass)
|
|
inp = 1;
|
|
else
|
|
inp = 0;
|
|
} else {
|
|
error("Can't apply calibration to profile of class %s",
|
|
icm2str(icmProfileClassSig, icco->header->deviceClass));
|
|
}
|
|
DBG(("input calibration = %d\n",inp));
|
|
|
|
/* First pass is to duplicate any linked TRCTags */
|
|
for (sigp = ssigp; sigp->prim != 0; sigp++) { /* Process each tag */
|
|
icmBase *primt;
|
|
|
|
DBG(("looking for tag '%s'\n",icm2str(icmTagSig, sigp->prim)));
|
|
if ((primt = icco->read_tag(icco, sigp->prim)) == NULL) {
|
|
if (sigp->prim == icSigProfileDescriptionTag)
|
|
error("Can't find icSigProfileDescriptionTag in profile");
|
|
continue; /* Don't have this tag */
|
|
}
|
|
|
|
/* XXXXTRCTag */
|
|
if (primt->ttype == icSigCurveType) {
|
|
icmCurve *wo, *ro = (icmCurve *)primt;
|
|
|
|
/* See if we have a backup */
|
|
if ((wo = (icmCurve *)icco->read_tag(icco, sigp->back)) == NULL) {
|
|
|
|
/* If tag is shared, we need to separated it */
|
|
if (ro->refcount > 1) {
|
|
DBG(("tag is shared, so separate it\n"));
|
|
if ((wo = (icmCurve *)icco->add_tag(
|
|
icco, sigp->back, icSigCurveType)) == NULL)
|
|
error("Failed to create tag '%s'\n", icm2str(icmTagSig, sigp->back));
|
|
wo->ctype = ro->ctype;
|
|
wo->count = ro->count;
|
|
wo->allocate(wo); /* Allocate space */
|
|
for (i = 0; i < wo->count; i++) /* Copy the curve */
|
|
wo->data[i] = ro->data[i];
|
|
|
|
if (icco->delete_tag(icco, sigp->prim))
|
|
error("Failed to delete tag '%s'",icm2str(icmTagSig, sigp->prim));
|
|
if (icco->rename_tag(icco, sigp->back, sigp->prim))
|
|
error("Failed to rename tag '%s' to '%s'",
|
|
icm2str(icmTagSig, sigp->back),
|
|
icm2str(icmTagSig, sigp->prim));
|
|
}
|
|
} else {
|
|
if (ro->refcount > 1)
|
|
error("Found tag %s has backup, but is shared",icm2str(icmTagSig,sigp->prim));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Second pass we create backups and calibrated curves */
|
|
for (sigp = ssigp; sigp->prim != 0; sigp++) { /* Process each tag */
|
|
icmBase *primt;
|
|
|
|
DBG(("looking for tag '%s'\n",icm2str(icmTagSig, sigp->prim)));
|
|
if ((primt = icco->read_tag(icco, sigp->prim)) == NULL) {
|
|
if (sigp->prim == icSigProfileDescriptionTag)
|
|
error("Can't find icSigProfileDescriptionTag in profile");
|
|
continue; /* Don't have this tag */
|
|
}
|
|
|
|
/* icSigProfileDescriptionTag type */
|
|
if (ISCOMMONTEXT(primt->ttype)) {
|
|
icmCommonTextDescription *wo, *ro = (icmCommonTextDescription *)primt;
|
|
char *extra = NULL;
|
|
|
|
/* See if we've done this tag before due to links */
|
|
for (i = 0; i < ntags; i++) {
|
|
if (dtags[i] == primt)
|
|
break; /* Yes */
|
|
}
|
|
if (i < ntags) {
|
|
DBG(("Found this tag before (link)\n"));
|
|
continue; /* Skip tag */
|
|
}
|
|
if (ntags >= 50) /* Impossible */
|
|
error("Internal, run out of previuos tags space");
|
|
dtags[ntags++] = primt; /* Remember this one */
|
|
|
|
DBG(("ProfileDescriptionTag\n"));
|
|
DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSig, sigp->back)));
|
|
|
|
/* See if we have a backup */
|
|
if ((wo = (icmCommonTextDescription *)icco->read_tag(icco, sigp->back)) == NULL) {
|
|
DBG(("No backup, creating one\n"));
|
|
/* No, so create one */
|
|
if ((wo = (icmCommonTextDescription *)icco->add_tag(
|
|
icco, sigp->back, icmSigCommonTextDescriptionType)) == NULL)
|
|
error("Failed to create tag '%s' type '%s'\n", icm2str(icmTagSig, sigp->back),icm2str(icmTypeSig,icmSigCommonTextDescriptionType));
|
|
|
|
wo->count = ro->count;
|
|
wo->allocate(wo); /* Allocate space */
|
|
strcpy(wo->desc, ro->desc); /* Copy the string in */
|
|
/* Hmm. what should we do with Unicode and script ? */
|
|
} else {
|
|
DBG(("Found backup\n"));
|
|
}
|
|
|
|
if (cal->xpi.profDesc != NULL)
|
|
extra = cal->xpi.profDesc;
|
|
else
|
|
extra = cal_name;
|
|
|
|
ro->count = strlen(wo->desc) + 3 + strlen(extra) + 3;
|
|
ro->allocate(ro); /* Allocate space */
|
|
strcpy(ro->desc, wo->desc);
|
|
strcat(ro->desc, " [ ");
|
|
strcat(ro->desc, extra);
|
|
strcat(ro->desc, " ]");
|
|
|
|
DBG(("Set tag contents to '%s' len %" PFSTPREC "d size %d\n",ro->desc,strlen(ro->desc)+1,ro->count));
|
|
|
|
/* icSigAToBXTag or icSigBToAXTag */
|
|
} else if (primt->ttype == icSigLut8Type
|
|
|| primt->ttype == icSigLut16Type) {
|
|
icmLut *ro = (icmLut *)primt; /* Modified Lut */
|
|
|
|
/* See if we've done this tag before due to links */
|
|
for (i = 0; i < ntags; i++) {
|
|
if (dtags[i] == primt)
|
|
break; /* Yes */
|
|
}
|
|
if (i < ntags) {
|
|
DBG(("Found this tag before (link)\n"));
|
|
continue; /* Skip tag */
|
|
}
|
|
if (ntags >= 50) /* Impossible */
|
|
error("Internal, run out of previous tags space");
|
|
dtags[ntags++] = primt; /* Remember this one */
|
|
|
|
DBG(("Lut8 or Lut16\n"));
|
|
|
|
if (sigp->dir) {
|
|
/* Apply calibration to the input table */
|
|
for (j = 0; j < ro->inputChan; j++) {
|
|
icTagSignature bsig = sigp->back;
|
|
icmCurve *wo; /* Backup of original */
|
|
|
|
/* Create a tag per channel */
|
|
bsig += j;
|
|
|
|
DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSig, bsig)));
|
|
|
|
/* See if we have a backup */
|
|
if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL) {
|
|
DBG(("No backup, creating one\n"));
|
|
/* No, so create one */
|
|
if ((wo = (icmCurve *)icco->add_tag(
|
|
icco, bsig, icSigCurveType)) == NULL)
|
|
error("Failed to create tag '%s'\n", icm2str(icmTagSig, bsig));
|
|
wo->ctype = icmCurveSpec; /* Specified version */
|
|
wo->count = ro->inputEnt;
|
|
wo->allocate(wo); /* Allocate space */
|
|
for (i = 0; i < wo->count; i++) /* Copy the curve */
|
|
wo->data[i] = ro->pe_ic[j]->data[i];
|
|
} else {
|
|
DBG(("Found backup\n"));
|
|
}
|
|
|
|
/* Create new input curve from inv cal + orginal curve */
|
|
for (i = 0; i < ro->inputEnt; i++) {
|
|
double val;
|
|
val = i/(ro->inputEnt-1.0);
|
|
if (inp)
|
|
val = cal->interp_ch(cal, j, val); /* Do calibration */
|
|
else
|
|
val = cal->inv_interp_ch(cal, j, val); /* Undo calibration */
|
|
wo->lookup_fwd(wo, &val, &val); /* Original curve */
|
|
ro->pe_ic[j]->data[i] = val;
|
|
}
|
|
DBG(("Created calibrated input curve\n"));
|
|
}
|
|
} else {
|
|
/* Apply calibration to the output table */
|
|
for (j = 0; j < ro->outputChan; j++) {
|
|
icTagSignature bsig = sigp->back;
|
|
icmCurve *wo; /* Backup of original */
|
|
|
|
/* Create a tag per channel */
|
|
bsig += j;
|
|
|
|
DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSig, bsig)));
|
|
/* See if we have a backup */
|
|
if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL) {
|
|
DBG(("No backup, creating one\n"));
|
|
/* No, so create one */
|
|
if ((wo = (icmCurve *)icco->add_tag(
|
|
icco, bsig, icSigCurveType)) == NULL)
|
|
error("Failed to create tag '%s'\n", icm2str(icmTagSig, bsig));
|
|
|
|
wo->ctype = icmCurveSpec; /* Specified version */
|
|
wo->count = ro->outputEnt;
|
|
wo->allocate(wo); /* Allocate space */
|
|
for (i = 0; i < wo->count; i++) /* Copy the curve */
|
|
wo->data[i] = ro->pe_oc[j]->data[i];
|
|
} else {
|
|
DBG(("Found backup\n"));
|
|
}
|
|
|
|
/* Create new output curve from original + cal */
|
|
for (i = 0; i < ro->outputEnt; i++) {
|
|
double val;
|
|
val = i/(ro->outputEnt-1.0);
|
|
wo->lookup_fwd(wo, &val, &val); /* Original curve */
|
|
if (inp)
|
|
val = cal->interp_ch(cal, j, val); /* Undo calibration */
|
|
else
|
|
val = cal->interp_ch(cal, j, val); /* Do calibration */
|
|
ro->pe_oc[j]->data[i] = val;
|
|
}
|
|
DBG(("Created calibrated output curve\n"));
|
|
}
|
|
}
|
|
|
|
/* XXXXTRCTag */
|
|
} else if (primt->ttype == icSigCurveType) {
|
|
icmCurve *wo, *ro = (icmCurve *)primt;
|
|
|
|
DBG(("CurveType\n"));
|
|
|
|
DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSig, sigp->back)));
|
|
|
|
/* See if we have a backup */
|
|
if ((wo = (icmCurve *)icco->read_tag(icco, sigp->back)) == NULL) {
|
|
|
|
DBG(("No backup, creating one\n"));
|
|
/* No, so create one */
|
|
if ((wo = (icmCurve *)icco->add_tag(
|
|
icco, sigp->back, icSigCurveType)) == NULL)
|
|
error("Failed to create tag '%s'\n", icm2str(icmTagSig, sigp->back));
|
|
|
|
wo->ctype = ro->ctype;
|
|
wo->count = ro->count;
|
|
wo->allocate(wo); /* Allocate space */
|
|
for (i = 0; i < wo->count; i++) /* Copy the curve */
|
|
wo->data[i] = ro->data[i];
|
|
|
|
/* Change type & size of ro if necessary */
|
|
if (ro->ctype != icmCurveSpec || wo->count < 256) {
|
|
ro->ctype = icmCurveSpec;
|
|
ro->count = 256;
|
|
ro->allocate(ro); /* Allocate space */
|
|
}
|
|
} else {
|
|
DBG(("Found backup\n"));
|
|
}
|
|
|
|
/* Create new forward direction curve from cal + orginal curve */
|
|
j = sigp->chan;
|
|
for (i = 0; i < ro->count; i++) {
|
|
double val;
|
|
val = i/(ro->count-1.0);
|
|
val = cal->inv_interp_ch(cal, j, val); /* Inverse output calibration */
|
|
wo->lookup_fwd(wo, &val, &val); /* Original curve */
|
|
ro->data[i] = val;
|
|
}
|
|
DBG(("Created calibrated %s curve for chan %d\n",inp ? "input" : "output",j));
|
|
} else {
|
|
error("Tag %s is type %s we don't know how to handle",
|
|
icm2str(icmTagSig, sigp->prim),
|
|
icm2str(icmTypeSig, primt->ttype));
|
|
}
|
|
}
|
|
|
|
} else if (remove) {
|
|
int k;
|
|
DBG(("Removing...\n"));
|
|
for (k = 0; k < 2; k++) {
|
|
if (k == 0)
|
|
ssigp = sigs;
|
|
else if (k == 1)
|
|
ssigp = linksigs;
|
|
|
|
for (sigp = ssigp; sigp->prim != 0; sigp++) { /* Process each tag */
|
|
icmBase *backt, *primt;
|
|
|
|
DBG(("Looking for baclup tag '%s'\n",icm2str(icmTagSig, sigp->back)));
|
|
if ((backt = icco->read_tag(icco, sigp->back)) == NULL)
|
|
continue; /* Don't have this backup tag */
|
|
|
|
DBG(("Looking for primary tag '%s'\n",icm2str(icmTagSig, sigp->prim)));
|
|
if ((primt = icco->read_tag(icco, sigp->prim)) == NULL) {
|
|
error("Can't find primary tag %s for backup %s",
|
|
icm2str(icmTagSig, sigp->prim),
|
|
icm2str(icmTagSig, sigp->back));
|
|
}
|
|
|
|
/* icSigProfileDescriptionTag type */
|
|
if (ISCOMMONTEXT(primt->ttype)) {
|
|
icmCommonTextDescription *wo, *ro = (icmCommonTextDescription *)primt;
|
|
|
|
DBG(("ProfileDescriptionTag\n"));
|
|
|
|
wo = (icmCommonTextDescription *)backt;
|
|
|
|
/* Restore primary table */
|
|
ro->count = wo->count;
|
|
ro->allocate(ro); /* Reallocate space */
|
|
strcpy(ro->desc, wo->desc); /* Restore description */
|
|
|
|
/* delete backup */
|
|
if (icco->delete_tag(icco, sigp->back))
|
|
error("Failed to delete tag '%s'",icm2str(icmTagSig, sigp->prim));
|
|
DBG(("Restored primary and deleted backup\n"));
|
|
|
|
/* icSigAToBXTag or icSigBToAXTag */
|
|
} else if (primt->ttype == icSigLut8Type
|
|
|| primt->ttype == icSigLut16Type) {
|
|
icmLut *ro = (icmLut *)primt; /* Modified Lut */
|
|
|
|
if (sigp->dir) {
|
|
/* Restore the input table */
|
|
for (j = 0; j < ro->inputChan; j++) {
|
|
icTagSignature bsig = sigp->back;
|
|
icmCurve *wo; /* Backup of original */
|
|
|
|
/* Create a tag per channel */
|
|
bsig += j;
|
|
|
|
DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSig, bsig)));
|
|
|
|
/* See if we have a backup */
|
|
if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL)
|
|
error("Can't find original table data in tag %s",
|
|
icm2str(icmTagSig, sigp->back));
|
|
|
|
/* Restore primary table */
|
|
for (i = 0; i < wo->count; i++) /* Copy the curve */
|
|
ro->pe_ic[j]->data[i] = wo->data[i];
|
|
|
|
/* delete backup */
|
|
if (icco->delete_tag(icco, bsig))
|
|
error("Failed to delete tag '%s'",icm2str(icmTagSig, bsig));
|
|
DBG(("Restored primary and deleted backup\n"));
|
|
}
|
|
} else {
|
|
/* Restore the output table */
|
|
for (j = 0; j < ro->outputChan; j++) {
|
|
icTagSignature bsig = sigp->back;
|
|
icmCurve *wo; /* Backup of original */
|
|
|
|
/* Create a tag per channel */
|
|
bsig += j;
|
|
|
|
DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSig, bsig)));
|
|
|
|
/* See if we have a backup */
|
|
if ((wo = (icmCurve *)icco->read_tag(icco, bsig)) == NULL)
|
|
error("Can't find original table data in tag %s",
|
|
icm2str(icmTagSig, sigp->back));
|
|
|
|
/* Restore primary table */
|
|
for (i = 0; i < wo->count; i++) /* Copy the curve */
|
|
ro->pe_oc[j]->data[i] = wo->data[i];
|
|
|
|
/* delete backup */
|
|
if (icco->delete_tag(icco, bsig))
|
|
error("Failed to delete tag '%s'",icm2str(icmTagSig, bsig));
|
|
DBG(("Restored primary and deleted backup\n"));
|
|
}
|
|
}
|
|
|
|
/* XXXXTRCTag */
|
|
} else if (primt->ttype == icSigCurveType) {
|
|
icmCurve *wo, *ro = (icmCurve *)primt;
|
|
|
|
DBG(("CurveType\n"));
|
|
DBG(("Looking for backup tag '%s'\n",icm2str(icmTagSig, sigp->back)));
|
|
|
|
/* See if we have a backup */
|
|
wo = (icmCurve *)backt;
|
|
|
|
/* Restore primary table */
|
|
ro->ctype = wo->ctype;
|
|
ro->count = wo->count;
|
|
ro->allocate(ro); /* Allocate space */
|
|
for (i = 0; i < wo->count; i++) /* Copy the curve */
|
|
ro->data[i] = wo->data[i];
|
|
|
|
/* delete backup */
|
|
if (icco->delete_tag(icco, sigp->back))
|
|
error("Failed to delete tag '%s'",icm2str(icmTagSig, sigp->back));
|
|
DBG(("Restored primary and deleted backup\n"));
|
|
|
|
} else {
|
|
error("Tag %s is type %s we don't know how to handle",
|
|
icm2str(icmTagSig, sigp->prim),
|
|
icm2str(icmTypeSig, primt->ttype));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* ======================================= */
|
|
|
|
if (apply || remove) {
|
|
/* Open up the other profile for writing */
|
|
if ((wr_fp = new_icmFileStd_name(&err,out_name,"w")) == NULL)
|
|
error ("Can't open file '%s' (0x%x, '%s')",out_name,err.c,err.m);
|
|
|
|
if ((rv = icco->write(icco,wr_fp,0)) != 0)
|
|
error ("Write file: %d, %s",rv,icco->e.m);
|
|
wr_fp->del(wr_fp);
|
|
}
|
|
|
|
if (cal != NULL)
|
|
cal->del(cal);
|
|
icco->del(icco);
|
|
|
|
if (found == 1)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|