📄 cctiff2.c
字号:
/* * Color Correct a TIFF file, using an ICC Device link profile. * Prototype of new version that allows an arbitrary string of profiles. * * Author: Graeme W. Gill * Date: 29/5/2004 * Version: 2.00 * * Copyright 2000 - 2004 Graeme W. Gill * All rights reserved. * * This material is licenced under the GNU GENERAL PUBLIC LICENCE :- * see the Licence.txt file for licencing details. *//* * Thanks to Neil Okamoto for the 16 bit TIFF mods. *//* TTBD: Waiting on the implementation of the unified simple profile support ( Lut - Clut - Lut) to implement this. This has become entangled in ICCV4 support. Question: Should this be changed to also function as a dedicated simple linker, capable of outputing a device link ? If argyll functionality was properly modularized, it would be possible to have a single arbitrary smart link chain for both purposes. *//* 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. */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <fcntl.h>#include <string.h>#include <math.h>#include "copyright.h"#include "config.h"#include "tiffio.h"#include "icc.h"#include "imdi.h"void error(char *fmt, ...), warning(char *fmt, ...);void usage(char *mes) { 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"); if (mes != NULL) fprintf(stderr,"Error: '%s'\n",mes); fprintf(stderr,"usage: cctiff [-options] { [-i intent] profile.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," -o n Choose TIFF output encoding from 1..n\n"); fprintf(stderr,"\n"); fprintf(stderr," Then for each profile in chain:\n"); fprintf(stderr," -i intent p = perceptual, r = relative colorimetric,\n"); fprintf(stderr," s = saturation, a = absolute colorimetric\n"); fprintf(stderr," profile.icm Device, Link or Abstract profile.\n"); fprintf(stderr,"\n"); fprintf(stderr," infile.tif Input TIFF file in appropriate color space\n"); fprintf(stderr," outfile.tif Output TIFF file\n"); exit(1);}/* Conversion functions from direct binary 0..n^2-1 == 0.0 .. 1.0 range *//* to ICC luo input range, and the reverse. *//* TIFF 8 bit CIELAB to standard L*a*b* *//* Assume that a & b have been converted from signed to offset */static void cvt_CIELAB8_to_Lab(double *out, double *in) { out[0] = in[0] * 100.0; out[1] = in[1] * 255.0 - 128.0; out[2] = in[2] * 255.0 - 128.0;}/* Standard L*a*b* to TIFF 8 bit CIELAB *//* Assume that a & b will be converted from offset to signed */static void cvt_Lab_to_CIELAB8(double *out, double *in) { out[0] = in[0] / 100.0; out[1] = (in[1] + 128.0) * 1.0/255.0; out[2] = (in[2] + 128.0) * 1.0/255.0;}/* TIFF 16 bit CIELAB to standard L*a*b* *//* Assume that a & b have been converted from signed to offset */static void cvt_CIELAB16_to_Lab(double *out, double *in) { out[0] = in[0] * 100.0; out[1] = (in[1] - 32768.0/65535.0)/256.0; out[2] = (in[2] - 32768.0/65535.0)/256.0;}/* Standard L*a*b* to TIFF 16 bit CIELAB *//* Assume that a & b will be converted from offset to signed */static void cvt_Lab_to_CIELAB16(double *out, double *in) { out[0] = in[0] / 100.0; out[1] = in[1]/256.0 + 32768.0/65535.0; out[2] = in[2]/256.0 + 32768.0/65535.0;}/* TIFF 8 bit ICCLAB to standard L*a*b* */static void cvt_ICCLAB8_to_Lab(double *out, double *in) { out[0] = in[0] * 100.0; out[1] = (in[1] * 255.0) - 128.0; out[2] = (in[2] * 255.0) - 128.0;}/* Standard L*a*b* to TIFF 8 bit ICCLAB */static void cvt_Lab_to_ICCLAB8(double *out, double *in) { out[0] = in[0] * 1.0/100.0; out[1] = (in[1] + 128.0) * 1.0/255.0; out[2] = (in[2] + 128.0) * 1.0/255.0;}/* TIFF 16 bit ICCLAB to standard L*a*b* */static void cvt_ICCLAB16_to_Lab(double *out, double *in) { out[0] = in[0] * (100.0 * 65535.0)/65280.0; out[1] = (in[1] * (255.0 * 65535.0)/65280) - 128.0; out[2] = (in[2] * (255.0 * 65535.0)/65280) - 128.0;}/* Standard L*a*b* to TIFF 16 bit ICCLAB */static void cvt_Lab_to_ICCLAB16(double *out, double *in) { out[0] = in[0] * 65280.0/(100.0 * 65535.0); out[1] = (in[1] + 128.0) * 65280.0/(255.0 * 65535.0); out[2] = (in[2] + 128.0) * 65280.0/(255.0 * 65535.0);}/* Convert a TIFF Photometric tag to an ICC colorspace. *//* return 0 if not possible or applicable. */icColorSpaceSignature TiffPhotometric2ColorSpaceSignature(void (**ocvt)(double *out, double *in), /* Return write conversion function, NULL if none */void (**icvt)(double *out, double *in), /* Return read conversion function, NULL if none */int *smsk, /* Return signed handling mask, 0x0 if none */int pmtc, /* Input TIFF photometric */int bps, /* Input Bits per sample */int spp /* Input Samples per pixel */) { if (icvt != NULL) *icvt = NULL; /* Default return values */ if (ocvt != NULL) *ocvt = NULL; /* Default return values */ if (smsk != NULL) *smsk = 0x0; switch (pmtc) { case PHOTOMETRIC_MINISWHITE: /* Subtractive Gray */ return icSigGrayData; case PHOTOMETRIC_MINISBLACK: /* Additive Gray */ return icSigGrayData; case PHOTOMETRIC_RGB: return icSigRgbData; case PHOTOMETRIC_PALETTE: return 0x0; case PHOTOMETRIC_MASK: return 0x0; case PHOTOMETRIC_SEPARATED: switch(spp) { case 2: return icSig2colorData; case 3: return icSig3colorData; case 4: return icSig4colorData; case 5: return icSig5colorData; case 6: return icSig6colorData; case 7: return icSig7colorData; case 8: return icSig8colorData; case 9: return icSig9colorData; case 10: return icSig10colorData; case 11: return icSig11colorData; case 12: return icSig12colorData; case 13: return icSig13colorData; case 14: return icSig14colorData; case 15: return icSig15colorData; } case PHOTOMETRIC_YCBCR: return icSigYCbCrData; case PHOTOMETRIC_CIELAB: if (bps == 8) { if (icvt != NULL) *icvt = cvt_CIELAB8_to_Lab; if (ocvt != NULL) *ocvt = cvt_Lab_to_CIELAB8; } else { if (icvt != NULL) *icvt = cvt_CIELAB16_to_Lab; if (ocvt != NULL) *ocvt = cvt_Lab_to_CIELAB16; } *smsk = 0x6; /* Tread a & b as signed */ return icSigLabData; case PHOTOMETRIC_ICCLAB: if (bps == 8) { if (icvt != NULL) *icvt = cvt_ICCLAB8_to_Lab; if (ocvt != NULL) *ocvt = cvt_Lab_to_ICCLAB8; } else { if (icvt != NULL) *icvt = cvt_ICCLAB16_to_Lab; if (ocvt != NULL) *ocvt = cvt_Lab_to_ICCLAB16; } return icSigLabData; case PHOTOMETRIC_ITULAB: return 0x0; /* Could add this with a conversion function */ /* but have to allow for variable ITU gamut */ /* (Tag 433, "Decode") */ case PHOTOMETRIC_LOGL: return 0x0; /* Could add this with a conversion function */ case PHOTOMETRIC_LOGLUV: return 0x0; /* Could add this with a conversion function */ } return 0x0;}/* Convert an ICC colorspace to the corresponding possible TIFF Photometric tags. *//* Return the number of matching tags, and 0 if there is no corresponding tag. */intColorSpaceSignature2TiffPhotometric(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: tags[0] = PHOTOMETRIC_RGB; return 1; case icSigCmyData: case icSigCmykData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSigYCbCrData: tags[0] = PHOTOMETRIC_YCBCR; return 1; case icSigXYZData: case icSigLabData: tags[0] = PHOTOMETRIC_CIELAB; tags[1] = PHOTOMETRIC_ICCLAB;#ifdef NEVER tags[2] = PHOTOMETRIC_ITULAB;#endif return 2; case icSigLuvData: case icSigYxyData: /* Could handle this with a conversion ?? */ case icSigHsvData: case icSigHlsData: return 0; case icSig2colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig3colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig4colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig5colorData: case icSigMch5Data: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig6colorData: case icSigMch6Data: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig7colorData: case icSigMch7Data: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig8colorData: case icSigMch8Data: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig9colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig10colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig11colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig12colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig13colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig14colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; case icSig15colorData: tags[0] = PHOTOMETRIC_SEPARATED; return 1; default: return 0; } return 0;}/* Convert an ICC colorspace to the corresponding TIFF Inkset tag *//* return 0xffff if not possible or applicable. */intColorSpaceSignature2TiffInkset(icColorSpaceSignature cspace,char **inknames /* Return ASCII inknames */) { switch(cspace) { case icSigCmyData: if (inknames != NULL) *inknames = "cyan\000magenta\000yellow\000\000"; return 0; /* Not CMYK */ case icSigCmykData: if (inknames != NULL) *inknames = NULL; /* No inknames */ 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"; 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"; 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"; case PHOTOMETRIC_ICCLAB: return "ICCLab"; case PHOTOMETRIC_ITULAB: return "ITULab"; case PHOTOMETRIC_LOGL: return "CIELog2L"; case PHOTOMETRIC_LOGLUV: return "CIELog2Luv"; } sprintf(buf,"Unknown Tag %d",pmtc); return buf;}/* Callbacks used to initialise imdi *//* Information needed from a profile */struct _profinfo {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -