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/cmscgats.c | |
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/cmscgats.c')
-rw-r--r-- | contrib/libs/lcms2/src/cmscgats.c | 499 |
1 files changed, 395 insertions, 104 deletions
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); +} |