/* * International Color Consortium Format Library (icclib) * Library Read/Write test and example code. * * Author: Graeme W. Gill * Date: 1999/11/29 * Version: 2.15 * * Copyright 1997 - 2012 Graeme W. Gill * * This material is licensed with an "MIT" free use license:- * see the License4.txt file in this directory for licensing details. */ /* TTBD: * * Fix enums to be selected randomly (ie. header) * * Should add test of ->delete_tag() * Should add test of ->rename_tag() * * Add many extra comments and explanations. * */ /* This file is intended to serve two purposes. One is to minimally test the ability of the icc library to read and write all tag types. The other is as a source code example of how to read and write each tag type, since icc.h might otherwise take some effort to understand. Note XYZ scaling to 1.0, not 100.0 */ #define NTRIALS 100 #include #include #include #include #include #ifdef __sun #include #endif #include "icc.h" void error(char *fmt, ...), warning(char *fmt, ...); /* Rounded floating test numbers */ int rand_int(int low, int high); unsigned int rand_o8(void), rand_o16(void), rand_o32(void); double rand_8f(void), rand_L8(void), rand_ab8(void); double rand_16f(void), rand_XYZ16(void), rand_u8f8(void), rand_L16(void), rand_ab16(void); double rand_u16f16(void), rand_s15f16(void); int dcomp(double a, double b); /* random ICC specific values */ unsigned int rand_ScreenEncodings(void); unsigned int rand_DeviceAttributes(void); unsigned int rand_ProfileHeaderFlags(void); unsigned int rand_AsciiOrBinaryData(void); icColorSpaceSignature rand_ColorSpaceSignature(void); icColorSpaceSignature rand_PCS(void); icTechnologySignature rand_TechnologySignature(void); icProfileClassSignature rand_ProfileClassSignature(void); icPlatformSignature rand_PlatformSignature(void); icMeasurementFlare rand_MeasurementFlare(void); icMeasurementGeometry rand_MeasurementGeometry(void); icRenderingIntent rand_RenderingIntent(void); icSpotShape rand_SpotShape(void); icStandardObserver rand_StandardObserver(void); icIlluminant rand_Illuminant(void); /* declare some test functions */ int md5_test(void); /* I've split the functionality up into two pieces. The main() code does the overall file write/read, while the tag type code is all in the doit() function. The write/read logic is all sandwiched together (distinguished by the state of the mode flag), so that the code for each tag type is kept adjacent. In a real application, one wouldn't do it this way. */ int doit(int mode, icc *wr_icco, icc *rd_icco); int main( int argc, char *argv[] ) { char *file_name = "xxxx.icm"; icmFile *wr_fp, *rd_fp; icc *wr_icco, *rd_icco; /* Keep object separate */ int rv = 0; int i; unsigned int offset = 0; /* File write/read offset, 0 for standard icc */ printf("ICC library regression test, V%s\n",ICCLIB_VERSION_STR); /* Do any internal code tests. */ if (md5_test() != 0) error ("MD5 checksum routine is faulty"); /* Outer loop does a number of file write/reads, */ /* in order to exercise random tests, and to test file offsets. */ for (i = 0; i < NTRIALS; i++) { unsigned int size; /* Expected write size */ printf("."); fflush(stdout); /* -------------------------- */ /* Deal with writing the file */ /* Open up the file for writing */ if ((wr_fp = new_icmFileStd_name(file_name,"w")) == NULL) error ("Write: Can't open file '%s'",file_name); if ((wr_icco = new_icc()) == NULL) error ("Write: Creation of ICC object failed"); /* Add all the tags with their tag types */ if ((rv = doit(0, wr_icco, NULL)) != 0) error ("Write tags: %d, %s",rv,wr_icco->err); /* Write the file (including all tags) out */ /* The last parameter is the offset to write the */ /* ICC profile into the file. For a standard ICC profile, */ /* this needs to be 0, but it might be non-zero if you are writing */ /* an embedded profile. */ /* Check that get_size() is working too. */ if ((size = wr_icco->get_size(wr_icco)) == 0) error ("Write size: %d, %s",wr_icco->errc,wr_icco->err); if ((rv = wr_icco->write(wr_icco,wr_fp,offset)) != 0) error ("Write file: %d, %s",rv,wr_icco->err); /* To check that get_size() is correct: */ { icmFileStd *pp = (icmFileStd *)wr_fp; /* Cheat - Look inside icmFile */ if (fseek(pp->fp, 0, SEEK_END)) error ("Write: seek to EOF failed"); if ((unsigned int)ftell(pp->fp) != offset + size) error ("Write: get_size function didn't return correct value - got %d, expected %d", ftell(pp->fp),offset+size); } /* Would normally call wr_icco->del(wr_icco); but leave it, so that we can verify the read. */ wr_fp->del(wr_fp); /* -------------------------- */ /* Deal with reading and verifying the file */ /* Open up the file for reading */ if ((rd_fp = new_icmFileStd_name(file_name,"r")) == NULL) error ("Read: Can't open file '%s'",file_name); if ((rd_icco = new_icc()) == NULL) error ("Read: Creation of ICC object failed"); /* Read the header and tag list */ /* The last parameter is the offset to read the */ /* ICC profile from the file. For a standard ICC proifile, */ /* this needs to be 0, but it might be non-zero if you are writing */ /* an embedded profile this needs to be 0, but it might be non-zero */ /* if you are writing an embedded profile. */ if ((rv = rd_icco->read(rd_icco,rd_fp,offset)) != 0) error ("Read: %d, %s",rv,rd_icco->err); /* Read and verify all the tags and their tag types */ if ((rv = doit(1, wr_icco, rd_icco)) != 0) error ("Read: %d, %s",rv,rd_icco->err); /* -------- */ /* Clean up */ wr_icco->del(wr_icco); rd_icco->del(rd_icco); rd_fp->del(rd_fp); /* choose another file offset to test */ offset = rand_int(0,72789); } return 0; } /* -------------------------------------------------------------- */ /* Internal routine checks. */ /* Test the MD5 function. Return nz if fail. */ int md5_test() { int rv = 0; int i, j; icc *icco; icmMD5 *m; unsigned char chs1[16]; unsigned char chs2[16]; /* Standard RFC 1321 test cases */ struct { char *s; ORD32 sum[4]; } tc[] = { { "", { 0xd41d8cd9, 0x8f00b204, 0xe9800998, 0xecf8427e } }, { "a", { 0x0cc175b9, 0xc0f1b6a8, 0x31c399e2, 0x69772661 } }, { "abc", { 0x90015098, 0x3cd24fb0, 0xd6963f7d, 0x28e17f72 } }, { "message digest", { 0xf96b697d, 0x7cb7938d, 0x525a2f31, 0xaaf161d0 } }, { "abcdefghijklmnopqrstuvwxyz", { 0xc3fcd3d7, 0x6192e400, 0x7dfb496c, 0xca67e13b } }, { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", { 0xd174ab98, 0xd277d9f5, 0xa5611c2c, 0x9f419d9f } }, { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", { 0x57edf4a2, 0x2be3c955, 0xac49da2e, 0x2107b67a } }, { NULL, { 0,0,0,0 } } }; if ((icco = new_icc()) == NULL) error ("Creation of ICC object failed"); m = new_icmMD5_a(icco->al); for (i = 0; ; i++) { if (tc[i].s == NULL) break; m->reset(m); m->add(m, (unsigned char *)tc[i].s, strlen(tc[i].s)); m->get(m, chs2); /* Convert reference to a byte stream */ chs1[0] = (tc[i].sum[0] >> 24) & 0xff, chs1[1] = (tc[i].sum[0] >> 16) & 0xff, chs1[2] = (tc[i].sum[0] >> 8) & 0xff, chs1[3] = tc[i].sum[0] & 0xff, chs1[4] = (tc[i].sum[1] >> 24) & 0xff, chs1[5] = (tc[i].sum[1] >> 16) & 0xff, chs1[6] = (tc[i].sum[1] >> 8) & 0xff, chs1[7] = tc[i].sum[1] & 0xff, chs1[8] = (tc[i].sum[2] >> 24) & 0xff, chs1[9] = (tc[i].sum[2] >> 16) & 0xff, chs1[10] = (tc[i].sum[2] >> 8) & 0xff, chs1[11] = tc[i].sum[2] & 0xff, chs1[12] = (tc[i].sum[3] >> 24) & 0xff, chs1[13] = (tc[i].sum[3] >> 16) & 0xff, chs1[14] = (tc[i].sum[3] >> 8) & 0xff, chs1[15] = tc[i].sum[3] & 0xff; for (j = 0; j < 16; j++) { if (chs1[j] != chs2[j]) { printf("MD5 check on '%s' fails at %d with:\n",tc[i].s,j); printf("Sum is %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", chs2[0], chs2[1], chs2[2], chs2[3], chs2[4], chs2[5], chs2[6], chs2[7], chs2[8], chs2[9], chs2[10], chs2[11], chs2[12], chs2[13], chs2[14], chs2[15]); printf("Should be %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", chs1[0], chs1[1], chs1[2], chs1[3], chs1[4], chs1[5], chs1[6], chs1[7], chs1[8], chs1[9], chs1[10], chs1[11], chs1[12], chs1[13], chs1[14], chs1[15]); rv = 1; break; } } } m->del(m); icco->del(icco); return rv; } /* -------------------------------------------------------------- */ /* This is the code that inits and checks the header and tag data. */ /* Note that to undestand this, you need a copy of the ICC profile */ /* spec., and a copy of the icc header file (icc34.h in this code) */ /* All items that begin "icXXX" are from the ICC generic icc34.h file, */ /* while the items that begin "icmXXX" are machine versions of structures */ /* that are specific to this library. */ int doit( int mode, /* 0 - write, 1 = read/verify */ icc *wr_icco, /* The write icc object */ icc *rd_icco /* The read icc object */ ) { int rv = 0; /* ----------- */ /* The header: */ if (mode == 0) { icmHeader *wh = wr_icco->header; /* Values that must be set before writing */ wh->deviceClass = icSigAbstractClass; wh->colorSpace = rand_ColorSpaceSignature(); wh->pcs = rand_PCS(); wh->renderingIntent = rand_RenderingIntent(); /* Values that should be set before writing */ wh->manufacturer = str2tag("tst1"); wh->model = str2tag("1234"); wh->attributes.l = rand_DeviceAttributes(); wh->flags = rand_ProfileHeaderFlags(); /* Values that may optionally be set before writing */ wh->attributes.h = 0x12345678; wh->creator = str2tag("tst2"); /* Values that are not normally set. Set them to non-defaults for testing */ wh->cmmId = str2tag("tst3"); wh->majv = 2; /* Default version 2.1.0 */ wh->minv = 1; wh->bfv = 0; wh->date.year = rand_int(1900,3000); /* Defaults to current date */ wh->date.month = rand_int(1,12); wh->date.day = rand_int(1,31); wh->date.hours = rand_int(0,23); wh->date.minutes = rand_int(0,59); wh->date.seconds = rand_int(0,59); wh->platform = rand_PlatformSignature(); wh->illuminant.X = rand_XYZ16(); /* Defaults to D50 */ wh->illuminant.Y = rand_XYZ16(); wh->illuminant.Z = rand_XYZ16(); } else { icmHeader *rh = rd_icco->header; icmHeader *wh = wr_icco->header; /* Check all the values */ rv |= (rh->deviceClass != wh->deviceClass); rv |= (rh->colorSpace != wh->colorSpace); rv |= (rh->pcs != wh->pcs); rv |= (rh->renderingIntent != wh->renderingIntent); rv |= (rh->manufacturer != wh->manufacturer); rv |= (rh->model != wh->model); rv |= (rh->attributes.l != wh->attributes.l); rv |= (rh->attributes.h != wh->attributes.h); rv |= (rh->flags != wh->flags); rv |= (rh->creator != wh->creator); rv |= (rh->cmmId != wh->cmmId); rv |= (rh->majv != wh->majv); rv |= (rh->minv != wh->minv); rv |= (rh->bfv != wh->bfv); rv |= (rh->date.year != wh->date.year); rv |= (rh->date.month != wh->date.month); rv |= (rh->date.day != wh->date.day); rv |= (rh->date.hours != wh->date.hours); rv |= (rh->date.minutes != wh->date.minutes); rv |= (rh->date.seconds != wh->date.seconds); rv |= (rh->platform != wh->platform); rv |= dcomp(rh->illuminant.X, wh->illuminant.X); rv |= dcomp(rh->illuminant.Y, wh->illuminant.Y); rv |= dcomp(rh->illuminant.Z, wh->illuminant.Z); if (rv) error ("Header verify failed"); } /* ------------- */ /* CrdInfo info: */ { char *str1 = "Product Name"; char *str2[4] = { "Intent zero CRD Name", "Intent one CRD Name", "Intent two CRD Name", "Intent three CRD Name" }; static icmCrdInfo *wo; if (mode == 0) { unsigned int i; if ((wo = (icmCrdInfo *)wr_icco->add_tag( wr_icco, icSigCrdInfoTag, icSigCrdInfoType)) == NULL) return 1; wo->ppsize = strlen(str1)+1; /* Allocated and used size of text, inc null */ for (i = 0; i < 4; i++) wo->crdsize[i] = strlen(str2[i])+1; /* Allocated and used size of text, inc null */ wo->allocate((icmBase *)wo); /* Allocate space */ /* Note we could allocate and copy as we go, rather than doing them all at once. */ strcpy(wo->ppname, str1); /* Copy the text in */ for (i = 0; i < 4; i++) strcpy(wo->crdname[i], str2[i]); /* Copy the text in */ } else { icmCrdInfo *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmCrdInfo *)rd_icco->read_tag(rd_icco, icSigCrdInfoTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigCrdInfoType) return 1; /* Now check it out */ if (ro->ppsize != wo->ppsize) for (i = 0; i < 4; i++) { if (ro->crdsize[i] != wo->crdsize[i]) error ("CrdInfo crdsize[%d] doesn't match",i); } rv |= strcmp(ro->ppname, wo->ppname); for (i = 0; i < 4; i++) { rv |= strcmp(ro->crdname[i], wo->crdname[i]); } if (rv) error ("CrdInfo verify failed"); } } /* ---------------------- */ /* Curve - Linear version */ { static icmCurve *wo; if (mode == 0) { if ((wo = (icmCurve *)wr_icco->add_tag( wr_icco, icSigRedTRCTag, icSigCurveType)) == NULL) return 1; wo->flag = icmCurveLin; /* Linear version */ wo->allocate((icmBase *)wo);/* Allocate space */ } else { icmCurve *ro; /* Try and read the tag from the file */ ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigRedTRCTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigCurveType) return 1; /* Now check it out */ if (ro->flag != wo->flag) error ("Curve flag doesn't match for Linear"); if (ro->size != wo->size) error ("Curve size doesn't match"); if (rv) error ("Curve verify failed"); } } /* --------------------- */ /* Curve - Gamma version */ { static icmCurve *wo; if (mode == 0) { if ((wo = (icmCurve *)wr_icco->add_tag( wr_icco, icSigGreenTRCTag, icSigCurveType)) == NULL) return 1; wo->flag = icmCurveGamma; /* Gamma version */ wo->allocate((icmBase *)wo); /* Allocate space */ wo->data[0] = rand_u8f8(); /* Gamma value */ } else { icmCurve *ro; /* Try and read the tag from the file */ ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigGreenTRCTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigCurveType) return 1; /* Now check it out */ if (ro->flag != wo->flag) error ("Curve flag doesn't match for Gamma"); if (ro->size != wo->size) error ("Curve size doesn't match"); rv |= dcomp(ro->data[0], wo->data[0]); if (rv) error ("Curve verify failed"); } } /* ------------------------- */ /* Curve - Specified version */ { static icmCurve *wo; if (mode == 0) { unsigned int i; if ((wo = (icmCurve *)wr_icco->add_tag( wr_icco, icSigBlueTRCTag, icSigCurveType)) == NULL) return 1; wo->flag = icmCurveSpec; /* Specified version */ wo->size = rand_int(2,23); /* Number of entries (min must be 2!) */ wo->allocate((icmBase *)wo);/* Allocate space */ for (i = 0; i < wo->size; i++) wo->data[i] = rand_16f(); /* Curve values 0.0 - 1.0 */ } else { icmCurve *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmCurve *)rd_icco->read_tag(rd_icco, icSigBlueTRCTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigCurveType) return 1; /* Now check it out */ if (ro->flag != wo->flag) error ("Curve flag doesn't match for specified"); if (ro->size != wo->size) error ("Curve size doesn't match"); for (i = 0; i < wo->size; i++) rv |= dcomp(ro->data[i], wo->data[i]); if (rv) error ("Curve verify failed"); } } /* ------------------- */ /* Data - text version */ { static icmData *wo; char *ts1 = "This is a data string"; if (mode == 0) { if ((wo = (icmData *)wr_icco->add_tag( wr_icco, icSigPs2CRD0Tag, icSigDataType)) == NULL) return 1; wo->flag = icmDataASCII; /* Holding ASCII data */ wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */ wo->allocate((icmBase *)wo);/* Allocate space */ strcpy((char *)wo->data, ts1); /* Copy the text in */ } else { icmData *ro; /* Try and read the tag from the file */ ro = (icmData *)rd_icco->read_tag(rd_icco, icSigPs2CRD0Tag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigDataType) return 1; /* Now check it out */ if (ro->flag != wo->flag) error ("Data size doesn't match"); if (ro->size != wo->size) error ("Data size doesn't match"); rv |= strcmp((char *)ro->data, (char *)wo->data); if (rv) error ("Data verify failed"); } } /* --------------------- */ /* Data - Binary version */ { static icmData *wo; if (mode == 0) { unsigned int i; if ((wo = (icmData *)wr_icco->add_tag( wr_icco, icSigPs2CRD1Tag, icSigDataType)) == NULL) return 1; wo->flag = icmDataBin; /* Holding binary data */ wo->size = rand_int(0,43); /* Space we need for data */ wo->allocate((icmBase *)wo);/* Allocate space */ for (i = 0; i < wo->size; i ++) wo->data[i] = rand_o8(); } else { icmData *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmData *)rd_icco->read_tag(rd_icco, icSigPs2CRD1Tag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigDataType) return 1; /* Now check it out */ if (ro->flag != wo->flag) error ("Data size doesn't match"); if (ro->size != wo->size) error ("Data size doesn't match"); for (i = 0; i < wo->size; i++) rv |= (ro->data[i] != wo->data[i]); if (rv) error ("Data verify failed"); } } /* --------- */ /* DateTime: */ { static icmDateTimeNumber *wo; if (mode == 0) { if ((wo = (icmDateTimeNumber *)wr_icco->add_tag( wr_icco, icSigCalibrationDateTimeTag, icSigDateTimeType)) == NULL) return 1; wo->year = rand_int(1900, 3000); wo->month = rand_int(1, 12); wo->day = rand_int(1, 31); wo->hours = rand_int(0, 23); wo->minutes = rand_int(0, 59); wo->seconds = rand_int(0, 59); } else { icmDateTimeNumber *ro; /* Try and read the tag from the file */ ro = (icmDateTimeNumber *)rd_icco->read_tag(rd_icco, icSigCalibrationDateTimeTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigDateTimeType) return 1; /* Now check it out */ rv |= (ro->year != wo->year); rv |= (ro->month != wo->month); rv |= (ro->day != wo->day); rv |= (ro->hours != wo->hours); rv |= (ro->minutes != wo->minutes); rv |= (ro->seconds != wo->seconds); if (rv) error ("DateTime verify failed"); } } /* ----------- */ /* 16 bit lut: */ { static icmLut *wo; if (mode == 0) { unsigned int i, j, k; if ((wo = (icmLut *)wr_icco->add_tag( wr_icco, icSigAToB0Tag, icSigLut16Type)) == NULL) return 1; wo->inputChan = 2; wo->outputChan = 3; wo->clutPoints = 5; wo->inputEnt = 56; wo->outputEnt = 73; wo->allocate((icmBase *)wo);/* Allocate space */ /* The matrix is only applicable to XYZ input space */ for (i = 0; i < 3; i++) /* Matrix */ for (j = 0; j < 3; j++) wo->e[i][j] = rand_s15f16(); /* See icc.getNormFuncs() for normalizing functions */ /* The input table index range is over the normalized range 0.0 - 1.0. */ /* The range in input color space can be determined by denormalizing */ /* the values 0.0 - 1.0. */ for (i = 0; i < wo->inputChan; i++) /* Input tables */ for (j = 0; j < wo->inputEnt; j++) wo->inputTable[i * wo->inputEnt + j] = rand_16f(); /* Lut */ /* The multidimentional lut has a normalized index range */ /* of 0.0 - 1.0 in each dimension. Its entry values are also */ /* normalized values in the range 0.0 - 1.0. */ for (i = 0; i < wo->clutPoints; i++) /* Input chan 0 - slow changing */ for (j = 0; j < wo->clutPoints; j++) /* Input chan 1 - faster changing */ for (k = 0; k < wo->outputChan; k++) /* Output chans */ wo->clutTable[(i * wo->clutPoints + j) * wo->outputChan + k] = rand_16f(); /* The output color space values should be normalized to the */ /* range 0.0 - 1.0 for use as output table entry values. */ for (i = 0; i < wo->outputChan; i++) /* Output tables */ for (j = 0; j < wo->outputEnt; j++) wo->outputTable[i * wo->outputEnt + j] = rand_16f(); } else { icmLut *ro; unsigned int size; unsigned int i, j; /* Try and read the tag from the file */ ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB0Tag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigLut16Type) return 1; /* Now check it out */ rv |= (ro->inputChan != wo->inputChan); rv |= (ro->outputChan != wo->outputChan); rv |= (ro->clutPoints != wo->clutPoints); rv |= (ro->inputEnt != wo->inputEnt); rv |= (ro->outputEnt != wo->outputEnt); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) rv |= dcomp(ro->e[i][j], wo->e[i][j]); size = (wo->inputChan * wo->inputEnt); for (i = 0; i < size; i++) rv |= dcomp(ro->inputTable[i], wo->inputTable[i]); size = wo->outputChan; for (i = 0; i < wo->inputChan; i++) size *= wo->clutPoints; for (i = 0; i < size; i++) rv |= dcomp(ro->clutTable[i], wo->clutTable[i]); size = (wo->outputChan * wo->outputEnt); for (i = 0; i < size; i++) rv |= dcomp(ro->outputTable[i], wo->outputTable[i]); if (rv) error ("Lut16 verify failed"); } } /* ------------------ */ /* 16 bit lut - link: */ { static icmLut *wo; if (mode == 0) { /* Just link to the existing LUT. This is often used when there */ /* is no distinction between intents, and saves file and memory space. */ if ((wo = (icmLut *)wr_icco->link_tag( wr_icco, icSigAToB1Tag, icSigAToB0Tag)) == NULL) return 1; } else { icmLut *ro; unsigned int size; unsigned int i; /* Try and read the tag from the file */ ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB1Tag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigLut16Type) return 1; /* Now check it out */ rv |= (ro->inputChan != wo->inputChan); rv |= (ro->outputChan != wo->outputChan); rv |= (ro->clutPoints != wo->clutPoints); rv |= (ro->inputEnt != wo->inputEnt); rv |= (ro->outputEnt != wo->outputEnt); size = (wo->inputChan * wo->inputEnt); for (i = 0; i < size; i++) rv |= (ro->inputTable[i] != wo->inputTable[i]); size = wo->outputChan; for (i = 0; i < wo->inputChan; i++) size *= wo->clutPoints; for (i = 0; i < size; i++) rv |= (ro->clutTable[i] != wo->clutTable[i]); size = (wo->outputChan * wo->outputEnt); for (i = 0; i < size; i++) rv |= (ro->outputTable[i] != wo->outputTable[i]); if (rv) error ("Lut16 link verify failed"); } } /* ---------- */ /* 8 bit lut: */ { static icmLut *wo; if (mode == 0) { unsigned int i, j, m, k; if ((wo = (icmLut *)wr_icco->add_tag( wr_icco, icSigAToB2Tag, icSigLut8Type)) == NULL) return 1; wo->inputChan = 3; wo->outputChan = 2; wo->clutPoints = 4; wo->inputEnt = 256; /* Must be 256 for Lut8 */ wo->outputEnt = 256; wo->allocate((icmBase *)wo);/* Allocate space */ for (i = 0; i < 3; i++) /* Matrix */ for (j = 0; j < 3; j++) wo->e[i][j] = rand_s15f16(); for (i = 0; i < wo->inputChan; i++) /* Input tables */ for (j = 0; j < wo->inputEnt; j++) wo->inputTable[i * wo->inputEnt + j] = rand_8f(); /* Lut */ for (i = 0; i < wo->clutPoints; i++) /* Input chan 0 */ for (j = 0; j < wo->clutPoints; j++) /* Input chan 1 */ for (m = 0; m < wo->clutPoints; m++) /* Input chan 2 */ for (k = 0; k < wo->outputChan; k++) { /* Output chans */ int idx = ((i * wo->clutPoints + j) * wo->clutPoints + m) * wo->outputChan + k; wo->clutTable[idx] = rand_8f(); } for (i = 0; i < wo->outputChan; i++) /* Output tables */ for (j = 0; j < wo->outputEnt; j++) wo->outputTable[i * wo->outputEnt + j] = rand_8f(); } else { icmLut *ro; unsigned int size; unsigned int i, j; /* Try and read the tag from the file */ ro = (icmLut *)rd_icco->read_tag(rd_icco, icSigAToB2Tag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigLut8Type) return 1; /* Now check it out */ rv |= (ro->inputChan != wo->inputChan); rv |= (ro->outputChan != wo->outputChan); rv |= (ro->clutPoints != wo->clutPoints); rv |= (ro->inputEnt != wo->inputEnt); rv |= (ro->outputEnt != wo->outputEnt); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) rv |= dcomp(ro->e[i][j], wo->e[i][j]); size = (wo->inputChan * wo->inputEnt); for (i = 0; i < size; i++) rv |= dcomp(ro->inputTable[i], wo->inputTable[i]); size = wo->outputChan; for (i = 0; i < wo->inputChan; i++) size *= wo->clutPoints; for (i = 0; i < size; i++) rv |= dcomp(ro->clutTable[i], wo->clutTable[i]); size = (wo->outputChan * wo->outputEnt); for (i = 0; i < size; i++) rv |= dcomp(ro->outputTable[i], wo->outputTable[i]); if (rv) error ("Lut8 verify failed"); } } /* ----------------- */ /* Measurement: */ { static icmMeasurement *wo; if (mode == 0) { if ((wo = (icmMeasurement *)wr_icco->add_tag( wr_icco, icSigMeasurementTag, icSigMeasurementType)) == NULL) return 1; /* Standard observer */ switch(rand_int(0,2)) { case 0: wo->observer = icStdObsUnknown; break; case 1: wo->observer = icStdObs1931TwoDegrees; break; case 2: wo->observer = icStdObs1964TenDegrees; break; } /* XYZ for backing color */ wo->backing.X = rand_XYZ16(); wo->backing.Y = rand_XYZ16(); wo->backing.Z = rand_XYZ16(); /* Measurement geometry */ switch(rand_int(0,2)) { case 0: wo->geometry = icGeometryUnknown; break; case 1: wo->geometry = icGeometry045or450; break; case 2: wo->geometry = icGeometry0dord0; break; } /* Measurement flare */ wo->flare = rand_u16f16(); /* Illuminant */ switch(rand_int(0,8)) { case 0: wo->illuminant = icIlluminantUnknown; break; case 1: wo->illuminant = icIlluminantD50; break; case 2: wo->illuminant = icIlluminantD65; break; case 3: wo->illuminant = icIlluminantD93; break; case 4: wo->illuminant = icIlluminantF2; break; case 5: wo->illuminant = icIlluminantD55; break; case 6: wo->illuminant = icIlluminantA; break; case 7: wo->illuminant = icIlluminantEquiPowerE; break; case 8: wo->illuminant = icIlluminantF8; break; } } else { icmMeasurement *ro; /* Try and read the tag from the file */ ro = (icmMeasurement *)rd_icco->read_tag(rd_icco, icSigMeasurementTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigMeasurementType) return 1; /* Now check it out */ rv |= (ro->observer != wo->observer); rv |= dcomp(ro->backing.X, wo->backing.X); rv |= dcomp(ro->backing.Y, wo->backing.Y); rv |= dcomp(ro->backing.Z, wo->backing.Z); rv |= (ro->geometry != wo->geometry); rv |= dcomp(ro->flare, wo->flare); rv |= (ro->illuminant != wo->illuminant); if (rv) error ("Measurement verify failed"); } } /* ----------------- */ /* Old style NamedColor: */ { static icmNamedColor *wo; if (mode == 0) { unsigned int i; if ((wo = (icmNamedColor *)wr_icco->add_tag( wr_icco, icSigNamedColorTag, icSigNamedColorType)) == NULL) return 1; wo->vendorFlag = rand_int(0,65535) << 16; /* Bottom 16 bits for IC use */ wo->count = 3; /* Count of named colors */ strcpy(wo->prefix,"Prefix"); /* Prefix for each color name, max 32, null terminated */ strcpy(wo->suffix,"Suffix"); /* Suffix for each color name, max 32, null terminated */ wo->allocate((icmBase *)wo); /* Allocate named color structures */ for (i = 0; i < wo->count; i++) { unsigned int j; sprintf(wo->data[i].root,"Color %d",i); /* Root name, max 32, null terminated */ for (j = 0; j < wo->nDeviceCoords; j++) /* nDeviceCoords defaults appropriately */ wo->data[i].deviceCoords[j] = rand_8f(); /* Device coords of color */ } } else { icmNamedColor *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmNamedColor *)rd_icco->read_tag(rd_icco, icSigNamedColorTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigNamedColorType) return 1; /* Now check it out */ rv |= (ro->vendorFlag != wo->vendorFlag); rv |= (ro->count != wo->count); rv |= (ro->nDeviceCoords != wo->nDeviceCoords); rv |= strcmp(ro->prefix, wo->prefix); rv |= strcmp(ro->suffix, wo->suffix); if (rv) error ("NamedColor verify failed"); for (i = 0; i < wo->count; i++) { unsigned int j; rv |= strcmp(ro->data[i].root, wo->data[i].root); for (j = 0; j < wo->nDeviceCoords; j++) rv |= dcomp(ro->data[i].deviceCoords[j], wo->data[i].deviceCoords[j]); } if (rv) error ("NamedColor verify failed"); } } /* ----------------- */ /* NamedColor2: */ { static icmNamedColor *wo; /* Shares same machine specific structure */ if (mode == 0) { unsigned int i; if ((wo = (icmNamedColor *)wr_icco->add_tag( wr_icco, icSigNamedColor2Tag, icSigNamedColor2Type)) == NULL) return 1; wo->vendorFlag = rand_int(0,65535) << 16; /* Bottom 16 bits for ICC use */ wo->count = 4; /* Count of named colors */ wo->nDeviceCoords = 3; /* Num of device coordinates */ /* Could set this different to that implied by wr_icco->header->colorSpace */ strcpy(wo->prefix,"Prefix-ix"); /* Prefix for each color name, max 32, null terminated */ strcpy(wo->suffix,"Suffix-ixix"); /* Suffix for each color name, max 32, null terminated */ wo->allocate((icmBase *)wo); /* Allocate named color structures */ for (i = 0; i < wo->count; i++) { unsigned int j; sprintf(wo->data[i].root,"Pigment %d",i); /* Root name, max 32, null terminated */ for (j = 0; j < wo->nDeviceCoords; j++) wo->data[i].deviceCoords[j] = rand_8f(); /* Device coords of color */ switch(wo->icp->header->pcs) { case icSigXYZData: wo->data[i].pcsCoords[0] = rand_XYZ16(); wo->data[i].pcsCoords[1] = rand_XYZ16(); wo->data[i].pcsCoords[2] = rand_XYZ16(); break; case icSigLabData: wo->data[i].pcsCoords[0] = rand_L16(); wo->data[i].pcsCoords[1] = rand_ab16(); wo->data[i].pcsCoords[2] = rand_ab16(); break; default: break; } } } else { icmNamedColor *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmNamedColor *)rd_icco->read_tag(rd_icco, icSigNamedColor2Tag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigNamedColor2Type) return 1; /* Now check it out */ rv |= (ro->vendorFlag != wo->vendorFlag); rv |= (ro->count != wo->count); rv |= (ro->nDeviceCoords != wo->nDeviceCoords); rv |= strcmp(ro->prefix, wo->prefix); rv |= strcmp(ro->suffix, wo->suffix); if (rv) error ("NamedColor2 verify failed"); for (i = 0; i < wo->count; i++) { unsigned int j; rv |= strcmp(ro->data[i].root, wo->data[i].root); for (j = 0; j < wo->nDeviceCoords; j++) rv |= dcomp(ro->data[i].deviceCoords[j], wo->data[i].deviceCoords[j]); for (j = 0; j < 3; j++) { rv |= dcomp(ro->data[i].pcsCoords[j], wo->data[i].pcsCoords[j]); } } if (rv) error ("NamedColor2 verify failed"); } } /* ----------------- */ /* ColorantTable: */ { static icmColorantTable *wo; if (mode == 0) { unsigned int i; if ((wo = (icmColorantTable *)wr_icco->add_tag( wr_icco, icSigColorantTableTag, icSigColorantTableType)) == NULL) return 1; wo->count = 4; /* Count of colorants - should be same as implied by device space */ wo->allocate((icmBase *)wo); /* Allocate ColorantTable structures */ for (i = 0; i < wo->count; i++) { sprintf(wo->data[i].name,"Color %d",i); /* Colorant name, max 32, null terminated */ switch(wo->icp->header->pcs) { case icSigXYZData: wo->data[i].pcsCoords[0] = rand_XYZ16(); wo->data[i].pcsCoords[1] = rand_XYZ16(); wo->data[i].pcsCoords[2] = rand_XYZ16(); break; case icSigLabData: wo->data[i].pcsCoords[0] = rand_L16(); wo->data[i].pcsCoords[1] = rand_ab16(); wo->data[i].pcsCoords[2] = rand_ab16(); break; default: break; } } } else { icmColorantTable *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmColorantTable *)rd_icco->read_tag(rd_icco, icSigColorantTableTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigColorantTableType) return 1; /* Now check it out */ rv |= (ro->count != wo->count); if (rv) error ("ColorantTable verify failed"); for (i = 0; i < wo->count; i++) { int j; rv |= strcmp(ro->data[i].name, wo->data[i].name); for (j = 0; j < 3; j++) { rv |= dcomp(ro->data[i].pcsCoords[j], wo->data[i].pcsCoords[j]); } } if (rv) error ("ColorantTable verify failed"); } } /* ----------------- */ /* ProfileSequenceDescTag: */ { unsigned short ts2a[29] = {'T','h','i','s',' ','i','s',' ','a',' ','d','e','v','i','c','e', ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000}; unsigned short ts2b[28] = {'T','h','i','s',' ','i','s',' ','a',' ','m','o','d','e','l', ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000}; char *ts3a = "This is a device description"; char *ts3b = "This is a model description"; static icmProfileSequenceDesc*wo; if (mode == 0) { unsigned int i; if ((wo = (icmProfileSequenceDesc *)wr_icco->add_tag( wr_icco, icSigProfileSequenceDescTag, icSigProfileSequenceDescType)) == NULL) return 1; wo->count = 3; /* Number of descriptions in sequence */ wo->allocate((icmBase *)wo); /* Allocate space for all the DescStructures */ /* Fill in each description structure in sequence */ for (i = 0; i < wo->count; i++) { char ts1[100]; wo->data[i].deviceMfg = str2tag("mfg7"); wo->data[i].deviceModel = str2tag("2345"); wo->data[i].attributes.l = icTransparency | icMatte; wo->data[i].attributes.h = 0x98765432; wo->data[i].technology = rand_TechnologySignature(); /* device Text description */ sprintf(ts1,"This is device descrption %d",i); wo->data[i].device.size = strlen(ts1)+1; wo->data[i].allocate(&wo->data[i]); /* Allocate space */ strcpy(wo->data[i].device.desc, ts1); /* Copy the string in */ /* We'll fudge up the Unicode string */ wo->data[i].device.ucLangCode = 8765; /* UniCode language code */ wo->data[i].device.ucSize = 29; /* Size in chars inc null */ wo->data[i].allocate(&wo->data[i]); /* Allocate space */ memmove(wo->data[i].device.ucDesc, ts2a, 2 * 29); /* Copy string in */ wo->data[i].device.scCode = 67; /* Fudge scriptCode code */ wo->data[i].device.scSize = strlen(ts3a)+1; /* Used size of scDesc in bytes, inc null */ if (wo->data[i].device.scSize > 67) error("ScriptCode string longer than 67"); strcpy((char *)wo->data[i].device.scDesc, ts3a); /* Copy the string in */ /* model Text description */ sprintf(ts1,"This is model descrption %d",i); wo->data[i].model.size = strlen(ts1)+1; wo->data[i].allocate(&wo->data[i]); /* Allocate space */ strcpy(wo->data[i].model.desc, ts1); /* Copy the string in */ /* We'll fudge up the Unicode string */ wo->data[i].model.ucLangCode = 7856; /* UniCode language code */ wo->data[i].model.ucSize = 28; /* Size in chars inc null */ wo->data[i].allocate(&wo->data[i]); /* Allocate space */ memmove(wo->data[i].model.ucDesc, ts2b, 2 * 28); /* Copy string in */ wo->data[i].model.scCode = 67; /* Fudge scriptCode code */ wo->data[i].model.scSize = strlen(ts3b)+1; /* Used size of scDesc in bytes, inc null */ if (wo->data[i].model.scSize > 67) error("ScriptCode string longer than 67"); strcpy((char *)wo->data[i].model.scDesc, ts3b); /* Copy the string in */ } } else { icmProfileSequenceDesc *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmProfileSequenceDesc *)rd_icco->read_tag(rd_icco, icSigProfileSequenceDescTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigProfileSequenceDescType) return 1; /* Now check it out */ if (ro->count != wo->count) error ("ProfileSequenceDesc count doesn't match"); for (i = 0; i < wo->count; i++) { rv |= (ro->data[i].deviceMfg != wo->data[i].deviceMfg); rv |= (ro->data[i].deviceModel != wo->data[i].deviceModel); rv |= (ro->data[i].attributes.l != wo->data[i].attributes.l); rv |= (ro->data[i].attributes.h != wo->data[i].attributes.h); rv |= (ro->data[i].technology != wo->data[i].technology); /* device Text description */ rv |= (ro->data[i].device.size != wo->data[i].device.size); rv |= strcmp(ro->data[i].device.desc, wo->data[i].device.desc); rv |= (ro->data[i].device.ucLangCode != wo->data[i].device.ucLangCode); rv |= (ro->data[i].device.ucSize != wo->data[i].device.ucSize); rv |= memcmp(ro->data[i].device.ucDesc, wo->data[i].device.ucDesc, wo->data[i].device.ucSize * 2); rv |= (ro->data[i].device.scCode != wo->data[i].device.scCode); rv |= (ro->data[i].device.scSize != wo->data[i].device.scSize); rv |= strcmp((char *)ro->data[i].device.scDesc, (char *)wo->data[i].device.scDesc); /* model Text description */ rv |= (ro->data[i].model.size != wo->data[i].model.size); rv |= strcmp(ro->data[i].model.desc, wo->data[i].model.desc); rv |= (ro->data[i].model.ucLangCode != wo->data[i].model.ucLangCode); rv |= (ro->data[i].model.ucSize != wo->data[i].model.ucSize); rv |= memcmp(ro->data[i].model.ucDesc, wo->data[i].model.ucDesc, wo->data[i].model.ucSize * 2); rv |= (ro->data[i].model.scCode != wo->data[i].model.scCode); rv |= (ro->data[i].model.scSize != wo->data[i].model.scSize); rv |= strcmp((char *)ro->data[i].model.scDesc, (char *)wo->data[i].model.scDesc); } if (rv) error ("ProfileSequenceDesc verify failed"); } } /* ----------------- */ /* S15Fixed16Array: */ { static icmS15Fixed16Array *wo; if (mode == 0) { unsigned int i; /* There is no standard Tag that uses icSigS15Fixed16ArrayType, so use a 'custom' tag */ if ((wo = (icmS15Fixed16Array *)wr_icco->add_tag( wr_icco, str2tag("sf32"), icSigS15Fixed16ArrayType)) == NULL) return 1; wo->size = rand_int(0,17); /* Number in array */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->size; i++) { wo->data[i] = rand_s15f16(); /* Set numbers value */ } } else { icmS15Fixed16Array *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmS15Fixed16Array *)rd_icco->read_tag(rd_icco, str2tag("sf32")); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigS15Fixed16ArrayType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("S15Fixed16Array size doesn't match"); for (i = 0; i < wo->size; i++) { rv |= dcomp(ro->data[i], wo->data[i]); } if (rv) error ("S15Fixed16Array verify failed"); } } /* ----------------- */ /* Screening: */ { static icmScreening *wo; if (mode == 0) { unsigned int i; if ((wo = (icmScreening *)wr_icco->add_tag( wr_icco, icSigScreeningTag, icSigScreeningType)) == NULL) return 1; wo->screeningFlag = rand_ScreenEncodings(); wo->channels = rand_int(1,4); /* Number of channels */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->channels; i++) { wo->data[i].frequency = rand_s15f16(); /* Set screening frequency */ wo->data[i].angle = rand_s15f16(); /* Set screening angle */ wo->data[i].spotShape = rand_SpotShape(); /* Set spot shape */ } } else { icmScreening *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmScreening *)rd_icco->read_tag(rd_icco, icSigScreeningTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigScreeningType) return 1; /* Now check it out */ if (ro->channels != wo->channels) error ("Screening channels doesn't match"); rv |= (ro->screeningFlag != wo->screeningFlag); for (i = 0; i < wo->channels; i++) { rv |= dcomp(ro->data[i].frequency, wo->data[i].frequency); rv |= dcomp(ro->data[i].angle, wo->data[i].angle); rv |= (ro->data[i].spotShape != wo->data[i].spotShape); } if (rv) error ("Screening verify failed"); } } /* ----------------- */ /* Signature: */ { static icmSignature *wo; if (mode == 0) { if ((wo = (icmSignature *)wr_icco->add_tag( wr_icco, icSigTechnologyTag, icSigSignatureType)) == NULL) return 1; wo->sig = rand_TechnologySignature(); } else { icmSignature *ro; /* Try and read the tag from the file */ ro = (icmSignature *)rd_icco->read_tag(rd_icco, icSigTechnologyTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigSignatureType) return 1; /* Now check it out */ rv |= (ro->sig != wo->sig); if (rv) error ("Signature verify failed"); } } /* ----------------- */ /* Text Description: */ { static icmTextDescription *wo; char *ts1 = "This is a test description"; unsigned short ts2[27] = {'T','h','i','s',' ','i','s',' ','a',' ','t','e','s','t', ' ','d','e','s','c','r','i','p','t','i','o','n',0x0000}; char *ts3 = "This is a test3 description"; if (mode == 0) { if ((wo = (icmTextDescription *)wr_icco->add_tag( wr_icco, icSigProfileDescriptionTag, icSigTextDescriptionType)) == NULL) return 1; /* Data in tag type wojects is always allocated and freed by the woject */ wo->size = strlen(ts1)+1; /* Allocated and used size of desc, inc null */ wo->allocate((icmBase *)wo);/* Allocate space */ strcpy(wo->desc, ts1); /* Copy the string in */ /* We'll fudge up the Unicode string */ wo->ucLangCode = 1234; /* UniCode language code */ wo->ucSize = 27; /* Allocated and used size of ucDesc in characters, inc null */ wo->allocate((icmBase *)wo);/* Allocate space */ memmove(wo->ucDesc, ts2, 2 * 27); /* Copy string in */ /* Don't really know anything about scriptCode, but fudge some values */ wo->scCode = 23; /* ScriptCode code */ wo->scSize = strlen(ts3)+1; /* Used size of scDesc in bytes, inc null */ /* No allocations, since this has a fixed max of 67 bytes */ if (wo->scSize > 67) error("ScriptCode string longer than 67"); strcpy((char *)wo->scDesc, ts3); /* Copy the string in */ } else { icmTextDescription *ro; /* Try and read the tag from the file */ ro = (icmTextDescription *)rd_icco->read_tag(rd_icco, icSigProfileDescriptionTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ /* We could have left it icmBase, switched on ro->ttype, & then cast appropriately. */ if (ro->ttype != icSigTextDescriptionType) return 1; /* Now check it out */ rv |= (ro->size != wo->size); rv |= strcmp(ro->desc, wo->desc); rv |= (ro->ucLangCode != wo->ucLangCode); rv |= (ro->ucSize != wo->ucSize); rv |= memcmp(ro->ucDesc, wo->ucDesc, wo->ucSize * 2); rv |= (ro->scCode != wo->scCode); rv |= (ro->scSize != wo->scSize); rv |= strcmp((char *)ro->scDesc, (char *)wo->scDesc); if (rv) error ("Text Description verify failed4"); } } /* ----- */ /* Text: */ { static icmText *wo; char *ts1 = "This is Copyright by me!"; if (mode == 0) { if ((wo = (icmText *)wr_icco->add_tag( wr_icco, icSigCopyrightTag, icSigTextType)) == NULL) return 1; wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */ wo->allocate((icmBase *)wo);/* Allocate space */ strcpy(wo->data, ts1); /* Copy the text in */ } else { icmText *ro; /* Try and read the tag from the file */ ro = (icmText *)rd_icco->read_tag(rd_icco, icSigCopyrightTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigTextType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("Text size doesn't match"); rv |= strcmp(ro->data, wo->data); if (rv) error ("Text verify failed"); } } /* ---------------- */ /* U16Fixed16Array: */ { static icmU16Fixed16Array *wo; if (mode == 0) { unsigned int i; /* There is no standard Tag that uses icSigU16Fixed16ArrayType, so use a 'custom' tag */ if ((wo = (icmU16Fixed16Array *)wr_icco->add_tag( wr_icco, str2tag("uf32"), icSigU16Fixed16ArrayType)) == NULL) return 1; wo->size = rand_int(0,17); /* Number in array */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->size; i++) { wo->data[i] = rand_u16f16(); /* Set numbers value */ } } else { icmU16Fixed16Array *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmU16Fixed16Array *)rd_icco->read_tag(rd_icco, str2tag("uf32")); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigU16Fixed16ArrayType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("U16Fixed16Array size doesn't match"); for (i = 0; i < wo->size; i++) { rv |= dcomp(ro->data[i], wo->data[i]); } if (rv) error ("U16Fixed16Array verify failed"); } } /* ------------------- */ /* UcrBg - full curve: */ { static icmUcrBg *wo; char *ts1 = "UcrBg - full curve info"; if (mode == 0) { unsigned int i; if ((wo = (icmUcrBg *)wr_icco->add_tag( wr_icco, icSigUcrBgTag, icSigUcrBgType)) == NULL) return 1; wo->UCRcount = rand_int(2,55); /* Number in UCR curve */ wo->BGcount = rand_int(2,32); /* Number in BG array */ wo->allocate((icmBase *)wo); /* Allocate space for both curves */ for (i = 0; i < wo->UCRcount; i++) wo->UCRcurve[i] = rand_16f(); /* Set numbers value */ for (i = 0; i < wo->BGcount; i++) wo->BGcurve[i] = rand_16f(); /* Set numbers value */ wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */ wo->allocate((icmBase *)wo); /* Allocate space */ strcpy(wo->string, ts1); /* Copy the text in */ } else { icmUcrBg *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmUcrBg *)rd_icco->read_tag(rd_icco, icSigUcrBgTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigUcrBgType) return 1; /* Now check it out */ if (ro->UCRcount != wo->UCRcount) error ("UcrBg UCRcount doesn't match"); if (ro->BGcount != wo->BGcount) error ("UcrBg BGcount doesn't match"); for (i = 0; i < wo->UCRcount; i++) rv |= dcomp(ro->UCRcurve[i], wo->UCRcurve[i]); for (i = 0; i < wo->BGcount; i++) rv |= dcomp(ro->BGcurve[i], wo->BGcurve[i]); if (ro->size != wo->size) error ("Text size doesn't match"); rv |= strcmp(ro->string, wo->string); if (rv) error ("UcrBg verify failed"); } } /* ------------------- */ /* UcrBg - percentage: */ { static icmUcrBg *wo; char *ts1 = "UcrBg - percentage info"; if (mode == 0) { if ((wo = (icmUcrBg *)wr_icco->add_tag( wr_icco, str2tag("bfd%"), icSigUcrBgType)) == NULL) return 1; wo->UCRcount = 1; /* 1 == UCR percentage */ wo->BGcount = 1; /* 1 == BG percentage */ wo->allocate((icmBase *)wo);/* Allocate space */ wo->UCRcurve[0] = (double) rand_int(0,65535); wo->BGcurve[0] = (double) rand_int(0,65535); wo->size = strlen(ts1)+1; /* Allocated and used size of text, inc null */ wo->allocate((icmBase *)wo);/* Allocate space */ strcpy(wo->string, ts1); /* Copy the text in */ } else { icmUcrBg *ro; /* Try and read the tag from the file */ ro = (icmUcrBg *)rd_icco->read_tag(rd_icco, str2tag("bfd%")); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigUcrBgType) return 1; /* Now check it out */ if (ro->UCRcount != wo->UCRcount) error ("UcrBg UCRcount doesn't match"); if (ro->BGcount != wo->BGcount) error ("UcrBg BGcount doesn't match"); rv |= (ro->UCRcurve[0] != wo->UCRcurve[0]); rv |= (ro->BGcurve[0] != wo->BGcurve[0]); if (ro->size != wo->size) error ("Text size doesn't match"); rv |= strcmp(ro->string, wo->string); if (rv) error ("UcrBg verify failed"); } } /* ------------ */ /* UInt16Array: */ { static icmUInt16Array *wo; if (mode == 0) { unsigned int i; /* There is no standard Tag that uses icSigUInt16ArrayType, so use a 'custom' tag */ if ((wo = (icmUInt16Array *)wr_icco->add_tag( wr_icco, str2tag("ui16"), icSigUInt16ArrayType)) == NULL) return 1; wo->size = rand_int(0,17); /* Number in array */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->size; i++) { wo->data[i] = rand_o16(); /* Set numbers value */ } } else { icmUInt16Array *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmUInt16Array *)rd_icco->read_tag(rd_icco, str2tag("ui16")); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigUInt16ArrayType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("UInt16Array size doesn't match"); for (i = 0; i < wo->size; i++) { rv |= (ro->data[i] != wo->data[i]); } if (rv) error ("UInt16Array verify failed"); } } /* ------------ */ /* UInt32Array: */ { static icmUInt32Array *wo; if (mode == 0) { unsigned int i; /* There is no standard Tag that uses icSigUInt32ArrayType, so use a 'custom' tag */ if ((wo = (icmUInt32Array *)wr_icco->add_tag( wr_icco, str2tag("ui32"), icSigUInt32ArrayType)) == NULL) return 1; wo->size = rand_int(0,18); /* Number in array */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->size; i++) { wo->data[i] = rand_o32(); /* Set numbers value */ } } else { icmUInt32Array *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmUInt32Array *)rd_icco->read_tag(rd_icco, str2tag("ui32")); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigUInt32ArrayType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("UInt32Array size doesn't match"); for (i = 0; i < wo->size; i++) { rv |= (ro->data[i] != wo->data[i]); } if (rv) error ("UInt32Array verify failed"); } } /* ------------ */ /* UInt64Array: */ { static icmUInt64Array *wo; if (mode == 0) { unsigned int i; /* There is no standard Tag that uses icSigUInt64ArrayType, so use a 'custom' tag */ if ((wo = (icmUInt64Array *)wr_icco->add_tag( wr_icco, str2tag("ui64"), icSigUInt64ArrayType)) == NULL) return 1; wo->size = rand_int(0,19); /* Number in array */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->size; i++) { wo->data[i].l = rand_o32(); /* Set numbers value - low 32 bits */ wo->data[i].h = rand_o32(); /* Set numbers value - low 32 bits */ } } else { icmUInt64Array *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmUInt64Array *)rd_icco->read_tag(rd_icco, str2tag("ui64")); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigUInt64ArrayType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("UInt64Array size doesn't match"); for (i = 0; i < wo->size; i++) { rv |= (ro->data[i].l != wo->data[i].l); rv |= (ro->data[i].h != wo->data[i].h); } if (rv) error ("UInt64Array verify failed"); } } /* ----------- */ /* UInt8Array: */ { static icmUInt8Array *wo; if (mode == 0) { unsigned int i; /* There is no standard Tag that uses icSigUInt8ArrayType, so use a 'custom' tag */ if ((wo = (icmUInt8Array *)wr_icco->add_tag( wr_icco, str2tag("ui08"), icSigUInt8ArrayType)) == NULL) return 1; wo->size = rand_int(0,18); /* Number in array */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->size; i++) { wo->data[i] = rand_o8(); /* Set numbers value */ } } else { icmUInt8Array *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmUInt8Array *)rd_icco->read_tag(rd_icco, str2tag("ui08")); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigUInt8ArrayType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("UInt8Array size doesn't match"); for (i = 0; i < wo->size; i++) { rv |= (ro->data[i] != wo->data[i]); } if (rv) error ("UInt8Array verify failed"); } } /* --------------- */ /* VideoCardGamma: (ColorSync specific) */ { static icmVideoCardGamma *wo; if (mode == 0) { int i; if ((wo = (icmVideoCardGamma *)wr_icco->add_tag( wr_icco, icSigVideoCardGammaTag, icSigVideoCardGammaType)) == NULL) return 1; wo->tagType = icmVideoCardGammaTableType; wo->u.table.channels = rand_int(1,3); wo->u.table.entryCount = rand_int(2,1024); wo->u.table.entrySize = rand_int(1,2); wo->allocate((icmBase *)wo); if (wo->u.table.entrySize == 1) { unsigned char *cp = wo->u.table.data; for (i=0; iu.table.channels*wo->u.table.entryCount;i++,cp++) *cp = (unsigned char)rand_int(0,255); } else { unsigned short *sp = wo->u.table.data; for (i=0; iu.table.channels*wo->u.table.entryCount;i++,sp++) *sp = (unsigned short)rand_int(0,65535); } } else { icmVideoCardGamma *ro; int i; /* Try and read tag from the file */ ro = (icmVideoCardGamma *)rd_icco->read_tag(rd_icco, icSigVideoCardGammaTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate */ if (ro->ttype != icSigVideoCardGammaType) return 1; /* Now check it out */ rv |= (ro->tagType != wo->tagType); rv |= (ro->u.table.channels != wo->u.table.channels); rv |= (ro->u.table.entryCount != wo->u.table.entryCount); rv |= (ro->u.table.entrySize != wo->u.table.entrySize); for (i=0; iu.table.channels*ro->u.table.entryCount*ro->u.table.entrySize; i++) { rv |= (((char*)ro->u.table.data)[i] != ((char*)wo->u.table.data)[i]); if (rv) break; } if (rv) error ("VideoCardGamma verify failed"); } } /* ------------------ */ /* ViewingConditions: */ { static icmViewingConditions *wo; if (mode == 0) { if ((wo = (icmViewingConditions *)wr_icco->add_tag( wr_icco, icSigViewingConditionsTag, icSigViewingConditionsType)) == NULL) return 1; wo->illuminant.X = rand_XYZ16(); /* XYZ of illuminant in cd/m^2 */ wo->illuminant.Y = rand_XYZ16(); wo->illuminant.Z = rand_XYZ16(); wo->surround.X = rand_XYZ16(); /* XYZ of surround in cd/m^2 */ wo->surround.Y = rand_XYZ16(); wo->surround.Z = rand_XYZ16(); wo->stdIlluminant = rand_Illuminant(); /* Standard illuminent type */ } else { icmViewingConditions *ro; /* Try and read the tag from the file */ ro = (icmViewingConditions *)rd_icco->read_tag(rd_icco, icSigViewingConditionsTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigViewingConditionsType) return 1; /* Now check it out */ rv |= dcomp(ro->illuminant.X, wo->illuminant.X); rv |= dcomp(ro->illuminant.Y, wo->illuminant.Y); rv |= dcomp(ro->illuminant.Z, wo->illuminant.Z); rv |= dcomp(ro->surround.X , wo->surround.X); rv |= dcomp(ro->surround.Y , wo->surround.Y); rv |= dcomp(ro->surround.Z , wo->surround.Z); rv |= (ro->stdIlluminant != wo->stdIlluminant); if (rv) error ("ViewingConditions verify failed"); } } /* ---------- */ /* XYZ array: */ { static icmXYZArray *wo; if (mode == 0) { unsigned int i; /* Note that tag types icSigXYZType and icSigXYZArrayType are identical */ if ((wo = (icmXYZArray *)wr_icco->add_tag( wr_icco, icSigMediaWhitePointTag, icSigXYZArrayType)) == NULL) return 1; wo->size = rand_int(1,7); /* Should be one XYZ number, but test more */ wo->allocate((icmBase *)wo); /* Allocate space */ for (i = 0; i < wo->size; i++) { wo->data[i].X = rand_XYZ16(); /* Set numbers value */ wo->data[i].Y = rand_XYZ16(); wo->data[i].Z = rand_XYZ16(); } } else { icmXYZArray *ro; unsigned int i; /* Try and read the tag from the file */ ro = (icmXYZArray *)rd_icco->read_tag(rd_icco, icSigMediaWhitePointTag); if (ro == NULL) return 1; /* Need to check that the cast is appropriate. */ if (ro->ttype != icSigXYZArrayType) return 1; /* Now check it out */ if (ro->size != wo->size) error ("XYZArray size doesn't match"); for (i = 0; i < wo->size; i++) { rv |= dcomp(ro->data[i].X, wo->data[i].X); rv |= dcomp(ro->data[i].Y, wo->data[i].Y); rv |= dcomp(ro->data[i].Z, wo->data[i].Z); } if (rv) error ("XYZArray verify failed"); } } return 0; } /* ------------------------------------------------ */ /* Floating point random number generators */ /* These are appropriate for the underlying integer */ /* representations in the icc format. */ /* This is simply as a convenience so that we can */ /* test the full range of representation, and */ /* get away with exact verification. */ /* 32 bit pseudo random sequencer */ static unsigned int seed = 0x12345678; /* #define PSRAND(S) ((S) * 1103515245 + 12345) */ #define PSRAND(S) (((S) & 0x80000000) ? (((S) << 1) ^ 0xa398655d) : ((S) << 1)) unsigned int rand_o8() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xff; return o32; } unsigned int rand_o16() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xffff; return o32; } unsigned int rand_o32() { ORD32 o32; o32 = seed = PSRAND(seed); return o32; } int rand_int(int low, int high) { int i; seed = PSRAND(seed); i = seed % (high - low + 1); return i + low; } double rand_u8f8() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xffff; return (double)o32/256.0; } double rand_u16f16() { ORD32 o32; seed = PSRAND(seed); o32 = seed; return (double)o32/65536.0; } double rand_s15f16() { INR32 i32; seed = PSRAND(seed); i32 = seed; return (double)i32/65536.0; } double rand_XYZ16() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xffff; return (double)o32/32768.0; } double rand_L8() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xff; return (double)o32/2.550; } double rand_ab8() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xff; return (double)o32-128.0; } double rand_L16() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xffff; return (double)o32/652.800; /* 0xff00/100.0 */ } double rand_ab16() { ORD32 o32; seed = PSRAND(seed); o32 = seed & 0xffff; return ((double)o32/256.0)-128.0; } double rand_8f() { unsigned int rv; seed = PSRAND(seed); rv = seed & 0xff; return (double)rv/255.0; } double rand_16f() { unsigned int rv; seed = PSRAND(seed); rv = seed & 0xffff; return (double)rv/65535.0; } /* Random selectors for ICC flags and enumerayions */ unsigned int rand_ScreenEncodings() { unsigned int flags = 0; if (rand_int(0,1) == 0) flags |= icPrtrDefaultScreensTrue; if (rand_int(0,1) == 0) flags |= icLinesPerInch; return flags; } /* Device attributes */ unsigned int rand_DeviceAttributes() { unsigned int flags = 0; if (rand_int(0,1) == 0) flags |= icTransparency; if (rand_int(0,1) == 0) flags |= icMatte; return flags; } /* Profile header flags */ unsigned int rand_ProfileHeaderFlags() { unsigned int flags = 0; if (rand_int(0,1) == 0) flags |= icEmbeddedProfileTrue; if (rand_int(0,1) == 0) flags |= icUseWithEmbeddedDataOnly; return flags; } unsigned int rand_AsciiOrBinaryData() { unsigned int flags = 0; if (rand_int(0,1) == 0) flags |= icBinaryData; return flags; } icColorSpaceSignature rand_ColorSpaceSignature() { switch(rand_int(0,25)) { case 0: return icSigXYZData; case 1: return icSigLabData; case 2: return icSigLuvData; case 3: return icSigYCbCrData; case 4: return icSigYxyData; case 5: return icSigRgbData; case 6: return icSigGrayData; case 7: return icSigHsvData; case 8: return icSigHlsData; case 9: return icSigCmykData; case 10: return icSigCmyData; case 11: return icSigMch6Data; case 12: return icSig2colorData; case 13: return icSig3colorData; case 14: return icSig4colorData; case 15: return icSig5colorData; case 16: return icSig6colorData; case 17: return icSig7colorData; case 18: return icSig8colorData; case 19: return icSig9colorData; case 20: return icSig10colorData; case 21: return icSig11colorData; case 22: return icSig12colorData; case 23: return icSig13colorData; case 24: return icSig14colorData; case 25: return icSig15colorData; } return icMaxEnumData; } icColorSpaceSignature rand_PCS() { switch(rand_int(0,1)) { case 0: return icSigXYZData; case 1: return icSigLabData; } return icMaxEnumData; } icTechnologySignature rand_TechnologySignature() { switch(rand_int(0,21)) { case 0: return icSigDigitalCamera; case 1: return icSigFilmScanner; case 2: return icSigReflectiveScanner; case 3: return icSigInkJetPrinter; case 4: return icSigThermalWaxPrinter; case 5: return icSigElectrophotographicPrinter; case 6: return icSigElectrostaticPrinter; case 7: return icSigDyeSublimationPrinter; case 8: return icSigPhotographicPaperPrinter; case 9: return icSigFilmWriter; case 10: return icSigVideoMonitor; case 11: return icSigVideoCamera; case 12: return icSigProjectionTelevision; case 13: return icSigCRTDisplay; case 14: return icSigPMDisplay; case 15: return icSigAMDisplay; case 16: return icSigPhotoCD; case 17: return icSigPhotoImageSetter; case 18: return icSigGravure; case 19: return icSigOffsetLithography; case 20: return icSigSilkscreen; case 21: return icSigFlexography; } return icMaxEnumTechnology; } icProfileClassSignature rand_ProfileClassSignature() { switch(rand_int(0,6)) { case 0: return icSigInputClass; case 1: return icSigDisplayClass; case 2: return icSigOutputClass; case 3: return icSigLinkClass; case 4: return icSigAbstractClass; case 5: return icSigColorSpaceClass; case 6: return icSigNamedColorClass; } return icMaxEnumClass; } icPlatformSignature rand_PlatformSignature() { switch(rand_int(0,4)) { case 0: return icSigMacintosh; case 1: return icSigMicrosoft; case 2: return icSigSolaris; case 3: return icSigSGI; case 4: return icSigTaligent; } return icMaxEnumPlatform; } icMeasurementFlare rand_MeasurementFlare() { switch(rand_int(0,1)) { case 0: return icFlare0; case 1: return icFlare100; } return icMaxFlare; } icMeasurementGeometry rand_MeasurementGeometry() { switch(rand_int(0,2)) { case 0: return icGeometryUnknown; case 1: return icGeometry045or450; case 2: return icGeometry0dord0; } return icMaxGeometry; } icRenderingIntent rand_RenderingIntent() { switch(rand_int(0,3)) { case 0: return icPerceptual; case 1: return icRelativeColorimetric; case 2: return icSaturation; case 3: return icAbsoluteColorimetric; } return icMaxEnumIntent; } icSpotShape rand_SpotShape() { switch(rand_int(0,7)) { case 0: return icSpotShapeUnknown; case 1: return icSpotShapePrinterDefault; case 2: return icSpotShapeRound; case 3: return icSpotShapeDiamond; case 4: return icSpotShapeEllipse; case 5: return icSpotShapeLine; case 6: return icSpotShapeSquare; case 7: return icSpotShapeCross; } return icMaxEnumSpot; } icStandardObserver rand_StandardObserver() { switch(rand_int(0,2)) { case 0: return icStdObsUnknown; case 1: return icStdObs1931TwoDegrees; case 2: return icStdObs1964TenDegrees; } return icMaxStdObs; } icIlluminant rand_Illuminant() { switch(rand_int(0,8)) { case 0: return icIlluminantUnknown; case 1: return icIlluminantD50; case 2: return icIlluminantD65; case 3: return icIlluminantD93; case 4: return icIlluminantF2; case 5: return icIlluminantD55; case 6: return icIlluminantA; case 7: return icIlluminantEquiPowerE; case 8: return icIlluminantF8; } return icMaxEnumIlluminant; } /* Compare doubles with a margine to allow */ /* for floating point handling funnies */ int dcomp(double a, double b) { double dif = fabs(a - b); double mag = fabs(a) + fabs(b); return dif > (mag * 1e-10) ? 1 : 0; } /* ------------------------------------------------ */ /* Basic printf type error() and warning() routines */ void error(char *fmt, ...) { va_list args; fprintf(stderr,"icctest: 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,"icctest: Warning - "); va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); }