diff options
author | AlexSm <alex@ydb.tech> | 2023-12-21 15:05:38 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-21 15:05:38 +0100 |
commit | e98bcbc74422492351c51646dba3849a138a8ffc (patch) | |
tree | 38ad7a09b1f9c201ce8a7e3d69f2017388769224 /contrib/libs/lcms2/src | |
parent | 559d7083cd8378cb25b9e966dedcca21d413e338 (diff) | |
download | ydb-e98bcbc74422492351c51646dba3849a138a8ffc.tar.gz |
Import libs 1 (#590)
* Import libs 1
* Add new file without extension
* Add file missed in export config
Diffstat (limited to 'contrib/libs/lcms2/src')
-rw-r--r-- | contrib/libs/lcms2/src/cmsalpha.c | 28 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmscgats.c | 499 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmscnvrt.c | 43 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmserr.c | 7 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsgamma.c | 28 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsgmt.c | 4 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsio0.c | 31 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsio1.c | 12 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmslut.c | 11 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsnamed.c | 250 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsopt.c | 16 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmspack.c | 185 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsplugin.c | 21 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsps2.c | 191 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmssamp.c | 2 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmstypes.c | 273 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsvirt.c | 137 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/cmsxform.c | 15 | ||||
-rw-r--r-- | contrib/libs/lcms2/src/lcms2_internal.h | 7 |
19 files changed, 1416 insertions, 344 deletions
diff --git a/contrib/libs/lcms2/src/cmsalpha.c b/contrib/libs/lcms2/src/cmsalpha.c index 806577f994..7422256ca3 100644 --- a/contrib/libs/lcms2/src/cmsalpha.c +++ b/contrib/libs/lcms2/src/cmsalpha.c @@ -402,7 +402,7 @@ static cmsFormatterAlphaFn FormattersAlpha[6][6] = { // This function computes the distance from each component to the next one in bytes. static -void ComputeIncrementsForChunky(cmsUInt32Number Format, +cmsBool ComputeIncrementsForChunky(cmsUInt32Number Format, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) { @@ -416,7 +416,7 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, // Sanity check if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) - return; + return FALSE; memset(channels, 0, sizeof(channels)); @@ -453,13 +453,15 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, for (i = 0; i < extra; i++) ComponentStartingOrder[i] = channels[i + nchannels]; + + return TRUE; } // On planar configurations, the distance is the stride added to any non-negative static -void ComputeIncrementsForPlanar(cmsUInt32Number Format, +cmsBool ComputeIncrementsForPlanar(cmsUInt32Number Format, cmsUInt32Number BytesPerPlane, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) @@ -473,7 +475,7 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format, // Sanity check if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) - return; + return FALSE; memset(channels, 0, sizeof(channels)); @@ -509,29 +511,29 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format, for (i = 0; i < extra; i++) ComponentStartingOrder[i] = channels[i + nchannels]; + + return TRUE; } // Dispatcher por chunky and planar RGB static -void ComputeComponentIncrements(cmsUInt32Number Format, +cmsBool ComputeComponentIncrements(cmsUInt32Number Format, cmsUInt32Number BytesPerPlane, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) { if (T_PLANAR(Format)) { - ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); + return ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); } else { - ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); + return ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); } } - - // Handles extra channels copying alpha if requested by the flags void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, void* out, @@ -565,9 +567,11 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, if (nExtra == 0) return; - // Compute the increments - ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements); - ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements); + // Compute the increments + if (!ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements)) + return; + if (!ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements)) + return; // Check for conversions 8, 16, half, float, dbl copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat); diff --git a/contrib/libs/lcms2/src/cmscgats.c b/contrib/libs/lcms2/src/cmscgats.c index 51fc2a6e28..bccbf58c10 100644 --- a/contrib/libs/lcms2/src/cmscgats.c +++ b/contrib/libs/lcms2/src/cmscgats.c @@ -58,7 +58,7 @@ typedef enum { SEOF, // End of stream SSYNERROR, // Syntax error found on stream - // Keywords + // IT8 symbols SBEGIN_DATA, SBEGIN_DATA_FORMAT, @@ -66,7 +66,19 @@ typedef enum { SEND_DATA_FORMAT, SKEYWORD, SDATA_FORMAT_ID, - SINCLUDE + SINCLUDE, + + // Cube symbols + + SDOMAIN_MAX, + SDOMAIN_MIN, + S_LUT1D_SIZE, + S_LUT1D_INPUT_RANGE, + S_LUT3D_SIZE, + S_LUT3D_INPUT_RANGE, + S_LUT_IN_VIDEO_RANGE, + S_LUT_OUT_VIDEO_RANGE, + STITLE } SYMBOL; @@ -149,6 +161,10 @@ typedef struct struct_it8 { cmsUInt32Number TablesCount; // How many tables in this stream cmsUInt32Number nTable; // The actual table + // Partser type + cmsBool IsCUBE; + + // Tables TABLE Tab[MAXTABLES]; // Memory management @@ -208,8 +224,8 @@ typedef struct { } KEYWORD; -// The keyword->symbol translation table. Sorting is required. -static const KEYWORD TabKeys[] = { +// The keyword->symbol translation tables. Sorting is required. +static const KEYWORD TabKeysIT8[] = { {"$INCLUDE", SINCLUDE}, // This is an extension! {".INCLUDE", SINCLUDE}, // This is an extension! @@ -222,7 +238,25 @@ static const KEYWORD TabKeys[] = { {"KEYWORD", SKEYWORD} }; -#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) +#define NUMKEYS_IT8 (sizeof(TabKeysIT8)/sizeof(KEYWORD)) + +static const KEYWORD TabKeysCUBE[] = { + + {"DOMAIN_MAX", SDOMAIN_MAX }, + {"DOMAIN_MIN", SDOMAIN_MIN }, + {"LUT_1D_SIZE", S_LUT1D_SIZE }, + {"LUT_1D_INPUT_RANGE", S_LUT1D_INPUT_RANGE }, + {"LUT_3D_SIZE", S_LUT3D_SIZE }, + {"LUT_3D_INPUT_RANGE", S_LUT3D_INPUT_RANGE }, + {"LUT_IN_VIDEO_RANGE", S_LUT_IN_VIDEO_RANGE }, + {"LUT_OUT_VIDEO_RANGE", S_LUT_OUT_VIDEO_RANGE }, + {"TITLE", STITLE } + +}; + +#define NUMKEYS_CUBE (sizeof(TabKeysCUBE)/sizeof(KEYWORD)) + + // Predefined properties @@ -426,7 +460,7 @@ void StringCat(string* s, const char* c) static cmsBool isseparator(int c) { - return (c == ' ') || (c == '\t') ; + return (c == ' ') || (c == '\t'); } // Checks whatever c is a valid identifier char @@ -447,7 +481,7 @@ cmsBool isidchar(int c) static cmsBool isfirstidchar(int c) { - return !isdigit(c) && ismiddle(c); + return c != '-' && !isdigit(c) && ismiddle(c); } // Guess whether the supplied path looks like an absolute path @@ -486,13 +520,13 @@ cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffe // Already absolute? if (isabsolutepath(relPath)) { - strncpy(buffer, relPath, MaxLen); + memcpy(buffer, relPath, MaxLen); buffer[MaxLen-1] = 0; return TRUE; } // No, search for last - strncpy(buffer, basePath, MaxLen); + memcpy(buffer, basePath, MaxLen); buffer[MaxLen-1] = 0; tail = strrchr(buffer, DIR_CHAR); @@ -574,10 +608,10 @@ void NextCh(cmsIT8* it8) // Try to see if current identifier is a keyword, if so return the referred symbol static -SYMBOL BinSrchKey(const char *id) +SYMBOL BinSrchKey(const char *id, int NumKeys, const KEYWORD* TabKeys) { int l = 1; - int r = NUMKEYS; + int r = NumKeys; int x, res; while (r >= l) @@ -747,7 +781,7 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer) } -// Reads a string, special case to avoid infinite resursion on .include +// Reads a string, special case to avoid infinite recursion on .include static void InStringSymbol(cmsIT8* it8) { @@ -804,7 +838,9 @@ void InSymbol(cmsIT8* it8) } while (isidchar(it8->ch)); - key = BinSrchKey(StringPtr(it8->id)); + key = BinSrchKey(StringPtr(it8->id), + it8->IsCUBE ? NUMKEYS_CUBE : NUMKEYS_IT8, + it8->IsCUBE ? TabKeysCUBE : TabKeysIT8); if (key == SUNDEFINED) it8->sy = SIDENT; else it8->sy = key; @@ -913,6 +949,7 @@ void InSymbol(cmsIT8* it8) snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum); } + StringClear(it8->id); StringCat(it8->id, buffer); do { @@ -942,7 +979,7 @@ void InSymbol(cmsIT8* it8) // Next line case '\r': NextCh(it8); - if (it8 ->ch == '\n') + if (it8->ch == '\n') NextCh(it8); it8->sy = SEOLN; it8->lineno++; @@ -1263,7 +1300,12 @@ KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *S // This may work for editing properties - // return SynError(it8, "duplicate key <%s>", Key); + if (cmsstrcasecmp(Key, "NUMBER_OF_FIELDS") == 0 || + cmsstrcasecmp(Key, "NUMBER_OF_SETS") == 0) { + + SynError(it8, "duplicate key <%s>", Key); + return NULL; + } } else { @@ -1384,6 +1426,8 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) it8->MemoryBlock = NULL; it8->MemorySink = NULL; + it8->IsCUBE = FALSE; + it8 ->nTable = 0; it8->ContextID = ContextID; @@ -1665,7 +1709,7 @@ char* GetData(cmsIT8* it8, int nSet, int nField) int nSamples = t -> nSamples; int nPatches = t -> nPatches; - if (nSet >= nPatches || nField >= nSamples) + if (nSet < 0 || nSet >= nPatches || nField < 0 || nField >= nSamples) return NULL; if (!t->Data) return NULL; @@ -1850,11 +1894,14 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) WriteStr(fp, " "); nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); - for (i = 0; i < nSamples; i++) { + if (nSamples <= t->nSamples) { - WriteStr(fp, t->DataFormat[i]); - WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t")); - } + for (i = 0; i < nSamples; i++) { + + WriteStr(fp, t->DataFormat[i]); + WriteStr(fp, ((i == (nSamples - 1)) ? "\n" : "\t")); + } + } WriteStr (fp, "END_DATA_FORMAT\n"); } @@ -1864,39 +1911,42 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) static void WriteData(SAVESTREAM* fp, cmsIT8* it8) { - int i, j; + int i, j, nPatches; TABLE* t = GetTable(it8); if (!t->Data) return; WriteStr (fp, "BEGIN_DATA\n"); - t->nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); + nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); - for (i = 0; i < t-> nPatches; i++) { + if (nPatches <= t->nPatches) { - WriteStr(fp, " "); + for (i = 0; i < nPatches; i++) { - for (j = 0; j < t->nSamples; j++) { + WriteStr(fp, " "); - char *ptr = t->Data[i*t->nSamples+j]; + for (j = 0; j < t->nSamples; j++) { - if (ptr == NULL) WriteStr(fp, "\"\""); - else { - // If value contains whitespace, enclose within quote + char* ptr = t->Data[i * t->nSamples + j]; - if (strchr(ptr, ' ') != NULL) { + if (ptr == NULL) WriteStr(fp, "\"\""); + else { + // If value contains whitespace, enclose within quote - WriteStr(fp, "\""); - WriteStr(fp, ptr); - WriteStr(fp, "\""); - } - else - WriteStr(fp, ptr); - } + if (strchr(ptr, ' ') != NULL) { - WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t")); - } + WriteStr(fp, "\""); + WriteStr(fp, ptr); + WriteStr(fp, "\""); + } + else + WriteStr(fp, ptr); + } + + WriteStr(fp, ((j == (t->nSamples - 1)) ? "\n" : "\t")); + } + } } WriteStr (fp, "END_DATA\n"); } @@ -1917,15 +1967,29 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) for (i=0; i < it8 ->TablesCount; i++) { - cmsIT8SetTable(hIT8, i); - WriteHeader(it8, &sd); - WriteDataFormat(&sd, it8); - WriteData(&sd, it8); + TABLE* t; + + if (cmsIT8SetTable(hIT8, i) < 0) goto Error; + + /** + * Check for wrong data + */ + t = GetTable(it8); + if (t->Data == NULL) goto Error; + if (t->DataFormat == NULL) goto Error; + + WriteHeader(it8, &sd); + WriteDataFormat(&sd, it8); + WriteData(&sd, it8); } if (fclose(sd.stream) != 0) return FALSE; - return TRUE; + +Error: + fclose(sd.stream); + return FALSE; + } @@ -2302,78 +2366,72 @@ void CookPointers(cmsIT8* it8) int idField, i; char* Fld; cmsUInt32Number j; - cmsUInt32Number nOldTable = it8 ->nTable; + cmsUInt32Number nOldTable = it8->nTable; - for (j=0; j < it8 ->TablesCount; j++) { + for (j = 0; j < it8->TablesCount; j++) { - TABLE* t = it8 ->Tab + j; + TABLE* t = it8->Tab + j; - t -> SampleID = 0; - it8 ->nTable = j; - - for (idField = 0; idField < t -> nSamples; idField++) - { - if (t ->DataFormat == NULL){ - SynError(it8, "Undefined DATA_FORMAT"); - return; - } - - Fld = t->DataFormat[idField]; - if (!Fld) continue; - - - if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { - - t -> SampleID = idField; - } + t->SampleID = 0; + it8->nTable = j; - // "LABEL" is an extension. It keeps references to forward tables - - if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') { + for (idField = 0; idField < t->nSamples; idField++) + { + if (t->DataFormat == NULL) { + SynError(it8, "Undefined DATA_FORMAT"); + return; + } - // Search for table references... - for (i = 0; i < t->nPatches; i++) { + Fld = t->DataFormat[idField]; + if (!Fld) continue; - char* Label = GetData(it8, i, idField); - if (Label) { + if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { - cmsUInt32Number k; + t->SampleID = idField; + } - // This is the label, search for a table containing - // this property + // "LABEL" is an extension. It keeps references to forward tables - for (k = 0; k < it8->TablesCount; k++) { + if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') { - TABLE* Table = it8->Tab + k; - KEYVALUE* p; + // Search for table references... + for (i = 0; i < t->nPatches; i++) { - if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { + char* Label = GetData(it8, i, idField); - // Available, keep type and table - char Buffer[256]; + if (Label) { - char* Type = p->Value; - int nTable = (int)k; + cmsUInt32Number k; - snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type); + // This is the label, search for a table containing + // this property - SetData(it8, i, idField, Buffer); - } - } + for (k = 0; k < it8->TablesCount; k++) { + TABLE* Table = it8->Tab + k; + KEYVALUE* p; - } + if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { - } + // Available, keep type and table + char Buffer[256]; + char* Type = p->Value; + int nTable = (int)k; - } + snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type); - } - } + SetData(it8, i, idField, Buffer); + } + } + } + } + } + } + } - it8 ->nTable = nOldTable; + it8->nTable = nOldTable; } // Try to infere if the file is a CGATS/IT8 file at all. Read first line @@ -2464,7 +2522,7 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm if (it8->MemoryBlock == NULL) { cmsIT8Free(hIT8); - return FALSE; + return NULL; } strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); @@ -2476,7 +2534,7 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm if (!ParseIT8(it8, type-1)) { cmsIT8Free(hIT8); - return FALSE; + return NULL; } CookPointers(it8); @@ -2573,17 +2631,17 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyN } - Props = (char**)AllocChunk(it8, sizeof(char*) * n); - if (Props != NULL) { + Props = (char**)AllocChunk(it8, sizeof(char*) * n); + if (Props != NULL) { - // Pass#2 - Fill pointers - n = 0; - for (p = t->HeaderList; p != NULL; p = p->Next) { - Props[n++] = p->Keyword; - } + // Pass#2 - Fill pointers + n = 0; + for (p = t->HeaderList; p != NULL; p = p->Next) { + Props[n++] = p->Keyword; + } - } - *PropertyNames = Props; + } + *PropertyNames = Props; return n; } @@ -2943,3 +3001,236 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; } + +static +cmsBool ReadNumbers(cmsIT8* cube, int n, cmsFloat64Number* arr) +{ + int i; + + for (i = 0; i < n; i++) { + + if (cube->sy == SINUM) + arr[i] = cube->inum; + else + if (cube->sy == SDNUM) + arr[i] = cube->dnum; + else + return SynError(cube, "Number expected"); + + InSymbol(cube); + } + + return CheckEOLN(cube); +} + +static +cmsBool ParseCube(cmsIT8* cube, cmsStage** Shaper, cmsStage** CLUT, char title[]) +{ + cmsFloat64Number domain_min[3] = { 0, 0, 0 }; + cmsFloat64Number domain_max[3] = { 1.0, 1.0, 1.0 }; + cmsFloat64Number check_0_1[2] = { 0, 1.0 }; + int shaper_size = 0; + int lut_size = 0; + int i; + + InSymbol(cube); + + while (cube->sy != SEOF) { + switch (cube->sy) + { + // Set profile description + case STITLE: + InSymbol(cube); + if (!Check(cube, SSTRING, "Title string expected")) return FALSE; + memcpy(title, StringPtr(cube->str), MAXSTR); + title[MAXSTR - 1] = 0; + InSymbol(cube); + break; + + // Define domain + case SDOMAIN_MIN: + InSymbol(cube); + if (!ReadNumbers(cube, 3, domain_min)) return FALSE; + break; + + case SDOMAIN_MAX: + InSymbol(cube); + if (!ReadNumbers(cube, 3, domain_max)) return FALSE; + break; + + // Define shaper + case S_LUT1D_SIZE: + InSymbol(cube); + if (!Check(cube, SINUM, "Shaper size expected")) return FALSE; + shaper_size = cube->inum; + InSymbol(cube); + break; + + // Deefine CLUT + case S_LUT3D_SIZE: + InSymbol(cube); + if (!Check(cube, SINUM, "LUT size expected")) return FALSE; + lut_size = cube->inum; + InSymbol(cube); + break; + + // Range. If present, has to be 0..1.0 + case S_LUT1D_INPUT_RANGE: + case S_LUT3D_INPUT_RANGE: + InSymbol(cube); + if (!ReadNumbers(cube, 2, check_0_1)) return FALSE; + if (check_0_1[0] != 0 || check_0_1[1] != 1.0) { + return SynError(cube, "Unsupported format"); + } + break; + + case SEOLN: + InSymbol(cube); + break; + + default: + case S_LUT_IN_VIDEO_RANGE: + case S_LUT_OUT_VIDEO_RANGE: + return SynError(cube, "Unsupported format"); + + // Read and create tables + case SINUM: + case SDNUM: + + if (shaper_size > 0) { + + cmsToneCurve* curves[3]; + cmsFloat32Number* shapers = (cmsFloat32Number*)_cmsMalloc(cube->ContextID, 3 * shaper_size * sizeof(cmsFloat32Number)); + if (shapers == NULL) return FALSE; + + for (i = 0; i < shaper_size; i++) { + + cmsFloat64Number nums[3]; + + if (!ReadNumbers(cube, 3, nums)) return FALSE; + + shapers[i + 0] = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0])); + shapers[i + 1 * shaper_size] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1])); + shapers[i + 2 * shaper_size] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2])); + } + + for (i = 0; i < 3; i++) { + + curves[i] = cmsBuildTabulatedToneCurveFloat(cube->ContextID, shaper_size, + &shapers[i * shaper_size]); + if (curves[i] == NULL) return FALSE; + } + + *Shaper = cmsStageAllocToneCurves(cube->ContextID, 3, curves); + + cmsFreeToneCurveTriple(curves); + } + + if (lut_size > 0) { + + int nodes = lut_size * lut_size * lut_size; + + cmsFloat32Number* lut_table = _cmsMalloc(cube->ContextID, nodes * 3 * sizeof(cmsFloat32Number)); + if (lut_table == NULL) return FALSE; + + for (i = 0; i < nodes; i++) { + + cmsFloat64Number nums[3]; + + if (!ReadNumbers(cube, 3, nums)) return FALSE; + + lut_table[i * 3 + 2] = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0])); + lut_table[i * 3 + 1] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1])); + lut_table[i * 3 + 0] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2])); + } + + *CLUT = cmsStageAllocCLutFloat(cube->ContextID, lut_size, 3, 3, lut_table); + _cmsFree(cube->ContextID, lut_table); + } + + if (!Check(cube, SEOF, "Extra symbols found in file")) return FALSE; + } + } + + return TRUE; +} + +// Share the parser to read .cube format and create RGB devicelink profiles +cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName) +{ + cmsHPROFILE hProfile = NULL; + cmsIT8* cube = NULL; + cmsPipeline* Pipeline = NULL; + cmsStage* CLUT = NULL; + cmsStage* Shaper = NULL; + cmsMLU* DescriptionMLU = NULL; + char title[MAXSTR]; + + _cmsAssert(cFileName != NULL); + + cube = (cmsIT8*) cmsIT8Alloc(ContextID); + if (!cube) return NULL; + + cube->IsCUBE = TRUE; + cube->FileStack[0]->Stream = fopen(cFileName, "rt"); + + if (!cube->FileStack[0]->Stream) goto Done; + + strncpy(cube->FileStack[0]->FileName, cFileName, cmsMAX_PATH - 1); + cube->FileStack[0]->FileName[cmsMAX_PATH - 1] = 0; + + if (!ParseCube(cube, &Shaper, &CLUT, title)) goto Done; + + // Success on parsing, let's create the profile + hProfile = cmsCreateProfilePlaceholder(ContextID); + if (!hProfile) goto Done; + + cmsSetProfileVersion(hProfile, 4.4); + + cmsSetDeviceClass(hProfile, cmsSigLinkClass); + cmsSetColorSpace(hProfile, cmsSigRgbData); + cmsSetPCS(hProfile, cmsSigRgbData); + + cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL); + + // Creates a Pipeline to hold CLUT and shaper + Pipeline = cmsPipelineAlloc(ContextID, 3, 3); + if (Pipeline == NULL) goto Done; + + // Populates the pipeline + if (Shaper != NULL) { + if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Shaper)) + goto Done; + } + + if (CLUT != NULL) { + if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) + goto Done; + } + + // Propagate the description. We put no copyright because we know + // nothing on the copyrighted state of the .cube + DescriptionMLU = cmsMLUalloc(ContextID, 1); + if (!cmsMLUsetUTF8(DescriptionMLU, cmsNoLanguage, cmsNoCountry, title)) goto Done; + + // Flush the tags + if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Done; + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, (void*)Pipeline)) goto Done; + +Done: + + if (DescriptionMLU != NULL) + cmsMLUfree(DescriptionMLU); + + if (Pipeline != NULL) + cmsPipelineFree(Pipeline); + + cmsIT8Free((cmsHANDLE) cube); + + return hProfile; +} + +cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName) +{ + return cmsCreateDeviceLinkFromCubeFileTHR(NULL, cFileName); +} diff --git a/contrib/libs/lcms2/src/cmscnvrt.c b/contrib/libs/lcms2/src/cmscnvrt.c index de63975427..f00c117337 100644 --- a/contrib/libs/lcms2/src/cmscnvrt.c +++ b/contrib/libs/lcms2/src/cmscnvrt.c @@ -715,6 +715,16 @@ int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSRE return TRUE; } + +// Check whatever the profile is a CMYK->CMYK devicelink +static +cmsBool is_cmyk_devicelink(cmsHPROFILE hProfile) +{ + return cmsGetDeviceClass(hProfile) == cmsSigLinkClass && + cmsGetColorSpace(hProfile) == cmsSigCmykData && + cmsGetColorSpace(hProfile) == cmsSigCmykData; +} + // This is the entry for black-preserving K-only intents, which are non-ICC static cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, @@ -747,14 +757,16 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, lastProfilePos = nProfiles - 1; hLastProfile = hProfiles[lastProfilePos]; - while (lastProfilePos > 1) + // Skip CMYK->CMYK devicelinks on ending + while (is_cmyk_devicelink(hLastProfile)) { - hLastProfile = hProfiles[--lastProfilePos]; - if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData || - cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass) + if (lastProfilePos < 2) break; + + hLastProfile = hProfiles[--lastProfilePos]; } + preservationProfilesCount = lastProfilePos + 1; // Check for non-cmyk profiles @@ -771,7 +783,7 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, // Create a LUT holding normal ICC transform bp.cmyk2cmyk = DefaultICCintents(ContextID, - preservationProfilesCount, + preservationProfilesCount, ICCIntents, hProfiles, BPC, @@ -783,7 +795,7 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, // Now, compute the tone curve bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, - preservationProfilesCount, + preservationProfilesCount, ICCIntents, hProfiles, BPC, @@ -973,13 +985,14 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, lastProfilePos = nProfiles - 1; hLastProfile = hProfiles[lastProfilePos]; - while (lastProfilePos > 1) - { + // Skip CMYK->CMYK devicelinks on ending + while (is_cmyk_devicelink(hLastProfile)) + { + if (lastProfilePos < 2) + break; + hLastProfile = hProfiles[--lastProfilePos]; - if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData || - cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass) - break; - } + } preservationProfilesCount = lastProfilePos + 1; @@ -1148,8 +1161,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn cmsIntentsList* pt; cmsUInt32Number nIntents; - - for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) @@ -1162,7 +1174,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn nIntents++; } - for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + for (pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) @@ -1174,6 +1186,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn nIntents++; } + return nIntents; } diff --git a/contrib/libs/lcms2/src/cmserr.c b/contrib/libs/lcms2/src/cmserr.c index ccb40f9261..811c63502d 100644 --- a/contrib/libs/lcms2/src/cmserr.c +++ b/contrib/libs/lcms2/src/cmserr.c @@ -72,7 +72,7 @@ long int CMSEXPORT cmsfilelength(FILE* f) // // This is the interface to low-level memory management routines. By default a simple // wrapping to malloc/free/realloc is provided, although there is a limit on the max -// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent +// amount of memory that can be reclaimed. This is mostly as a safety feature to prevent // bogus or evil code to allocate huge blocks that otherwise lcms would never need. #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) @@ -92,7 +92,8 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plug static void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) { - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum + // Never allow 0 or over maximum + if (size == 0 || size > MAX_MEMORY_FOR_ALLOC) return NULL; return (void*) malloc(size); @@ -234,7 +235,7 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the - // context internal data should be malloce'd by using those functions. + // context internal data should be malloc'ed by using those functions. if (Data == NULL) { struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; diff --git a/contrib/libs/lcms2/src/cmsgamma.c b/contrib/libs/lcms2/src/cmsgamma.c index 1031fc15e0..a8a8946205 100644 --- a/contrib/libs/lcms2/src/cmsgamma.c +++ b/contrib/libs/lcms2/src/cmsgamma.c @@ -300,6 +300,10 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEnt return p; Error: + for (i=0; i < nSegments; i++) { + if (p ->Segments && p ->Segments[i].SampledPoints) _cmsFree(ContextID, p ->Segments[i].SampledPoints); + if (p ->SegInterp && p ->SegInterp[i]) _cmsFree(ContextID, p ->SegInterp[i]); + } if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp); if (p -> Segments) _cmsFree(ContextID, p -> Segments); if (p -> Evals) _cmsFree(ContextID, p -> Evals); @@ -593,10 +597,16 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu case 6: e = Params[1]*R + Params[2]; - if (e < 0) - Val = Params[3]; - else - Val = pow(e, Params[0]) + Params[3]; + // On gamma 1.0, don't clamp + if (Params[0] == 1.0) { + Val = e + Params[3]; + } + else { + if (e < 0) + Val = Params[3]; + else + Val = pow(e, Params[0]) + Params[3]; + } break; // ((Y - c) ^1/Gamma - b) / a @@ -1491,13 +1501,13 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num return (sum / n); // The mean } +// Retrieve segments on tone curves -// Retrieve parameters on one-segment tone curves - -cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t) +const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t) { _cmsAssert(t != NULL); - if (t->nSegments != 1) return NULL; - return t->Segments[0].Params; + if (n < 0 || n >= (cmsInt32Number) t->nSegments) return NULL; + return t->Segments + n; } + diff --git a/contrib/libs/lcms2/src/cmsgmt.c b/contrib/libs/lcms2/src/cmsgmt.c index 5109bfaefb..64573476c8 100644 --- a/contrib/libs/lcms2/src/cmsgmt.c +++ b/contrib/libs/lcms2/src/cmsgmt.c @@ -219,7 +219,7 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; cmsFloat64Number dE1, dE2, ErrorRatio; - // Assume in-gamut by default. + // Assume in-gamut by default. NEVER READ, USED FOR DEBUG PURPOSES. ErrorRatio = 1.0; // Convert input to Lab @@ -596,7 +596,7 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, // Actually, doing that "well" is quite hard, since every component may behave completely different. // Since the true point of this function is to detect suitable optimizations, I am imposing some requirements // that simplifies things: only RGB, and only profiles that can got in both directions. -// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma. +// The algorithm obtains Y from a synthetical gray R=G=B. Then least squares fitting is used to estimate gamma. // For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned. cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold) diff --git a/contrib/libs/lcms2/src/cmsio0.c b/contrib/libs/lcms2/src/cmsio0.c index 945140a3c8..75442e664d 100644 --- a/contrib/libs/lcms2/src/cmsio0.c +++ b/contrib/libs/lcms2/src/cmsio0.c @@ -530,7 +530,21 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) // Set default version Icc ->Version = 0x02100000; - + + // Set default CMM (that's me!) + Icc ->CMM = lcmsSignature; + + // Set default creator + // Created by LittleCMS (that's me!) + Icc ->creator = lcmsSignature; + + // Set default platform +#ifdef CMS_IS_WINDOWS_ + Icc ->platform = cmsSigMicrosoft; +#else + Icc ->platform = cmsSigMacintosh; +#endif + // Set default device class Icc->DeviceClass = cmsSigDisplayClass; @@ -784,16 +798,18 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) } // Adjust endianness of the used parameters + Icc -> CMM = _cmsAdjustEndianess32(Header.cmmId); Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); + Icc -> platform = (cmsPlatformSignature)_cmsAdjustEndianess32(Header.platform); Icc -> flags = _cmsAdjustEndianess32(Header.flags); Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); Icc -> model = _cmsAdjustEndianess32(Header.model); Icc -> creator = _cmsAdjustEndianess32(Header.creator); - + _cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes); Icc -> Version = _cmsAdjustEndianess32(_validatedVersion(Header.version)); @@ -893,7 +909,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) cmsUInt32Number Count; Header.size = _cmsAdjustEndianess32(UsedSpace); - Header.cmmId = _cmsAdjustEndianess32(lcmsSignature); + Header.cmmId = _cmsAdjustEndianess32(Icc ->CMM); Header.version = _cmsAdjustEndianess32(Icc ->Version); Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass); @@ -905,11 +921,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); -#ifdef CMS_IS_WINDOWS_ - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); -#else - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); -#endif + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(Icc -> platform); Header.flags = _cmsAdjustEndianess32(Icc -> flags); Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); @@ -925,8 +937,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y)); Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z)); - // Created by LittleCMS (that's me!) - Header.creator = _cmsAdjustEndianess32(lcmsSignature); + Header.creator = _cmsAdjustEndianess32(Icc ->creator); memset(&Header.reserved, 0, sizeof(Header.reserved)); diff --git a/contrib/libs/lcms2/src/cmsio1.c b/contrib/libs/lcms2/src/cmsio1.c index b923739f60..c75b454cd5 100644 --- a/contrib/libs/lcms2/src/cmsio1.c +++ b/contrib/libs/lcms2/src/cmsio1.c @@ -578,7 +578,7 @@ Error: return NULL; } -// Create an output MPE LUT from agiven profile. Version mismatches are handled here +// Create an output MPE LUT from a given profile. Version mismatches are handled here cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent) { cmsTagTypeSignature OriginalType; @@ -1027,3 +1027,13 @@ cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoT return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize); } + +cmsUInt32Number CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const cmsMLU* mlu = GetInfo(hProfile, Info); + if (mlu == NULL) return 0; + + return cmsMLUgetUTF8(mlu, LanguageCode, CountryCode, Buffer, BufferSize); +} diff --git a/contrib/libs/lcms2/src/cmslut.c b/contrib/libs/lcms2/src/cmslut.c index 77977fc6c9..1ea61a806b 100644 --- a/contrib/libs/lcms2/src/cmslut.c +++ b/contrib/libs/lcms2/src/cmslut.c @@ -475,6 +475,9 @@ cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) if (rv > UINT_MAX / dim) return 0; } + // Again, prevent overflow + if (rv > UINT_MAX / 15) return 0; + return rv; } @@ -814,7 +817,13 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler cmsUInt32Number nInputs, nOutputs; cmsUInt32Number* nSamples; cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + _cmsStageCLutData* clut; + + if (mpe == NULL) return FALSE; + + clut = (_cmsStageCLutData*)mpe->Data; + + if (clut == NULL) return FALSE; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; diff --git a/contrib/libs/lcms2/src/cmsnamed.c b/contrib/libs/lcms2/src/cmsnamed.c index 54d1abf913..f368fe2483 100644 --- a/contrib/libs/lcms2/src/cmsnamed.c +++ b/contrib/libs/lcms2/src/cmsnamed.c @@ -200,17 +200,145 @@ void strFrom16(char str[3], cmsUInt16Number n) str[0] = (char)(n >> 8); str[1] = (char)n; str[2] = (char)0; +} + + +// Convert from UTF8 to wchar, returns len. +static +cmsUInt32Number decodeUTF8(wchar_t* out, const char* in) +{ + cmsUInt32Number codepoint = 0; + cmsUInt32Number size = 0; + + while (*in) + { + cmsUInt8Number ch = (cmsUInt8Number) *in; + + if (ch <= 0x7f) + { + codepoint = ch; + } + else if (ch <= 0xbf) + { + codepoint = (codepoint << 6) | (ch & 0x3f); + } + else if (ch <= 0xdf) + { + codepoint = ch & 0x1f; + } + else if (ch <= 0xef) + { + codepoint = ch & 0x0f; + } + else + { + codepoint = ch & 0x07; + } + + in++; + + if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) + { + if (sizeof(wchar_t) > 2) + { + if (out) *out++ = (wchar_t) codepoint; + size++; + } + else + if (codepoint > 0xffff) + { + if (out) + { + *out++ = (wchar_t)(0xd800 + (codepoint >> 10)); + *out++ = (wchar_t)(0xdc00 + (codepoint & 0x03ff)); + size += 2; + } + } + else + if (codepoint < 0xd800 || codepoint >= 0xe000) + { + if (out) *out++ = (wchar_t) codepoint; + size++; + } + } + } + + return size; +} + +// Convert from wchar_t to UTF8 +static +cmsUInt32Number encodeUTF8(char* out, const wchar_t* in, cmsUInt32Number max_wchars, cmsUInt32Number max_chars) +{ + cmsUInt32Number codepoint = 0; + cmsUInt32Number size = 0; + cmsUInt32Number len_w = 0; + + while (*in && len_w < max_wchars) + { + if (*in >= 0xd800 && *in <= 0xdbff) + codepoint = ((*in - 0xd800) << 10) + 0x10000; + else + { + if (*in >= 0xdc00 && *in <= 0xdfff) + codepoint |= *in - 0xdc00; + else + codepoint = *in; + + if (codepoint <= 0x7f) + { + if (out && (size + 1 < max_chars)) *out++ = (char)codepoint; + size++; + } + + else if (codepoint <= 0x7ff) + { + if (out && (max_chars > 0) && (size + 2 < max_chars)) + { + *out++ = (char)(cmsUInt32Number)(0xc0 | ((codepoint >> 6) & 0x1f)); + *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); + } + size += 2; + } + else if (codepoint <= 0xffff) + { + if (out && (max_chars > 0) && (size + 3 < max_chars)) + { + *out++ = (char)(cmsUInt32Number)(0xe0 | ((codepoint >> 12) & 0x0f)); + *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f)); + *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); + } + size += 3; + } + else + { + if (out && (max_chars > 0) && (size + 4 < max_chars)) + { + *out++ = (char)(cmsUInt32Number)(0xf0 | ((codepoint >> 18) & 0x07)); + *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 12) & 0x3f)); + *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f)); + *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); + } + size += 4; + } + + codepoint = 0; + } + in++; len_w++; + } + + return size; } // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) // In the case the user explicitly sets an empty string, we force a \0 cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) { - cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString); + cmsUInt32Number i, len = (cmsUInt32Number)strlen(ASCIIString); wchar_t* WStr; cmsBool rc; - cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Lang = strTo16(LanguageCode); cmsUInt16Number Cntry = strTo16(CountryCode); if (mlu == NULL) return FALSE; @@ -218,22 +346,56 @@ cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const // len == 0 would prevent operation, so we set a empty string pointing to zero if (len == 0) { - len = 1; + wchar_t empty = 0; + return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry); } - WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t)); + WStr = (wchar_t*)_cmsCalloc(mlu->ContextID, len, sizeof(wchar_t)); if (WStr == NULL) return FALSE; - for (i=0; i < len; i++) - WStr[i] = (wchar_t) ASCIIString[i]; + for (i = 0; i < len; i++) + WStr[i] = (wchar_t)ASCIIString[i]; - rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); + rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); - _cmsFree(mlu ->ContextID, WStr); + _cmsFree(mlu->ContextID, WStr); return rc; } +// Add an UTF8 entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) +// In the case the user explicitly sets an empty string, we force a \0 +cmsBool CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* UTF8String) +{ + cmsUInt32Number UTF8len; + wchar_t* WStr; + cmsBool rc; + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + + if (mlu == NULL) return FALSE; + + if (*UTF8String == '\0') + { + wchar_t empty = 0; + return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry); + } + + // Len excluding terminator 0 + UTF8len = decodeUTF8(NULL, UTF8String); + + // Get space for dest + WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, UTF8len, sizeof(wchar_t)); + if (WStr == NULL) return FALSE; + + decodeUTF8(WStr, UTF8String); + + rc = AddMLUBlock(mlu, UTF8len * sizeof(wchar_t), WStr, Lang, Cntry); + + _cmsFree(mlu ->ContextID, WStr); + return rc; +} + // We don't need any wcs support library static cmsUInt32Number mywcslen(const wchar_t *s) @@ -372,7 +534,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, if (v->StrW + v->Len > mlu->PoolSize) return NULL; - return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); + return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); } @@ -410,10 +572,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, // Precess each character for (i=0; i < ASCIIlen; i++) { - if (Wide[i] == 0) - Buffer[i] = 0; + wchar_t wc = Wide[i]; + + if (wc < 0xff) + Buffer[i] = (char)wc; else - Buffer[i] = (char) Wide[i]; + Buffer[i] = '?'; } // We put a termination "\0" @@ -421,6 +585,46 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, return ASCIIlen + 1; } + +// Obtain a UTF8 representation of the wide string. Setting buffer to NULL returns the len +cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const wchar_t *Wide; + cmsUInt32Number StrLen = 0; + cmsUInt32Number UTF8len; + + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + + // Sanitize + if (mlu == NULL) return 0; + + // Get WideChar + Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); + if (Wide == NULL) return 0; + + UTF8len = encodeUTF8(NULL, Wide, StrLen / sizeof(wchar_t), BufferSize); + + // Maybe we want only to know the len? + if (Buffer == NULL) return UTF8len + 1; // Note the zero at the end + + // No buffer size means no data + if (BufferSize <= 0) return 0; + + // Some clipping may be required + if (BufferSize < UTF8len + 1) + UTF8len = BufferSize - 1; + + // Process it + encodeUTF8(Buffer, Wide, StrLen / sizeof(wchar_t), BufferSize); + + // We put a termination "\0" + Buffer[UTF8len] = 0; + return UTF8len + 1; +} + // Obtain a wide representation of the MLU, on depending on current locale settings cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], @@ -441,12 +645,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, // Maybe we want only to know the len? if (Buffer == NULL) return StrLen + sizeof(wchar_t); - // No buffer size means no data - if (BufferSize <= 0) return 0; + // Invalid buffer size means no data + if (BufferSize < sizeof(wchar_t)) return 0; // Some clipping may be required if (BufferSize < StrLen + sizeof(wchar_t)) - StrLen = BufferSize - + sizeof(wchar_t); + StrLen = BufferSize - sizeof(wchar_t); memmove(Buffer, Wide, StrLen); Buffer[StrLen / sizeof(wchar_t)] = 0; @@ -814,13 +1018,19 @@ void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq) { cmsUInt32Number i; - for (i=0; i < pseq ->n; i++) { - if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); - if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); - if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); + if (pseq == NULL) + return; + + if (pseq ->seq != NULL) { + for (i=0; i < pseq ->n; i++) { + if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); + if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); + if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); + } + + _cmsFree(pseq ->ContextID, pseq ->seq); } - if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq); _cmsFree(pseq -> ContextID, pseq); } diff --git a/contrib/libs/lcms2/src/cmsopt.c b/contrib/libs/lcms2/src/cmsopt.c index b3d831cbd9..4038088b2b 100644 --- a/contrib/libs/lcms2/src/cmsopt.c +++ b/contrib/libs/lcms2/src/cmsopt.c @@ -183,6 +183,7 @@ cmsBool isFloatMatrixIdentity(const cmsMAT3* a) return TRUE; } + // if two adjacent matrices are found, multiply them. static cmsBool _MultiplyMatrix(cmsPipeline* Lut) @@ -1113,14 +1114,17 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte // Store result in curve for (t=0; t < OriginalLut ->InputChannels; t++) - Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); + { + if (Trans[t]->Table16 != NULL) + Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); + } } // Slope-limit the obtained curves for (t = 0; t < OriginalLut ->InputChannels; t++) SlopeLimiting(Trans[t]); - // Check for validity + // Check for validity. lIsLinear is here for debug purposes lIsSuitable = TRUE; lIsLinear = TRUE; for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) { @@ -1724,6 +1728,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1); + if (Matrix1->InputChannels != 3 || Matrix1->OutputChannels != 3) return FALSE; + // Copy the matrix to our result memcpy(&res, Data->Double, sizeof(res)); @@ -1768,7 +1774,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); // In this particular optimization, cache does not help as it takes more time to deal with - // the cache that with the pixel handling + // the cache than with the pixel handling *dwFlags |= cmsFLAGS_NOCACHE; // Setup the optimizarion routines @@ -1924,8 +1930,8 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, // Named color pipelines cannot be optimized for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut); mpe != NULL; - mpe = cmsStageNext(mpe)) { - if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; } // Try to get rid of identities and trivial conversions. diff --git a/contrib/libs/lcms2/src/cmspack.c b/contrib/libs/lcms2/src/cmspack.c index 5a96712a48..c191896c08 100644 --- a/contrib/libs/lcms2/src/cmspack.c +++ b/contrib/libs/lcms2/src/cmspack.c @@ -2952,6 +2952,108 @@ cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info, // -------------------------------------------------------------------------------------------------------- static +cmsUInt8Number* PackBytesFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt8Number* swap1 = (cmsUInt8Number*)output; + cmsFloat64Number v = 0; + cmsUInt8Number vv = 0; + cmsUInt32Number i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * 65535.0; + + if (Reverse) + v = 65535.0 - v; + + vv = FROM_16_TO_8(_cmsQuickSaturateWord(v)); + + if (Planar) + ((cmsUInt8Number*)output)[(i + start) * Stride] = vv; + else + ((cmsUInt8Number*)output)[i + start] = vv; + } + + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt8Number)); + *swap1 = vv; + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt8Number); + else + return output + (nChan + Extra) * sizeof(cmsUInt8Number); +} + +static +cmsUInt8Number* PackWordsFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt16Number* swap1 = (cmsUInt16Number*)output; + cmsFloat64Number v = 0; + cmsUInt16Number vv = 0; + cmsUInt32Number i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * 65535.0; + + if (Reverse) + v = 65535.0 - v; + + vv = _cmsQuickSaturateWord(v); + + if (Planar) + ((cmsUInt16Number*)output)[(i + start) * Stride] = vv; + else + ((cmsUInt16Number*)output)[i + start] = vv; + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt16Number)); + *swap1 = vv; + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + (nChan + Extra) * sizeof(cmsUInt16Number); +} + + +static cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, cmsFloat32Number wOut[], cmsUInt8Number* output, @@ -3114,6 +3216,77 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, } +static +cmsUInt8Number* PackEncodedBytesLabV2FromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsCIELab Lab; + cmsUInt16Number wlab[3]; + + Lab.L = (cmsFloat64Number)(wOut[0] * 100.0); + Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0); + Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0); + + cmsFloat2LabEncoded(wlab, &Lab); + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + output[0] = wlab[0] >> 8; + output[Stride] = wlab[1] >> 8; + output[Stride*2] = wlab[2] >> 8; + + return output + 1; + } + else { + + output[0] = wlab[0] >> 8; + output[1] = wlab[1] >> 8; + output[2] = wlab[2] >> 8; + + return output + (3 + T_EXTRA(Info ->OutputFormat)); + } +} + +static +cmsUInt8Number* PackEncodedWordsLabV2FromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsCIELab Lab; + cmsUInt16Number wlab[3]; + + Lab.L = (cmsFloat64Number)(wOut[0] * 100.0); + Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0); + Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0); + + cmsFloat2LabEncodedV2(wlab, &Lab); + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + ((cmsUInt16Number*) output)[0] = wlab[0]; + ((cmsUInt16Number*) output)[Stride] = wlab[1]; + ((cmsUInt16Number*) output)[Stride*2] = wlab[2]; + + return output + sizeof(cmsUInt16Number); + } + else { + + ((cmsUInt16Number*) output)[0] = wlab[0]; + ((cmsUInt16Number*) output)[1] = wlab[1]; + ((cmsUInt16Number*) output)[2] = wlab[2]; + + return output + (3 + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsUInt16Number); + } +} + + // From 0..1 range to 0..MAX_ENCODEABLE_XYZ static cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, @@ -3647,10 +3820,20 @@ static const cmsFormattersFloat OutputFormattersFloat[] = { { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat}, + { TYPE_LabV2_8, ANYPLANAR|ANYEXTRA, PackEncodedBytesLabV2FromFloat}, + { TYPE_LabV2_16, ANYPLANAR|ANYEXTRA, PackEncodedWordsLabV2FromFloat}, + { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR| ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackFloatsFromFloat }, { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR| ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackDoublesFromFloat }, + + { BYTES_SH(2), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackWordsFromFloat }, + + { BYTES_SH(1), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackBytesFromFloat }, + #ifndef CMS_NO_HALF_SUPPORT { FLOAT_SH(1)|BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat }, @@ -3861,7 +4044,7 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace); - cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); + cmsInt32Number nOutputChans = cmsChannelsOfColorSpace(ColorSpace); cmsUInt32Number Float = lIsFloat ? 1U : 0; // Unsupported color space? diff --git a/contrib/libs/lcms2/src/cmsplugin.c b/contrib/libs/lcms2/src/cmsplugin.c index 3876506dac..e278832813 100644 --- a/contrib/libs/lcms2/src/cmsplugin.c +++ b/contrib/libs/lcms2/src/cmsplugin.c @@ -364,12 +364,7 @@ cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) // from Fixed point 8.8 to double cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) { - cmsUInt8Number msb, lsb; - - lsb = (cmsUInt8Number) (fixed8 & 0xff); - msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff); - - return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0)); + return fixed8 / 256.0; } cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) @@ -381,19 +376,7 @@ cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) // from Fixed point 15.16 to double cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) { - cmsFloat64Number floater, sign, mid; - int Whole, FracPart; - - sign = (fix32 < 0 ? -1 : 1); - fix32 = abs(fix32); - - Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff; - FracPart = (cmsUInt16Number)(fix32 & 0xffff); - - mid = (cmsFloat64Number) FracPart / 65536.0; - floater = (cmsFloat64Number) Whole + mid; - - return sign * floater; + return fix32 / 65536.0; } // from double to Fixed point 15.16 diff --git a/contrib/libs/lcms2/src/cmsps2.c b/contrib/libs/lcms2/src/cmsps2.c index 9aeea36d4f..eea1629d35 100644 --- a/contrib/libs/lcms2/src/cmsps2.c +++ b/contrib/libs/lcms2/src/cmsps2.c @@ -431,48 +431,46 @@ void EmitLab2XYZ(cmsIOHANDLER* m) _cmsIOPrintf(m, "]\n"); } -static -void EmitSafeGuardBegin(cmsIOHANDLER* m, const char* name) -{ - _cmsIOPrintf(m, "%%LCMS2: Save previous definition of %s on the operand stack\n", name); - _cmsIOPrintf(m, "currentdict /%s known { /%s load } { null } ifelse\n", name, name); -} -static -void EmitSafeGuardEnd(cmsIOHANDLER* m, const char* name, int depth) -{ - _cmsIOPrintf(m, "%%LCMS2: Restore previous definition of %s\n", name); - if (depth > 1) { - // cycle topmost items on the stack to bring the previous definition to the front - _cmsIOPrintf(m, "%d -1 roll ", depth); - } - _cmsIOPrintf(m, "dup null eq { pop currentdict /%s undef } { /%s exch def } ifelse\n", name, name); -} // Outputs a table of words. It does use 16 bits static -void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) +void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) { cmsUInt32Number i; cmsFloat64Number gamma; - if (Table == NULL) return; // Error + /** + * On error, empty tables or lienar assume gamma 1.0 + */ + if (Table == NULL || + Table->nEntries <= 0 || + cmsIsToneCurveLinear(Table)) { - if (Table ->nEntries <= 0) return; // Empty table + _cmsIOPrintf(m, "{ 1 } bind "); + return; + } - // Suppress whole if identity - if (cmsIsToneCurveLinear(Table)) return; // Check if is really an exponential. If so, emit "exp" gamma = cmsEstimateGamma(Table, 0.001); if (gamma > 0) { - _cmsIOPrintf(m, "/%s { %g exp } bind def\n", name, gamma); + _cmsIOPrintf(m, "{ %g exp } bind ", gamma); return; } - EmitSafeGuardBegin(m, "lcms2gammatable"); - _cmsIOPrintf(m, "/lcms2gammatable ["); + _cmsIOPrintf(m, "{ "); + + // Bounds check + EmitRangeCheck(m); + + // Emit intepolation code + + // PostScript code Stack + // =============== ======================== + // v + _cmsIOPrintf(m, " ["); for (i=0; i < Table->nEntries; i++) { if (i % 10 == 0) @@ -480,20 +478,8 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) _cmsIOPrintf(m, "%d ", Table->Table16[i]); } - _cmsIOPrintf(m, "] def\n"); + _cmsIOPrintf(m, "] "); // v tab - - // Emit interpolation code - - // PostScript code Stack - // =============== ======================== - // v - _cmsIOPrintf(m, "/%s {\n ", name); - - // Bounds check - EmitRangeCheck(m); - - _cmsIOPrintf(m, "\n //lcms2gammatable "); // v tab _cmsIOPrintf(m, "dup "); // v tab tab _cmsIOPrintf(m, "length 1 sub "); // v tab dom _cmsIOPrintf(m, "3 -1 roll "); // tab dom v @@ -520,9 +506,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) _cmsIOPrintf(m, "add "); // y _cmsIOPrintf(m, "65535 div\n"); // result - _cmsIOPrintf(m, "} bind def\n"); - - EmitSafeGuardEnd(m, "lcms2gammatable", 1); + _cmsIOPrintf(m, " } bind "); } @@ -539,10 +523,10 @@ cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Numb // Does write a set of gamma curves static -void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix) +void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[]) { cmsUInt32Number i; - static char buffer[2048]; + for( i=0; i < n; i++ ) { @@ -550,12 +534,10 @@ void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const cha if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) { - _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1); + _cmsIOPrintf(m, "dup "); } else { - snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i); - buffer[sizeof(buffer)-1] = '\0'; - Emit1Gamma(m, g[i], buffer); + Emit1Gamma(m, g[i]); } } @@ -679,18 +661,21 @@ void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, sc.FixWhite = FixWhite; sc.ColorSpace = ColorSpace; - _cmsIOPrintf(m, "["); + if (sc.Pipeline != NULL && sc.Pipeline->Params != NULL) { + + _cmsIOPrintf(m, "["); - for (i=0; i < sc.Pipeline->Params->nInputs; i++) - _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); + for (i = 0; i < sc.Pipeline->Params->nInputs; i++) + _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); - _cmsIOPrintf(m, " [\n"); + _cmsIOPrintf(m, " [\n"); - cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT); + cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*)&sc, SAMPLER_INSPECT); - _cmsIOPrintf(m, PostMin); - _cmsIOPrintf(m, PostMaj); - _cmsIOPrintf(m, "] "); + _cmsIOPrintf(m, PostMin); + _cmsIOPrintf(m, PostMaj); + _cmsIOPrintf(m, "] "); + } } @@ -704,11 +689,11 @@ int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint) _cmsIOPrintf(m, "[ /CIEBasedA\n"); _cmsIOPrintf(m, " <<\n"); - EmitSafeGuardBegin(m, "lcms2gammaproc"); - Emit1Gamma(m, Curve, "lcms2gammaproc"); + _cmsIOPrintf(m, "/DecodeA "); + + Emit1Gamma(m, Curve); - _cmsIOPrintf(m, "/DecodeA /lcms2gammaproc load\n"); - EmitSafeGuardEnd(m, "lcms2gammaproc", 3); + _cmsIOPrintf(m, " \n"); _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n"); _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); @@ -732,19 +717,11 @@ int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** Cu _cmsIOPrintf(m, "[ /CIEBasedABC\n"); _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "/DecodeABC [ "); + + EmitNGamma(m, 3, CurveSet); - EmitSafeGuardBegin(m, "lcms2gammaproc0"); - EmitSafeGuardBegin(m, "lcms2gammaproc1"); - EmitSafeGuardBegin(m, "lcms2gammaproc2"); - EmitNGamma(m, 3, CurveSet, "lcms2gammaproc"); - _cmsIOPrintf(m, "/DecodeABC [\n"); - _cmsIOPrintf(m, " /lcms2gammaproc0 load\n"); - _cmsIOPrintf(m, " /lcms2gammaproc1 load\n"); - _cmsIOPrintf(m, " /lcms2gammaproc2 load\n"); _cmsIOPrintf(m, "]\n"); - EmitSafeGuardEnd(m, "lcms2gammaproc2", 3); - EmitSafeGuardEnd(m, "lcms2gammaproc1", 3); - EmitSafeGuardEnd(m, "lcms2gammaproc0", 3); _cmsIOPrintf(m, "/MatrixABC [ " ); @@ -776,11 +753,9 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte { const char* PreMaj; const char* PostMaj; - const char* PreMin, * PostMin; + const char* PreMin, *PostMin; cmsStage* mpe; - int i, numchans; - static char buffer[2048]; - + mpe = Pipeline->Elements; switch (cmsStageInputChannels(mpe)) { @@ -808,34 +783,18 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte if (cmsStageType(mpe) == cmsSigCurveSetElemType) { - numchans = (int) cmsStageOutputChannels(mpe); - for (i = 0; i < numchans; ++i) { - snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i); - buffer[sizeof(buffer) - 1] = '\0'; - EmitSafeGuardBegin(m, buffer); - } - EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc"); - _cmsIOPrintf(m, "/DecodeDEF [\n"); - for (i = 0; i < numchans; ++i) { - snprintf(buffer, sizeof(buffer), " /lcms2gammaproc%d load\n", i); - buffer[sizeof(buffer) - 1] = '\0'; - _cmsIOPrintf(m, buffer); - } + _cmsIOPrintf(m, "/DecodeDEF [ "); + EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe)); _cmsIOPrintf(m, "]\n"); - for (i = numchans - 1; i >= 0; --i) { - snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i); - buffer[sizeof(buffer) - 1] = '\0'; - EmitSafeGuardEnd(m, buffer, 3); - } - mpe = mpe->Next; + mpe = mpe ->Next; } if (cmsStageType(mpe) == cmsSigCLutElemType) { - _cmsIOPrintf(m, "/Table "); - WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0); - _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, "/Table "); + WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0); + _cmsIOPrintf(m, "]\n"); } EmitLab2XYZ(m); @@ -995,9 +954,9 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr for (j = 0; j < 3; j++) Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ; - rc = EmitCIEBasedABC(m, (cmsFloat64Number *)&Mat, - _cmsStageGetPtrToCurveSet(Shaper), - &BlackPointAdaptedToD50); + rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat, + _cmsStageGetPtrToCurveSet(Shaper), + &BlackPointAdaptedToD50); } else { @@ -1024,10 +983,15 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); + cmsCloseProfile(hLab); + if (xform == NULL) return 0; NamedColorList = cmsGetNamedColorList(xform); - if (NamedColorList == NULL) return 0; + if (NamedColorList == NULL) { + cmsDeleteTransform(xform); + return 0; + } _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA"); @@ -1036,7 +1000,6 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number nColors = cmsNamedColorCount(NamedColorList); - for (i=0; i < nColors; i++) { cmsUInt16Number In[1]; @@ -1051,12 +1014,9 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); } - - _cmsIOPrintf(m, ">>\n"); cmsDeleteTransform(xform); - cmsCloseProfile(hLab); return 1; } @@ -1310,7 +1270,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent cmsUInt32Number InFrm = TYPE_Lab_16; cmsUInt32Number RelativeEncodingIntent; cmsColorSpaceSignature ColorSpace; - + cmsStage* first; hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); if (hLab == NULL) return 0; @@ -1336,8 +1296,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent OutputFormat, RelativeEncodingIntent, 0); cmsCloseProfile(hLab); - if (xform == NULL) { - + if (xform == NULL) { cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); return 0; } @@ -1345,10 +1304,12 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent // Get a copy of the internal devicelink v = (_cmsTRANSFORM*) xform; DeviceLink = cmsPipelineDup(v ->Lut); - if (DeviceLink == NULL) return 0; - + if (DeviceLink == NULL) { + cmsDeleteTransform(xform); + return 0; + } - // We need a CLUT + // We need a CLUT dwFlags |= cmsFLAGS_FORCE_CLUT; _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); @@ -1375,8 +1336,10 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent _cmsIOPrintf(m, "/RenderTable "); - - WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); + first = cmsPipelineGetPtrToFirstStage(DeviceLink); + if (first != NULL) { + WriteCLUT(m, first, "<", ">\n", "", "", lFixWhite, ColorSpace); + } _cmsIOPrintf(m, " %d {} bind ", nChannels); @@ -1385,7 +1348,6 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent _cmsIOPrintf(m, "]\n"); - EmitIntent(m, Intent); _cmsIOPrintf(m, ">>\n"); @@ -1448,7 +1410,10 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number NamedColorList = cmsGetNamedColorList(xform); - if (NamedColorList == NULL) return 0; + if (NamedColorList == NULL) { + cmsDeleteTransform(xform); + return 0; + } _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); diff --git a/contrib/libs/lcms2/src/cmssamp.c b/contrib/libs/lcms2/src/cmssamp.c index 4888f1ea88..0cee16a9ec 100644 --- a/contrib/libs/lcms2/src/cmssamp.c +++ b/contrib/libs/lcms2/src/cmssamp.c @@ -123,7 +123,7 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Convert black to Lab cmsDoTransform(xform, Black, &Lab, 1); - // Force it to be neutral, check for inconsistences + // Force it to be neutral, check for inconsistencies Lab.a = Lab.b = 0; if (Lab.L > 50 || Lab.L < 0) Lab.L = 0; diff --git a/contrib/libs/lcms2/src/cmstypes.c b/contrib/libs/lcms2/src/cmstypes.c index ec1909f8d3..8eabe1f079 100644 --- a/contrib/libs/lcms2/src/cmstypes.c +++ b/contrib/libs/lcms2/src/cmstypes.c @@ -93,7 +93,7 @@ cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient return TRUE; } -// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additions // made by plug-ins and then the built-in defaults. static cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) @@ -925,6 +925,7 @@ static void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { char* Text = NULL; + wchar_t* UnicodeString = NULL; cmsMLU* mlu = NULL; cmsUInt32Number AsciiCount; cmsUInt32Number i, UnicodeCode, UnicodeCount; @@ -944,7 +945,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND if (SizeOfTag < AsciiCount) return NULL; // All seems Ok, allocate the container - mlu = cmsMLUalloc(self ->ContextID, 1); + mlu = cmsMLUalloc(self ->ContextID, 2); if (mlu == NULL) return NULL; // As many memory as size of tag @@ -969,15 +970,30 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done; SizeOfTag -= 2* sizeof(cmsUInt32Number); - if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; + if (UnicodeCount == 0 || SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; + + UnicodeString = (wchar_t*)_cmsMallocZero(self->ContextID, (UnicodeCount + 1) * sizeof(wchar_t)); + if (UnicodeString == NULL) goto Done; + + if (!_cmsReadWCharArray(io, UnicodeCount, UnicodeString)) { + _cmsFree(self->ContextID, (void*)UnicodeString); + goto Done; + } + + UnicodeString[UnicodeCount] = 0; - for (i=0; i < UnicodeCount; i++) { - if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done; + if (!cmsMLUsetWide(mlu, cmsV2Unicode, cmsV2Unicode, UnicodeString)) { + _cmsFree(self->ContextID, (void*)UnicodeString); + goto Done; } + + _cmsFree(self->ContextID, (void*)UnicodeString); + UnicodeString = NULL; + SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number); // Skip ScriptCode code if present. Some buggy profiles does have less - // data that stricttly required. We need to skip it as this type may come + // data that strictly required. We need to skip it as this type may come // embedded in other types. if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) { @@ -997,6 +1013,7 @@ Done: return mlu; Error: + if (UnicodeString) _cmsFree(self->ContextID, (void*)UnicodeString); if (Text) _cmsFree(self ->ContextID, (void*) Text); if (mlu) cmsMLUfree(mlu); return NULL; @@ -1049,7 +1066,7 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO // Get both representations. cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char)); - cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t)); + cmsMLUgetWide(mlu, cmsV2Unicode, cmsV2Unicode, Wide, len * sizeof(wchar_t)); } // Tell the real text len including the null terminator and padding @@ -1548,8 +1565,6 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU if (SizeOfTag == 0) { Block = NULL; - NumOfWchar = 0; - } else { @@ -1911,7 +1926,7 @@ Error: // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin. static -cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsUInt32Number j, nTabSize, i; cmsUInt8Number val; @@ -1924,6 +1939,12 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // Disassemble the LUT into components. mpe = NewLUT -> Elements; + + if (mpe == NULL) { // Should never be empty. Corrupted? + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "empty LUT8 is not supported"); + return FALSE; + } + if (mpe ->Type == cmsSigMatrixElemType) { if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE; @@ -2665,8 +2686,8 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // If this is a table-based curve, use curve type even on V4 CurrentType = Type; - if ((Curves[i] ->nSegments == 0)|| - ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) ) + if ((Curves[i] ->nSegments == 0) || // 16 bits tabulated + ((Curves[i]->nSegments == 3) && (Curves[i] ->Segments[1].Type == 0)) ) // Floating-point tabulated CurrentType = cmsSigCurveType; else if (Curves[i] ->Segments[0].Type < 0) @@ -4430,8 +4451,8 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - if (InputChans == 0) goto Error; - if (OutputChans == 0) goto Error; + if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) goto Error; + if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) goto Error; if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) goto Error; @@ -4452,7 +4473,7 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, clut = (_cmsStageCLutData*) mpe ->Data; for (i=0; i < clut ->nEntries; i++) { - if (!_cmsReadFloat32Number(io, &clut->Tab.TFloat[i])) goto Error; + if (!_cmsReadFloat32Number(io, &clut->Tab.TFloat[i])) goto Error; } *nItems = 1; @@ -5221,11 +5242,13 @@ cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _c } Before = io ->Tell(io); - e ->Offsets[i] = Before - BaseOffset; + if (e->Offsets != NULL) + e ->Offsets[i] = Before - BaseOffset; if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE; - e ->Sizes[i] = io ->Tell(io) - Before; + if (e->Sizes != NULL) + e ->Sizes[i] = io ->Tell(io) - Before; return TRUE; } @@ -5470,6 +5493,216 @@ void Type_VideoSignal_Free(struct _cms_typehandler_struct* self, void* Ptr) _cmsFree(self->ContextID, Ptr); } + +// ******************************************************************************** +// Microsoft's MHC2 Type support +// ******************************************************************************** + +static +void SetIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4]) +{ + XYZ2XYZmatrix[0][0] = 1.0; XYZ2XYZmatrix[0][1] = 0.0; XYZ2XYZmatrix[0][2] = 0.0; XYZ2XYZmatrix[0][3] = 0.0; + XYZ2XYZmatrix[1][0] = 0.0; XYZ2XYZmatrix[1][1] = 1.0; XYZ2XYZmatrix[1][2] = 0.0; XYZ2XYZmatrix[1][3] = 0.0; + XYZ2XYZmatrix[2][0] = 0.0; XYZ2XYZmatrix[2][1] = 0.0; XYZ2XYZmatrix[2][2] = 1.0; XYZ2XYZmatrix[2][3] = 0.0; +} + +static +cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b) +{ + return fabs(b - a) < (1.0 / 65535.0); +} + +cmsBool IsIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4]) +{ + cmsFloat64Number Identity[3][4]; + int i, j; + + SetIdentity(Identity); + + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + if (!CloseEnough(XYZ2XYZmatrix[i][j], Identity[i][j])) return FALSE; + + return TRUE; +} + +static +void Type_MHC2_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr; + + if (mhc2->RedCurve != NULL) _cmsFree(self->ContextID, mhc2->RedCurve); + if (mhc2->GreenCurve != NULL) _cmsFree(self->ContextID, mhc2->GreenCurve); + if (mhc2->BlueCurve != NULL) _cmsFree(self->ContextID, mhc2->BlueCurve); + + _cmsFree(self->ContextID, Ptr); +} + +void* Type_MHC2_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + cmsMHC2Type* mhc2 = _cmsDupMem(self->ContextID, Ptr, sizeof(cmsMHC2Type)); + + mhc2->RedCurve = _cmsDupMem(self->ContextID, mhc2->RedCurve, mhc2->CurveEntries*sizeof(cmsFloat64Number)); + mhc2->GreenCurve = _cmsDupMem(self->ContextID, mhc2->GreenCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number)); + mhc2->BlueCurve = _cmsDupMem(self->ContextID, mhc2->BlueCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number)); + + if (mhc2->RedCurve == NULL || + mhc2->GreenCurve == NULL || + mhc2->BlueCurve == NULL) { + + Type_MHC2_Free(self, mhc2); + return NULL; + } + + return mhc2; + + cmsUNUSED_PARAMETER(n); +} + + +static +cmsBool WriteDoubles(cmsIOHANDLER* io, cmsUInt32Number n, cmsFloat64Number* Values) +{ + cmsUInt32Number i; + + for (i = 0; i < n; i++) { + + if (!_cmsWrite15Fixed16Number(io, *Values++)) return FALSE; + } + + return TRUE; +} + +static +cmsBool Type_MHC2_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr; + cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase); + cmsUInt32Number TablesOffsetPos; + cmsUInt32Number MatrixOffset; + cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable; + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, mhc2->CurveEntries)) return FALSE; + + if (!_cmsWrite15Fixed16Number(io, mhc2->MinLuminance)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, mhc2->PeakLuminance)) return FALSE; + + TablesOffsetPos = io->Tell(io); + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Matrix + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Curve R + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Curve G + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Curve B + + + if (IsIdentity(mhc2->XYZ2XYZmatrix)) + { + MatrixOffset = 0; + } + else + { + MatrixOffset = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, 3 * 4, &mhc2->XYZ2XYZmatrix[0][0])) return FALSE; + } + + OffsetRedTable = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->RedCurve)) return FALSE; + OffsetGreenTable = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->GreenCurve)) return FALSE; + OffsetBlueTable = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->BlueCurve)) return FALSE; + + if (!io->Seek(io, TablesOffsetPos)) return FALSE; + + if (!_cmsWriteUInt32Number(io, MatrixOffset)) return FALSE; + if (!_cmsWriteUInt32Number(io, OffsetRedTable)) return FALSE; + if (!_cmsWriteUInt32Number(io, OffsetGreenTable)) return FALSE; + if (!_cmsWriteUInt32Number(io, OffsetBlueTable)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(self); + cmsUNUSED_PARAMETER(nItems); +} + + +static +cmsBool ReadDoublesAt(cmsIOHANDLER* io, cmsUInt32Number At, cmsUInt32Number n, cmsFloat64Number* Values) +{ + cmsUInt32Number CurrentPos = io->Tell(io); + cmsUInt32Number i; + + if (!io->Seek(io, At)) return FALSE; + + for (i = 0; i < n; i++) { + + if (!_cmsRead15Fixed16Number(io, Values++)) return FALSE; + } + + if (!io->Seek(io, CurrentPos)) return FALSE; + + return TRUE; +} + +static +void* Type_MHC2_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsMHC2Type* mhc2 = NULL; + + cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase); + cmsUInt32Number MatrixOffset; + cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable; + + if (!_cmsReadUInt32Number(io, NULL)) return NULL; + + mhc2 = (cmsMHC2Type*)_cmsCalloc(self->ContextID, 1, sizeof(cmsMHC2Type)); + if (mhc2 == NULL) return NULL; + + if (!_cmsReadUInt32Number(io, &mhc2->CurveEntries)) goto Error; + + if (mhc2->CurveEntries > 4096) goto Error; + + mhc2->RedCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number)); + mhc2->GreenCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number)); + mhc2->BlueCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number)); + + if (mhc2->RedCurve == NULL || + mhc2->GreenCurve == NULL || + mhc2->BlueCurve == NULL) goto Error; + + if (!_cmsRead15Fixed16Number(io, &mhc2->MinLuminance)) goto Error; + if (!_cmsRead15Fixed16Number(io, &mhc2->PeakLuminance)) goto Error; + + if (!_cmsReadUInt32Number(io, &MatrixOffset)) goto Error; + if (!_cmsReadUInt32Number(io, &OffsetRedTable)) goto Error; + if (!_cmsReadUInt32Number(io, &OffsetGreenTable)) goto Error; + if (!_cmsReadUInt32Number(io, &OffsetBlueTable)) goto Error; + + if (MatrixOffset == 0) + SetIdentity(mhc2->XYZ2XYZmatrix); + else + { + if (!ReadDoublesAt(io, BaseOffset + MatrixOffset, 3*4, &mhc2->XYZ2XYZmatrix[0][0])) goto Error; + } + + if (!ReadDoublesAt(io, BaseOffset + OffsetRedTable, mhc2->CurveEntries, mhc2->RedCurve)) goto Error; + if (!ReadDoublesAt(io, BaseOffset + OffsetGreenTable, mhc2->CurveEntries, mhc2->GreenCurve)) goto Error; + if (!ReadDoublesAt(io, BaseOffset + OffsetBlueTable, mhc2->CurveEntries, mhc2->BlueCurve)) goto Error; + + // Success + *nItems = 1; + return mhc2; + +Error: + Type_MHC2_Free(self, mhc2); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + + // ******************************************************************************** // Type support main routines // ******************************************************************************** @@ -5509,7 +5742,8 @@ static const _cmsTagTypeLinkedList SupportedTagTypes[] = { {TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] }, {TYPE_HANDLER(cmsSigDictType, Dictionary), (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] }, {TYPE_HANDLER(cmsSigcicpType, VideoSignal), (_cmsTagTypeLinkedList*) &SupportedTagTypes[31] }, -{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL } +{TYPE_HANDLER(cmsSigVcgtType, vcgt), (_cmsTagTypeLinkedList*) &SupportedTagTypes[32] }, +{TYPE_HANDLER(cmsSigMHC2Type, MHC2), NULL } }; @@ -5705,7 +5939,8 @@ static _cmsTagLinkedList SupportedTags[] = { { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]}, { cmsSigcicpTag, { 1, 1, { cmsSigcicpType}, NULL }, &SupportedTags[64]}, - { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL} + { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, &SupportedTags[65]}, + { cmsSigMHC2Tag, { 1, 1, { cmsSigMHC2Type }, NULL}, NULL} }; diff --git a/contrib/libs/lcms2/src/cmsvirt.c b/contrib/libs/lcms2/src/cmsvirt.c index 951a8ee29d..3d662b2cc6 100644 --- a/contrib/libs/lcms2/src/cmsvirt.c +++ b/contrib/libs/lcms2/src/cmsvirt.c @@ -406,10 +406,9 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, if (Limit < 0.0 || Limit > 400) { - cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); - if (Limit < 0) Limit = 0; + cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 1..400"); + if (Limit < 1) Limit = 1; if (Limit > 400) Limit = 400; - } hICC = cmsCreateProfilePlaceholder(ContextID); @@ -672,6 +671,127 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) return cmsCreate_sRGBProfileTHR(NULL); } +/** +* Oklab colorspace profile (experimental) +* +* This virtual profile cannot be saved as an ICC file +*/ +cmsHPROFILE cmsCreate_OkLabProfile(cmsContext ctx) +{ + cmsStage* XYZPCS = _cmsStageNormalizeFromXyzFloat(ctx); + cmsStage* PCSXYZ = _cmsStageNormalizeToXyzFloat(ctx); + + const double M_D65_D50[] = + { + 1.047886, 0.022919, -0.050216, + 0.029582, 0.990484, -0.017079, + -0.009252, 0.015073, 0.751678 + }; + + const double M_D50_D65[] = + { + 0.955512609517083, -0.023073214184645, 0.063308961782107, + -0.028324949364887, 1.009942432477107, 0.021054814890112, + 0.012328875695483, -0.020535835374141, 1.330713916450354 + }; + + cmsStage* D65toD50 = cmsStageAllocMatrix(ctx, 3, 3, M_D65_D50, NULL); + cmsStage* D50toD65 = cmsStageAllocMatrix(ctx, 3, 3, M_D50_D65, NULL); + + const double M_D65_LMS[] = + { + 0.8189330101, 0.3618667424, -0.1288597137, + 0.0329845436, 0.9293118715, 0.0361456387, + 0.0482003018, 0.2643662691, 0.6338517070 + }; + + const double M_LMS_D65[] = + { + 1.227013851103521, -0.557799980651822, 0.281256148966468, + -0.040580178423281, 1.112256869616830, -0.071676678665601, + -0.076381284505707, -0.421481978418013, 1.586163220440795 + }; + + cmsStage* D65toLMS = cmsStageAllocMatrix(ctx, 3, 3, M_D65_LMS, NULL); + cmsStage* LMStoD65 = cmsStageAllocMatrix(ctx, 3, 3, M_LMS_D65, NULL); + + cmsToneCurve* CubeRoot = cmsBuildGamma(ctx, 1.0 / 3.0); + cmsToneCurve* Cube = cmsBuildGamma(ctx, 3.0); + + cmsToneCurve* Roots[3] = { CubeRoot, CubeRoot, CubeRoot }; + cmsToneCurve* Cubes[3] = { Cube, Cube, Cube }; + + cmsStage* NonLinearityFw = cmsStageAllocToneCurves(ctx, 3, Roots); + cmsStage* NonLinearityRv = cmsStageAllocToneCurves(ctx, 3, Cubes); + + const double M_LMSprime_OkLab[] = + { + 0.2104542553, 0.7936177850, -0.0040720468, + 1.9779984951, -2.4285922050, 0.4505937099, + 0.0259040371, 0.7827717662, -0.8086757660 + }; + + const double M_OkLab_LMSprime[] = + { + 0.999999998450520, 0.396337792173768, 0.215803758060759, + 1.000000008881761, -0.105561342323656, -0.063854174771706, + 1.000000054672411, -0.089484182094966, -1.291485537864092 + }; + + cmsStage* LMSprime_OkLab = cmsStageAllocMatrix(ctx, 3, 3, M_LMSprime_OkLab, NULL); + cmsStage* OkLab_LMSprime = cmsStageAllocMatrix(ctx, 3, 3, M_OkLab_LMSprime, NULL); + + cmsPipeline* AToB = cmsPipelineAlloc(ctx, 3, 3); + cmsPipeline* BToA = cmsPipelineAlloc(ctx, 3, 3); + + cmsHPROFILE hProfile = cmsCreateProfilePlaceholder(ctx); + + cmsSetProfileVersion(hProfile, 4.4); + + cmsSetDeviceClass(hProfile, cmsSigColorSpaceClass); + cmsSetColorSpace(hProfile, cmsSig3colorData); + cmsSetPCS(hProfile, cmsSigXYZData); + + cmsSetHeaderRenderingIntent(hProfile, INTENT_RELATIVE_COLORIMETRIC); + + /** + * Conversion PCS (XYZ/D50) to OkLab + */ + if (!cmsPipelineInsertStage(BToA, cmsAT_END, PCSXYZ)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, D50toD65)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, D65toLMS)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, NonLinearityFw)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, LMSprime_OkLab)) goto error; + + if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA)) goto error; + + if (!cmsPipelineInsertStage(AToB, cmsAT_END, OkLab_LMSprime)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, NonLinearityRv)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, LMStoD65)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, D65toD50)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, XYZPCS)) goto error; + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB)) goto error; + + cmsPipelineFree(BToA); + cmsPipelineFree(AToB); + + cmsFreeToneCurve(CubeRoot); + cmsFreeToneCurve(Cube); + + return hProfile; + +error: + cmsPipelineFree(BToA); + cmsPipelineFree(AToB); + + cmsFreeToneCurve(CubeRoot); + cmsFreeToneCurve(Cube); + cmsCloseProfile(hProfile); + + return NULL; + +} typedef struct { @@ -1031,7 +1151,7 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { - if (n > Tab ->nTypes) return FALSE; + if (n >= Tab ->nTypes) return FALSE; if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; } @@ -1062,9 +1182,9 @@ const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTa cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags) { cmsHPROFILE hProfile = NULL; - cmsUInt32Number FrmIn, FrmOut; - cmsInt32Number ChansIn, ChansOut; - int ColorSpaceBitsIn, ColorSpaceBitsOut; + cmsUInt32Number FrmIn, FrmOut; + cmsInt32Number ChansIn, ChansOut; + int ColorSpaceBitsIn, ColorSpaceBitsOut; _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; cmsPipeline* LUT = NULL; cmsStage* mpe; @@ -1075,6 +1195,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat _cmsAssert(hTransform != NULL); + // Check if the pipeline holding is valid + if (xform -> Lut == NULL) return NULL; + // Get the first mpe to check for named color mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); diff --git a/contrib/libs/lcms2/src/cmsxform.c b/contrib/libs/lcms2/src/cmsxform.c index c70b7cbce1..8fe6b6b974 100644 --- a/contrib/libs/lcms2/src/cmsxform.c +++ b/contrib/libs/lcms2/src/cmsxform.c @@ -914,7 +914,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, } // Check whatever this is a true floating point transform - if (_cmsFormatterIsFloat(*OutputFormat)) { + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) { // Get formatter function always return a valid union, but the contents of this union may be NULL. p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; @@ -989,6 +989,19 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, } } + /** + * Check consistency for alpha channel copy + */ + if (*dwFlags & cmsFLAGS_COPY_ALPHA) + { + if (T_EXTRA(*InputFormat) != T_EXTRA(*OutputFormat)) + { + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Mismatched alpha channels"); + cmsDeleteTransform(p); + return NULL; + } + } + p ->InputFormat = *InputFormat; p ->OutputFormat = *OutputFormat; p ->dwOriginalFlags = *dwFlags; diff --git a/contrib/libs/lcms2/src/lcms2_internal.h b/contrib/libs/lcms2/src/lcms2_internal.h index 1fc99fbe7f..8e78a71e6e 100644 --- a/contrib/libs/lcms2/src/lcms2_internal.h +++ b/contrib/libs/lcms2/src/lcms2_internal.h @@ -260,6 +260,7 @@ typedef CRITICAL_SECTION _cmsMutex; #ifdef _MSC_VER # if (_MSC_VER >= 1800) # pragma warning(disable : 26135) +# pragma warning(disable : 4127) # endif #endif @@ -517,7 +518,7 @@ struct _cmsContext_struct { struct _cmsContext_struct* Next; // Points to next context in the new style _cmsSubAllocator* MemPool; // The memory pool that stores context data - void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. + void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is held in the suballocator. // If NULL, then it reverts to global Context0 _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overridden @@ -811,6 +812,9 @@ typedef struct _cms_iccprofile_struct { // Creation time struct tm Created; + // Color management module identification + cmsUInt32Number CMM; + // Only most important items found in ICC profiles cmsUInt32Number Version; cmsProfileClassSignature DeviceClass; @@ -818,6 +822,7 @@ typedef struct _cms_iccprofile_struct { cmsColorSpaceSignature PCS; cmsUInt32Number RenderingIntent; + cmsPlatformSignature platform; cmsUInt32Number flags; cmsUInt32Number manufacturer, model; cmsUInt64Number attributes; |