Thanks for this. It works like a charm and is exactly what I need.
rgds Garreth Peter Speck wrote: > On 18/12/2006, at 22:25, Garreth McDaid wrote: > >> I'd like to be able to use the functionality provided by icctrans in PHP >> ie take 4 CMYK color channel values and convert them to RGB color >> channel values with reference to a CMYK and sRGB ICC profile. Once I >> have this, I can compile it into PHP. > > The code below might help. Execute program like: > ./icc-translate 0 0 0 EuroscaleCoated.icc Adobe-sRGB.icc 3 - 1.0 1.0 > 0 0 > output: > ## R=18.07 G=11.20 B=52.42 ## > > arg 1: 0 = silent or 1 = verbose > arg 2: Intent (0=Perceptual, 1=Colorimetric, 2=Saturation, 3=Absolute) > arg 3: WhiteBlackCompensation (0=False, 1=True) > arg 4: path to input profile > arg 5: path to output profile > arg 6: proof intent > arg 7: path to proof profile, or "-" if not proofing > arg 8... input colors, can specify multiple, each value is fraction > from zero to one (1 == 100%) > for cmyk, 1.0 1.0 0 0 is 100% cyan, 100% yellow, 0% magenta and 0% > black > Output is percentage, for some unknown reason... > > > I compile it using: > CFLAGS=-I/usr/local/lcms/include > LDFLAGS=-L/usr/local/lcms/lib > gcc -std=c99 $CFLAGS $LDFLAGS -l lcms -o icc-translate icc-translate.c > > > /* > Little cms > Copyright (C) 1998-2001 Marti Maria > > THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, > EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY > WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. > > IN NO EVENT SHALL MARTI MARIA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, > INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, > OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, > WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY > THEORY OF > LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE > OF THIS SOFTWARE. > > > This library is free software; you can redistribute it and/or > modify it under the terms of the GNU Lesser General Public > License as published by the Free Software Foundation; either > version 2 of the License, or (at your option) any later version. > > This library is distributed in the hope that it will be useful, > but WITHOUT ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > Lesser General Public License for more details. > > You should have received a copy of the GNU Lesser General Public > License along with this library; if not, write to the Free Software > Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 > USA > */ > > #include "lcms.h" > #include <stdarg.h> > #include <ctype.h> > > /* > ------------------------------------------------------------------------ */ > > static int Verbose = 0; > static int gArgc = 0; > static int gArgIdx = 0; > static char **gArgv = NULL; > static char *cInProf = NULL; > static char *cOutProf = NULL; > static char *cProofing = NULL; > static double outputScale = 255; > static int Intent = INTENT_PERCEPTUAL; > static int ProofingIntent = INTENT_PERCEPTUAL; > static BOOL WhiteBlackCompensation = FALSE; > > static cmsHPROFILE hInput = NULL; > static cmsHPROFILE hOutput = NULL; > static cmsHPROFILE hProof = NULL; > static cmsHPROFILE hLab = NULL; > static cmsHPROFILE hXYZ = NULL; > static cmsHTRANSFORM hTrans, hTransXYZ, hTransLab; > > static icColorSpaceSignature InputColorSpace, OutputColorSpace; > static cmsCIEXYZ xyz; > static cmsCIELab Lab; > > #define xisatty(x) isatty( fileno( (x) ) ) > > #ifndef stricmp > #define stricmp strcasecmp > #endif > > static void FatalError(const char *frm,...) > { > va_list args; > va_start(args, frm); > vfprintf(stderr, frm, args); > va_end(args); > printf("Usage: icc-translate\n" > " <bool> verbose (0 for false, 1 for true)\n" > " <int> intent: 0=Perceptual, 1=Colorimetric, > 2=Saturation, 3=Absolute\n" > " <bool> black/white compensation\n" > " <path> input profile\n" > " <path> output profile\n" > " <int> proofing intent\n" > " <path> proofing profile, '-' for none\n" > " <double> color values, floating point from 0 to 1\n" > "\n" > "Examples:\n" > " convert black, gray and white from sRGB to CMYK:\n" > " icc-translate 0 3 0 Adobe-sRGB.icc EuroscaleCoated.icc 0 - > 0 0 0 0.5 0.5 0.5 1 1 1\n" > "\n" > " convert cmyk from Euroscale to Lanie printer, proofing > Burda:\n" > " icc-translate 0 3 0 EuroscaleCoated.icc Lanier.icc \\\n" > " 3 burda2001v3.icc 0 0 0 0 0 0 0 1 0 0 1 0\n" > ); > exit(1); > } > > static char* NextArg() > { > if (gArgIdx + 1 >= gArgc) > FatalError("Too few arguments\n"); > return gArgv[++gArgIdx]; > } > > static cmsHPROFILE OpenProfile(const char *File) > { > if (!File) > return cmsCreate_sRGBProfile(); > if (stricmp(File, "*Lab") == 0) > return cmsCreateLabProfile(NULL); > if (stricmp(File, "*LabD65") == 0) { > cmsCIExyY D65xyY; > cmsWhitePointFromTemp(6504, &D65xyY); > return cmsCreateLabProfile(&D65xyY); > } > if (stricmp(File, "*XYZ") == 0) > return cmsCreateXYZProfile(); > cmsHPROFILE h = cmsOpenProfileFromFile(File, "r"); > if (h == NULL) > FatalError("Can't open profile '%s'", File); > return h; > } > > static void OpenTransforms(void) > { > DWORD dwFlags = 0; > dwFlags |= cmsFLAGS_NOTPRECALC; > hInput = OpenProfile(cInProf); > hOutput = OpenProfile(cOutProf); > if (cProofing != NULL && *cProofing && strcmp(cProofing, "-")) { > hProof = cmsOpenProfileFromFile(cProofing, "r"); > dwFlags |= cmsFLAGS_SOFTPROOFING; > } > > InputColorSpace = cmsGetColorSpace(hInput); > OutputColorSpace = cmsGetColorSpace(hOutput); > > if (cmsGetDeviceClass(hInput) == icSigLinkClass || > cmsGetDeviceClass(hOutput) == icSigLinkClass) > FatalError("Use some flag for devicelink profiles!\n"); > > hXYZ = cmsCreateXYZProfile(); > hLab = cmsCreateLabProfile(NULL); > > if (Verbose) { > printf("From: %s\n", cmsTakeProductName(hInput)); > if (hOutput) > printf("To: %s\n", cmsTakeProductName(hOutput)); > if (hProof) > printf("Proof: %s\n", cmsTakeProductName(hProof)); > printf("\n"); > } > DWORD dwIn = BYTES_SH(2) | > CHANNELS_SH(_cmsChannelsOf(InputColorSpace)); > DWORD dwOut = BYTES_SH(2) | > CHANNELS_SH(_cmsChannelsOf(OutputColorSpace)); > > if (WhiteBlackCompensation) > dwFlags |= cmsFLAGS_WHITEBLACKCOMPENSATION; > > if (hProof) { > hTrans = cmsCreateProofingTransform(hInput, dwIn, > hOutput, dwOut, hProof, Intent, ProofingIntent, dwFlags); > } else { > hTrans = cmsCreateTransform(hInput, dwIn, > hOutput, dwOut, Intent, dwFlags); > } > > if (Verbose) { > hTransXYZ = cmsCreateTransform(hInput, dwIn, > hXYZ, TYPE_XYZ_16, > Intent, cmsFLAGS_NOTPRECALC); > hTransLab = cmsCreateTransform(hInput, dwIn, > hLab, TYPE_Lab_16, > Intent, cmsFLAGS_NOTPRECALC); > } > } > > > static void CloseTransforms(void) > { > cmsDeleteTransform(hTrans); > if (hTransLab) > cmsDeleteTransform(hTransLab); > if (hTransXYZ) > cmsDeleteTransform(hTransXYZ); > cmsCloseProfile(hInput); > if (hOutput) > cmsCloseProfile(hOutput); > cmsCloseProfile(hXYZ); > cmsCloseProfile(hLab); > } > > > static void PrintOne(const char *C, double v) > { > v /= 257.; > v /= 255; > v *= outputScale; > printf("%s=%.2f ", C, v); > } > > static void PrintCooked(const char *C, double v) > { > printf("%s=%.4f ", C, v); > } > > > static void PrintResults(WORD Encoded[], icColorSpaceSignature ColorSpace) > { > switch (ColorSpace) { > case icSigXYZData: > cmsXYZEncoded2Float(&xyz, Encoded); > PrintCooked("X", xyz.X * 100.); > PrintCooked("Y", xyz.Y * 100.); > PrintCooked("Z", xyz.Z * 100.); > break; > > case icSigLabData: > cmsLabEncoded2Float(&Lab, Encoded); > PrintCooked("L*", Lab.L); > PrintCooked("a*", Lab.a); > PrintCooked("b*", Lab.b); > break; > > case icSigLuvData: > PrintOne("L", Encoded[0]); > PrintOne("u", Encoded[1]); > PrintOne("v", Encoded[2]); > break; > > case icSigYCbCrData: > PrintOne("Y", Encoded[0]); > PrintOne("Cb", Encoded[1]); > PrintOne("Cr", Encoded[2]); > break; > > > case icSigYxyData: > PrintOne("Y", Encoded[0]); > PrintOne("x", Encoded[1]); > PrintOne("y", Encoded[2]); > break; > > case icSigRgbData: > PrintOne("R", Encoded[0]); > PrintOne("G", Encoded[1]); > PrintOne("B", Encoded[2]); > break; > > case icSigGrayData: > PrintOne("L", Encoded[0]); > break; > > case icSigHsvData: > PrintOne("H", Encoded[0]); > PrintOne("s", Encoded[1]); > PrintOne("v", Encoded[2]); > break; > > case icSigHlsData: > PrintOne("H", Encoded[0]); > PrintOne("l", Encoded[1]); > PrintOne("s", Encoded[2]); > break; > > case icSigCmykData: > PrintOne("C", Encoded[0]); > PrintOne("M", Encoded[1]); > PrintOne("Y", Encoded[2]); > PrintOne("K", Encoded[3]); > break; > > case icSigCmyData: > PrintOne("C", Encoded[0]); > PrintOne("M", Encoded[1]); > PrintOne("Y", Encoded[2]); > break; > > case icSig6colorData: > PrintOne("C", Encoded[0]); > PrintOne("M", Encoded[1]); > PrintOne("Y", Encoded[2]); > PrintOne("K", Encoded[3]); > PrintOne("c", Encoded[1]); > PrintOne("m", Encoded[2]); > break; > > default: > for (int i = 0; i < _cmsChannelsOf(OutputColorSpace); i++) { > char Buffer[10]; > sprintf(Buffer, "CHAN%d", i + 1); > PrintOne(Buffer, Encoded[i]); > } > } > } > > static int GetVal(const char *AskFor) > { > double v1 = atof(NextArg()); > double v2 = v1 * 255.0 * 257.0; > int v = (int) v2; > if (Verbose) { > PrintOne("GetVal", v); > printf(" GetVal(%s) returns %.2f = %.2f = %d\n", AskFor, v1, > v2, v); > } > return v2; > } > > > static double GetDbl(const char *AskFor) > { > return atof(NextArg()); > } > > > static void TakeValues(WORD Encoded[]) > { > switch (InputColorSpace) { > > case icSigXYZData: > xyz.X = GetDbl("X"); > xyz.Y = GetDbl("Y"); > xyz.Z = GetDbl("Z"); > cmsFloat2XYZEncoded(Encoded, &xyz); > break; > > case icSigLabData: > Lab.L = GetDbl("L*"); > Lab.a = GetDbl("a*"); > Lab.b = GetDbl("b*"); > cmsFloat2LabEncoded(Encoded, &Lab); > break; > > case icSigLuvData: > Encoded[0] = GetVal("L"); > Encoded[1] = GetVal("u"); > Encoded[2] = GetVal("v"); > break; > > case icSigYCbCrData: > Encoded[0] = GetVal("Y"); > Encoded[1] = GetVal("Cb"); > Encoded[2] = GetVal("Cr"); > break; > > > case icSigYxyData: > Encoded[0] = GetVal("Y"); > Encoded[1] = GetVal("x"); > Encoded[2] = GetVal("y"); > break; > > case icSigRgbData: > Encoded[0] = GetVal("R"); > Encoded[1] = GetVal("G"); > Encoded[2] = GetVal("B"); > break; > > case icSigGrayData: > Encoded[0] = GetVal("L"); > break; > > case icSigHsvData: > Encoded[0] = GetVal("H"); > Encoded[1] = GetVal("s"); > Encoded[2] = GetVal("v"); > break; > > case icSigHlsData: > Encoded[0] = GetVal("H"); > Encoded[1] = GetVal("l"); > Encoded[2] = GetVal("s"); > break; > > case icSigCmykData: > Encoded[0] = GetVal("C"); > Encoded[1] = GetVal("M"); > Encoded[2] = GetVal("Y"); > Encoded[3] = GetVal("K"); > break; > > case icSigCmyData: > Encoded[0] = GetVal("C"); > Encoded[1] = GetVal("M"); > Encoded[2] = GetVal("Y"); > break; > > case icSig6colorData: > FatalError("Hexachrome separations unsupported on input"); > break; > > default: > FatalError("Unsupported %d channel profile", > _cmsChannelsOf(InputColorSpace)); > } > } > > > int main(int argc, char *argv[]) > { > WORD Input[MAXCHANNELS], Output[MAXCHANNELS], > PCSLab[MAXCHANNELS], > PCSxyz[MAXCHANNELS]; > gArgc = argc; > gArgv = argv; > gArgIdx = 0; > > Verbose = atoi(NextArg()); > Intent = atoi(NextArg()); > if (Intent > 3 || Intent < 0) > FatalError("Invalid intent"); > WhiteBlackCompensation = atoi(NextArg()) != 0; > cInProf = NextArg(); > cOutProf = NextArg(); > ProofingIntent = atoi(NextArg()); > if (ProofingIntent > 3 || ProofingIntent < 0) > FatalError("Invalid ProofingIntent"); > cProofing = NextArg(); > > OpenTransforms(); > > while (gArgIdx + 1 < gArgc) { > TakeValues(Input); > cmsDoTransform(hTrans, Input, Output, 1); > > if (hTransXYZ) > cmsDoTransform(hTransXYZ, Input, PCSxyz, 1); > if (hTransLab) > cmsDoTransform(hTransLab, Input, PCSLab, 1); > > outputScale = 100; > printf("## "); > PrintResults(Output, OutputColorSpace); > printf(" ##\n"); > if (Verbose) { > outputScale = 255; > printf("scale255: "); > PrintResults(Output, OutputColorSpace); > printf("\n"); > } > if (Verbose && hTransXYZ && hTransLab) { > PrintResults(PCSxyz, icSigXYZData); > printf("\n"); > PrintResults(PCSLab, icSigLabData); > printf("\n"); > } > } > return 0; > } > > > ---- > - Peter Speck > > > ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ Lcms-user mailing list Lcms-user@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/lcms-user