13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2017 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
178
179 if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
180 Array[i] = (wchar_t) tmp;
181 }
182 else {
183 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
184 }
185
186 }
187 return TRUE;
188 }
189
190 // To deal with position tables
191 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
192 cmsIOHANDLER* io,
193 void* Cargo,
194 cmsUInt32Number n,
195 cmsUInt32Number SizeOfTag);
196
197 // Helper function to deal with position tables as described in ICC spec 4.3
198 // A table of n elements is readed, where first comes n records containing offsets and sizes and
199 // then a block containing the data itself. This allows to reuse same data in more than one entry
200 static
201 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
202 cmsIOHANDLER* io,
203 cmsUInt32Number Count,
204 cmsUInt32Number BaseOffset,
205 void *Cargo,
206 PositionTableEntryFn ElementFn)
207 {
208 cmsUInt32Number i;
209 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
210 cmsUInt32Number currentPosition;
211
212 currentPosition = io->Tell(io);
213
214 // Verify there is enough space left to read at least two cmsUInt32Number items for Count items.
215 if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count)
216 return FALSE;
217
218 // Let's take the offsets to each element
986
987
988 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
989 static
990 cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
991 {
992 cmsMLU* mlu = (cmsMLU*) Ptr;
993 char *Text = NULL;
994 wchar_t *Wide = NULL;
995 cmsUInt32Number len, len_text, len_tag_requirement, len_aligned;
996 cmsBool rc = FALSE;
997 char Filler[68];
998
999 // Used below for writing zeroes
1000 memset(Filler, 0, sizeof(Filler));
1001
1002 // Get the len of string
1003 len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
1004
1005 // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data
1006 //(see clause 4.1 for the definition of “aligned”). Because the Unicode language
1007 // code and Unicode count immediately follow the ASCII description, their
1008 // alignment is not correct if the ASCII count is not a multiple of four. The
1009 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
1010 // writing software must be written carefully in order to handle these alignment
1011 // problems.
1012 //
1013 // The above last sentence suggest to handle alignment issues in the
1014 // parser. The provided example (Table 69 on Page 60) makes this clear.
1015 // The padding only in the ASCII count is not sufficient for a aligned tag
1016 // size, with the same text size in ASCII and Unicode.
1017
1018 // Null strings
1019 if (len <= 0) {
1020
1021 Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
1022 Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
1023 }
1024 else {
1025 // Create independent buffers
1026 Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
1492
1493 SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
1494 LargestPosition = 0;
1495
1496 for (i=0; i < Count; i++) {
1497
1498 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
1499 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error;
1500
1501 // Now deal with Len and offset.
1502 if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1503 if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1504
1505 // Check for overflow
1506 if (Offset < (SizeOfHeader + 8)) goto Error;
1507 if (((Offset + Len) < Len) || ((Offset + Len) > SizeOfTag + 8)) goto Error;
1508
1509 // True begin of the string
1510 BeginOfThisString = Offset - SizeOfHeader - 8;
1511
1512 // Ajust to wchar_t elements
1513 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1514 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1515
1516 // To guess maximum size, add offset + len
1517 EndOfThisString = BeginOfThisString + Len;
1518 if (EndOfThisString > LargestPosition)
1519 LargestPosition = EndOfThisString;
1520 }
1521
1522 // Now read the remaining of tag and fill all strings. Subtract the directory
1523 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1524 if (SizeOfTag == 0)
1525 {
1526 Block = NULL;
1527 NumOfWchar = 0;
1528
1529 }
1530 else
1531 {
1532 Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
1865 }
1866
1867
1868 // Get output tables
1869 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
1870
1871 *nItems = 1;
1872 return NewLUT;
1873
1874 Error:
1875 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1876 return NULL;
1877
1878 cmsUNUSED_PARAMETER(SizeOfTag);
1879 }
1880
1881 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1882 static
1883 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1884 {
1885 cmsUInt32Number j, nTabSize;
1886 cmsUInt8Number val;
1887 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1888 cmsStage* mpe;
1889 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1890 _cmsStageMatrixData* MatMPE = NULL;
1891 _cmsStageCLutData* clut = NULL;
1892 cmsUInt32Number clutPoints;
1893
1894 // Disassemble the LUT into components.
1895 mpe = NewLUT -> Elements;
1896 if (mpe ->Type == cmsSigMatrixElemType) {
1897
1898 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1899 mpe = mpe -> Next;
1900 }
1901
1902 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1903 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1904 mpe = mpe -> Next;
1905 }
1914 mpe = mpe -> Next;
1915 }
1916
1917 // That should be all
1918 if (mpe != NULL) {
1919 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
1920 return FALSE;
1921 }
1922
1923
1924 if (clut == NULL)
1925 clutPoints = 0;
1926 else
1927 clutPoints = clut->Params->nSamples[0];
1928
1929 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
1930 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
1931 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
1932 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
1933
1934
1935 if (MatMPE != NULL) {
1936
1937 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
1938 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
1939 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
1940 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
1941 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
1942 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
1943 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
1944 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
1945 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
1946
1947 }
1948 else {
1949
1950 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1951 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1952 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1953 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1954 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1955 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1956 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1957 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1958 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1959 }
1960
1961 // The prelinearization table
1962 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1963
1964 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1965 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
1966 if (nTabSize > 0) {
1967
1968 // The 3D CLUT.
1969 if (clut != NULL) {
2168
2169 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2170 // Some empty defaults are created for missing parts
2171
2172 static
2173 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2174 {
2175 cmsUInt32Number nTabSize;
2176 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2177 cmsStage* mpe;
2178 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2179 _cmsStageMatrixData* MatMPE = NULL;
2180 _cmsStageCLutData* clut = NULL;
2181 cmsUInt32Number i, InputChannels, OutputChannels, clutPoints;
2182
2183 // Disassemble the LUT into components.
2184 mpe = NewLUT -> Elements;
2185 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2186
2187 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
2188 mpe = mpe -> Next;
2189 }
2190
2191
2192 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2193 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2194 mpe = mpe -> Next;
2195 }
2196
2197 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
2198 clut = (_cmsStageCLutData*) mpe -> Data;
2199 mpe = mpe ->Next;
2200 }
2201
2202 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2203 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2204 mpe = mpe -> Next;
2205 }
2206
2207 // That should be all
2208 if (mpe != NULL) {
2209 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
2210 return FALSE;
2211 }
2212
2213 InputChannels = cmsPipelineInputChannels(NewLUT);
2214 OutputChannels = cmsPipelineOutputChannels(NewLUT);
2215
2216 if (clut == NULL)
2217 clutPoints = 0;
2218 else
2219 clutPoints = clut->Params->nSamples[0];
2220
2221 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
2222 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
2223 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
2224 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
2225
2226
2227 if (MatMPE != NULL) {
2228
2229 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[0])) return FALSE;
2230 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[1])) return FALSE;
2231 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[2])) return FALSE;
2232 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[3])) return FALSE;
2233 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[4])) return FALSE;
2234 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[5])) return FALSE;
2235 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[6])) return FALSE;
2236 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[7])) return FALSE;
2237 if (!_cmsWrite15Fixed16Number(io, MatMPE -> Double[8])) return FALSE;
2238 }
2239 else {
2240
2241 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2242 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2243 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2244 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2245 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2246 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2247 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2248 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2249 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2250 }
2251
2252
2253 if (PreMPE != NULL) {
2254 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
2255 } else {
2256 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2257 }
2562 }
2563
2564 if (offsetB != 0) {
2565 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
2566 goto Error;
2567 }
2568
2569 *nItems = 1;
2570 return NewLUT;
2571 Error:
2572 cmsPipelineFree(NewLUT);
2573 return NULL;
2574
2575 cmsUNUSED_PARAMETER(SizeOfTag);
2576 }
2577
2578 // Write a set of curves
2579 static
2580 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2581 {
2582 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2583
2584 // Write the Matrix
2585 if (!_cmsWrite15Fixed16Number(io, m -> Double[0])) return FALSE;
2586 if (!_cmsWrite15Fixed16Number(io, m -> Double[1])) return FALSE;
2587 if (!_cmsWrite15Fixed16Number(io, m -> Double[2])) return FALSE;
2588 if (!_cmsWrite15Fixed16Number(io, m -> Double[3])) return FALSE;
2589 if (!_cmsWrite15Fixed16Number(io, m -> Double[4])) return FALSE;
2590 if (!_cmsWrite15Fixed16Number(io, m -> Double[5])) return FALSE;
2591 if (!_cmsWrite15Fixed16Number(io, m -> Double[6])) return FALSE;
2592 if (!_cmsWrite15Fixed16Number(io, m -> Double[7])) return FALSE;
2593 if (!_cmsWrite15Fixed16Number(io, m -> Double[8])) return FALSE;
2594
2595 if (m ->Offset != NULL) {
2596
2597 if (!_cmsWrite15Fixed16Number(io, m -> Offset[0])) return FALSE;
2598 if (!_cmsWrite15Fixed16Number(io, m -> Offset[1])) return FALSE;
2599 if (!_cmsWrite15Fixed16Number(io, m -> Offset[2])) return FALSE;
2600 }
2601 else {
2602 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2603 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2604 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2605
2606 }
2607
2608
2609 return TRUE;
2610
2611 cmsUNUSED_PARAMETER(self);
2612 }
2613
2614
2615 // Write a set of curves
2616 static
2617 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2618 {
2619 cmsUInt32Number i, n;
2620 cmsTagTypeSignature CurrentType;
2621 cmsToneCurve** Curves;
2622
2623
2624 n = cmsStageOutputChannels(mpe);
2625 Curves = _cmsStageGetPtrToCurveSet(mpe);
3103 }
3104
3105
3106 static
3107 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3108 {
3109 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3110 return;
3111
3112 cmsUNUSED_PARAMETER(self);
3113 }
3114
3115
3116 // ********************************************************************************
3117 // Type cmsSigNamedColor2Type
3118 // ********************************************************************************
3119 //
3120 //The namedColor2Type is a count value and array of structures that provide color
3121 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3122 //device representation of the color are given. Both representations are 16-bit values.
3123 //The device representation corresponds to the header’s “color space of data” field.
3124 //This representation should be consistent with the “number of device components”
3125 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3126 //The PCS representation corresponds to the header’s PCS field. The PCS representation
3127 //is always provided. Color names are fixed-length, 32-byte fields including null
3128 //termination. In order to maintain maximum portability, it is strongly recommended
3129 //that special characters of the 7-bit ASCII set not be used.
3130
3131 static
3132 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3133 {
3134
3135 cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
3136 cmsUInt32Number count; // Count of named colors
3137 cmsUInt32Number nDeviceCoords; // Num of device coordinates
3138 char prefix[32]; // Prefix for each color name
3139 char suffix[32]; // Suffix for each color name
3140 cmsNAMEDCOLORLIST* v;
3141 cmsUInt32Number i;
3142
3143
3144 *nItems = 0;
3145 if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
3146 if (!_cmsReadUInt32Number(io, &count)) return NULL;
3851 static
3852 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3853 {
3854 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3855
3856 cmsUNUSED_PARAMETER(n);
3857 }
3858
3859
3860 static
3861 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3862 {
3863 _cmsFree(self ->ContextID, Ptr);
3864 }
3865
3866 // ********************************************************************************
3867 // Type cmsSigViewingConditionsType
3868 // ********************************************************************************
3869 //
3870 //This type represents a set of viewing condition parameters including:
3871 //CIE ’absolute’ illuminant white point tristimulus values and CIE ’absolute’
3872 //surround tristimulus values.
3873
3874 static
3875 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3876 {
3877 cmsICCViewingConditions* vc = NULL;
3878
3879 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3880 if (vc == NULL) return NULL;
3881
3882 *nItems = 0;
3883
3884 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3885 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3886 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3887
3888 *nItems = 1;
3889
3890 return (void*) vc;
3891
3938
3939 static
3940 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3941 {
3942 return (void*) cmsStageDup((cmsStage*) Ptr);
3943
3944 cmsUNUSED_PARAMETER(n);
3945 cmsUNUSED_PARAMETER(self);
3946 }
3947
3948 static
3949 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
3950 {
3951 cmsStageFree((cmsStage*) Ptr);
3952 return;
3953
3954 cmsUNUSED_PARAMETER(self);
3955 }
3956
3957 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
3958 // The first curve segment always starts at –Infinity, and the last curve segment always ends at +Infinity. The
3959 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
3960 // specified either in terms of a formula, or by a sampled curve.
3961
3962
3963 // Read an embedded segmented curve
3964 static
3965 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
3966 {
3967 cmsCurveSegSignature ElementSig;
3968 cmsUInt32Number i, j;
3969 cmsUInt16Number nSegments;
3970 cmsCurveSegment* Segments;
3971 cmsToneCurve* Curve;
3972 cmsFloat32Number PrevBreak = MINUS_INF; // - infinite
3973
3974 // Take signature and channels for each element.
3975 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
3976
3977 // That should be a segmented curve
3978 if (ElementSig != cmsSigSegmentedCurve) return NULL;
4219 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4220
4221 // Write the header. Since those are curves, input and output channels are same
4222 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4223 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4224
4225 if (!WritePositionTable(self, io, 0,
4226 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4227
4228
4229 return TRUE;
4230
4231 cmsUNUSED_PARAMETER(nItems);
4232 }
4233
4234
4235
4236 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4237 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4238 // is organized as follows:
4239 // array = [e11, e12, …, e1P, e21, e22, …, e2P, …, eQ1, eQ2, …, eQP, e1, e2, …, eQ]
4240
4241 static
4242 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4243 {
4244 cmsStage* mpe;
4245 cmsUInt16Number InputChans, OutputChans;
4246 cmsUInt32Number nElems, i;
4247 cmsFloat64Number* Matrix;
4248 cmsFloat64Number* Offsets;
4249
4250 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4251 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4252
4253
4254 // Input and output chans may be ANY (up to 0xffff),
4255 // but we choose to limit to 16 channels for now
4256 if (InputChans >= cmsMAXCHANNELS) return NULL;
4257 if (OutputChans >= cmsMAXCHANNELS) return NULL;
4258
4259 nElems = (cmsUInt32Number) InputChans * OutputChans;
4742
4743 // In this case, gamma is stored as a formula
4744 case cmsVideoCardGammaFormulaType:
4745 {
4746 _cmsVCGTGAMMA Colorant[3];
4747
4748 // Populate tone curves
4749 for (n=0; n < 3; n++) {
4750
4751 double Params[10];
4752
4753 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
4754 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
4755 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
4756
4757 // Parametric curve type 5 is:
4758 // Y = (aX + b)^Gamma + e | X >= d
4759 // Y = cX + f | X < d
4760
4761 // vcgt formula is:
4762 // Y = (Max – Min) * (X ^ Gamma) + Min
4763
4764 // So, the translation is
4765 // a = (Max – Min) ^ ( 1 / Gamma)
4766 // e = Min
4767 // b=c=d=f=0
4768
4769 Params[0] = Colorant[n].Gamma;
4770 Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
4771 Params[2] = 0;
4772 Params[3] = 0;
4773 Params[4] = 0;
4774 Params[5] = Colorant[n].Min;
4775 Params[6] = 0;
4776
4777 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4778 if (Curves[n] == NULL) goto Error;
4779 }
4780 }
4781 break;
4782
4783 // Unsupported
4784 default:
4785 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
|
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2020 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
178
179 if (!_cmsReadUInt16Number(io, &tmp)) return FALSE;
180 Array[i] = (wchar_t) tmp;
181 }
182 else {
183 if (!_cmsReadUInt16Number(io, NULL)) return FALSE;
184 }
185
186 }
187 return TRUE;
188 }
189
190 // To deal with position tables
191 typedef cmsBool (* PositionTableEntryFn)(struct _cms_typehandler_struct* self,
192 cmsIOHANDLER* io,
193 void* Cargo,
194 cmsUInt32Number n,
195 cmsUInt32Number SizeOfTag);
196
197 // Helper function to deal with position tables as described in ICC spec 4.3
198 // A table of n elements is read, where first comes n records containing offsets and sizes and
199 // then a block containing the data itself. This allows to reuse same data in more than one entry
200 static
201 cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
202 cmsIOHANDLER* io,
203 cmsUInt32Number Count,
204 cmsUInt32Number BaseOffset,
205 void *Cargo,
206 PositionTableEntryFn ElementFn)
207 {
208 cmsUInt32Number i;
209 cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
210 cmsUInt32Number currentPosition;
211
212 currentPosition = io->Tell(io);
213
214 // Verify there is enough space left to read at least two cmsUInt32Number items for Count items.
215 if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count)
216 return FALSE;
217
218 // Let's take the offsets to each element
986
987
988 // This tag can come IN UNALIGNED SIZE. In order to prevent issues, we force zeros on description to align it
989 static
990 cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
991 {
992 cmsMLU* mlu = (cmsMLU*) Ptr;
993 char *Text = NULL;
994 wchar_t *Wide = NULL;
995 cmsUInt32Number len, len_text, len_tag_requirement, len_aligned;
996 cmsBool rc = FALSE;
997 char Filler[68];
998
999 // Used below for writing zeroes
1000 memset(Filler, 0, sizeof(Filler));
1001
1002 // Get the len of string
1003 len = cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, NULL, 0);
1004
1005 // Specification ICC.1:2001-04 (v2.4.0): It has been found that textDescriptionType can contain misaligned data
1006 //(see clause 4.1 for the definition of 'aligned'). Because the Unicode language
1007 // code and Unicode count immediately follow the ASCII description, their
1008 // alignment is not correct if the ASCII count is not a multiple of four. The
1009 // ScriptCode code is misaligned when the ASCII count is odd. Profile reading and
1010 // writing software must be written carefully in order to handle these alignment
1011 // problems.
1012 //
1013 // The above last sentence suggest to handle alignment issues in the
1014 // parser. The provided example (Table 69 on Page 60) makes this clear.
1015 // The padding only in the ASCII count is not sufficient for a aligned tag
1016 // size, with the same text size in ASCII and Unicode.
1017
1018 // Null strings
1019 if (len <= 0) {
1020
1021 Text = (char*) _cmsDupMem(self ->ContextID, "", sizeof(char));
1022 Wide = (wchar_t*) _cmsDupMem(self ->ContextID, L"", sizeof(wchar_t));
1023 }
1024 else {
1025 // Create independent buffers
1026 Text = (char*) _cmsCalloc(self ->ContextID, len, sizeof(char));
1492
1493 SizeOfHeader = 12 * Count + sizeof(_cmsTagBase);
1494 LargestPosition = 0;
1495
1496 for (i=0; i < Count; i++) {
1497
1498 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Language)) goto Error;
1499 if (!_cmsReadUInt16Number(io, &mlu ->Entries[i].Country)) goto Error;
1500
1501 // Now deal with Len and offset.
1502 if (!_cmsReadUInt32Number(io, &Len)) goto Error;
1503 if (!_cmsReadUInt32Number(io, &Offset)) goto Error;
1504
1505 // Check for overflow
1506 if (Offset < (SizeOfHeader + 8)) goto Error;
1507 if (((Offset + Len) < Len) || ((Offset + Len) > SizeOfTag + 8)) goto Error;
1508
1509 // True begin of the string
1510 BeginOfThisString = Offset - SizeOfHeader - 8;
1511
1512 // Adjust to wchar_t elements
1513 mlu ->Entries[i].Len = (Len * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1514 mlu ->Entries[i].StrW = (BeginOfThisString * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1515
1516 // To guess maximum size, add offset + len
1517 EndOfThisString = BeginOfThisString + Len;
1518 if (EndOfThisString > LargestPosition)
1519 LargestPosition = EndOfThisString;
1520 }
1521
1522 // Now read the remaining of tag and fill all strings. Subtract the directory
1523 SizeOfTag = (LargestPosition * sizeof(wchar_t)) / sizeof(cmsUInt16Number);
1524 if (SizeOfTag == 0)
1525 {
1526 Block = NULL;
1527 NumOfWchar = 0;
1528
1529 }
1530 else
1531 {
1532 Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
1865 }
1866
1867
1868 // Get output tables
1869 if (!Read8bitTables(self ->ContextID, io, NewLUT, OutputChannels)) goto Error;
1870
1871 *nItems = 1;
1872 return NewLUT;
1873
1874 Error:
1875 if (NewLUT != NULL) cmsPipelineFree(NewLUT);
1876 return NULL;
1877
1878 cmsUNUSED_PARAMETER(SizeOfTag);
1879 }
1880
1881 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
1882 static
1883 cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
1884 {
1885 cmsUInt32Number j, nTabSize, i, n;
1886 cmsUInt8Number val;
1887 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
1888 cmsStage* mpe;
1889 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
1890 _cmsStageMatrixData* MatMPE = NULL;
1891 _cmsStageCLutData* clut = NULL;
1892 cmsUInt32Number clutPoints;
1893
1894 // Disassemble the LUT into components.
1895 mpe = NewLUT -> Elements;
1896 if (mpe ->Type == cmsSigMatrixElemType) {
1897
1898 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
1899 mpe = mpe -> Next;
1900 }
1901
1902 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
1903 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
1904 mpe = mpe -> Next;
1905 }
1914 mpe = mpe -> Next;
1915 }
1916
1917 // That should be all
1918 if (mpe != NULL) {
1919 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
1920 return FALSE;
1921 }
1922
1923
1924 if (clut == NULL)
1925 clutPoints = 0;
1926 else
1927 clutPoints = clut->Params->nSamples[0];
1928
1929 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
1930 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
1931 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
1932 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
1933
1934 n = NewLUT->InputChannels * NewLUT->OutputChannels;
1935
1936 if (MatMPE != NULL) {
1937
1938 for (i = 0; i < n; i++)
1939 {
1940 if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
1941 }
1942 }
1943 else {
1944
1945 if (n != 9) return FALSE;
1946
1947 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1948 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1949 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1950 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1951 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1952 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1953 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1954 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
1955 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
1956 }
1957
1958 // The prelinearization table
1959 if (!Write8bitTables(self ->ContextID, io, NewLUT ->InputChannels, PreMPE)) return FALSE;
1960
1961 nTabSize = uipow(NewLUT->OutputChannels, clutPoints, NewLUT ->InputChannels);
1962 if (nTabSize == (cmsUInt32Number) -1) return FALSE;
1963 if (nTabSize > 0) {
1964
1965 // The 3D CLUT.
1966 if (clut != NULL) {
2165
2166 // We only allow some specific MPE structures: Matrix plus prelin, plus clut, plus post-lin.
2167 // Some empty defaults are created for missing parts
2168
2169 static
2170 cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
2171 {
2172 cmsUInt32Number nTabSize;
2173 cmsPipeline* NewLUT = (cmsPipeline*) Ptr;
2174 cmsStage* mpe;
2175 _cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
2176 _cmsStageMatrixData* MatMPE = NULL;
2177 _cmsStageCLutData* clut = NULL;
2178 cmsUInt32Number i, InputChannels, OutputChannels, clutPoints;
2179
2180 // Disassemble the LUT into components.
2181 mpe = NewLUT -> Elements;
2182 if (mpe != NULL && mpe ->Type == cmsSigMatrixElemType) {
2183
2184 MatMPE = (_cmsStageMatrixData*) mpe ->Data;
2185 if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE;
2186 mpe = mpe -> Next;
2187 }
2188
2189
2190 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2191 PreMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2192 mpe = mpe -> Next;
2193 }
2194
2195 if (mpe != NULL && mpe ->Type == cmsSigCLutElemType) {
2196 clut = (_cmsStageCLutData*) mpe -> Data;
2197 mpe = mpe ->Next;
2198 }
2199
2200 if (mpe != NULL && mpe ->Type == cmsSigCurveSetElemType) {
2201 PostMPE = (_cmsStageToneCurvesData*) mpe ->Data;
2202 mpe = mpe -> Next;
2203 }
2204
2205 // That should be all
2206 if (mpe != NULL) {
2207 cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
2208 return FALSE;
2209 }
2210
2211 InputChannels = cmsPipelineInputChannels(NewLUT);
2212 OutputChannels = cmsPipelineOutputChannels(NewLUT);
2213
2214 if (clut == NULL)
2215 clutPoints = 0;
2216 else
2217 clutPoints = clut->Params->nSamples[0];
2218
2219 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
2220 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
2221 if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
2222 if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
2223
2224 if (MatMPE != NULL) {
2225
2226 for (i = 0; i < 9; i++)
2227 {
2228 if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
2229 }
2230
2231 }
2232 else {
2233
2234 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2235 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2236 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2237 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2238 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2239 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2240 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2241 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2242 if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
2243 }
2244
2245
2246 if (PreMPE != NULL) {
2247 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) PreMPE ->TheCurves[0]->nEntries)) return FALSE;
2248 } else {
2249 if (!_cmsWriteUInt16Number(io, 2)) return FALSE;
2250 }
2555 }
2556
2557 if (offsetB != 0) {
2558 if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, ReadSetOfCurves(self, io, BaseOffset + offsetB, outputChan)))
2559 goto Error;
2560 }
2561
2562 *nItems = 1;
2563 return NewLUT;
2564 Error:
2565 cmsPipelineFree(NewLUT);
2566 return NULL;
2567
2568 cmsUNUSED_PARAMETER(SizeOfTag);
2569 }
2570
2571 // Write a set of curves
2572 static
2573 cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
2574 {
2575 cmsUInt32Number i, n;
2576
2577 _cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
2578
2579 n = mpe->InputChannels * mpe->OutputChannels;
2580
2581 // Write the Matrix
2582 for (i = 0; i < n; i++)
2583 {
2584 if (!_cmsWrite15Fixed16Number(io, m->Double[i])) return FALSE;
2585 }
2586
2587 if (m->Offset != NULL) {
2588
2589 for (i = 0; i < mpe->OutputChannels; i++)
2590 {
2591 if (!_cmsWrite15Fixed16Number(io, m->Offset[i])) return FALSE;
2592 }
2593 }
2594 else {
2595 for (i = 0; i < mpe->OutputChannels; i++)
2596 {
2597 if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
2598 }
2599 }
2600
2601
2602 return TRUE;
2603
2604 cmsUNUSED_PARAMETER(self);
2605 }
2606
2607
2608 // Write a set of curves
2609 static
2610 cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsTagTypeSignature Type, cmsStage* mpe)
2611 {
2612 cmsUInt32Number i, n;
2613 cmsTagTypeSignature CurrentType;
2614 cmsToneCurve** Curves;
2615
2616
2617 n = cmsStageOutputChannels(mpe);
2618 Curves = _cmsStageGetPtrToCurveSet(mpe);
3096 }
3097
3098
3099 static
3100 void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr)
3101 {
3102 cmsFreeNamedColorList((cmsNAMEDCOLORLIST*) Ptr);
3103 return;
3104
3105 cmsUNUSED_PARAMETER(self);
3106 }
3107
3108
3109 // ********************************************************************************
3110 // Type cmsSigNamedColor2Type
3111 // ********************************************************************************
3112 //
3113 //The namedColor2Type is a count value and array of structures that provide color
3114 //coordinates for 7-bit ASCII color names. For each named color, a PCS and optional
3115 //device representation of the color are given. Both representations are 16-bit values.
3116 //The device representation corresponds to the header's 'color space of data' field.
3117 //This representation should be consistent with the 'number of device components'
3118 //field in the namedColor2Type. If this field is 0, device coordinates are not provided.
3119 //The PCS representation corresponds to the header's PCS field. The PCS representation
3120 //is always provided. Color names are fixed-length, 32-byte fields including null
3121 //termination. In order to maintain maximum portability, it is strongly recommended
3122 //that special characters of the 7-bit ASCII set not be used.
3123
3124 static
3125 void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3126 {
3127
3128 cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
3129 cmsUInt32Number count; // Count of named colors
3130 cmsUInt32Number nDeviceCoords; // Num of device coordinates
3131 char prefix[32]; // Prefix for each color name
3132 char suffix[32]; // Suffix for each color name
3133 cmsNAMEDCOLORLIST* v;
3134 cmsUInt32Number i;
3135
3136
3137 *nItems = 0;
3138 if (!_cmsReadUInt32Number(io, &vendorFlag)) return NULL;
3139 if (!_cmsReadUInt32Number(io, &count)) return NULL;
3844 static
3845 void* Type_Screening_Dup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3846 {
3847 return _cmsDupMem(self ->ContextID, Ptr, sizeof(cmsScreening));
3848
3849 cmsUNUSED_PARAMETER(n);
3850 }
3851
3852
3853 static
3854 void Type_Screening_Free(struct _cms_typehandler_struct* self, void* Ptr)
3855 {
3856 _cmsFree(self ->ContextID, Ptr);
3857 }
3858
3859 // ********************************************************************************
3860 // Type cmsSigViewingConditionsType
3861 // ********************************************************************************
3862 //
3863 //This type represents a set of viewing condition parameters including:
3864 //CIE 'absolute' illuminant white point tristimulus values and CIE 'absolute'
3865 //surround tristimulus values.
3866
3867 static
3868 void *Type_ViewingConditions_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
3869 {
3870 cmsICCViewingConditions* vc = NULL;
3871
3872 vc = (cmsICCViewingConditions*) _cmsMallocZero(self ->ContextID, sizeof(cmsICCViewingConditions));
3873 if (vc == NULL) return NULL;
3874
3875 *nItems = 0;
3876
3877 if (!_cmsReadXYZNumber(io, &vc ->IlluminantXYZ)) goto Error;
3878 if (!_cmsReadXYZNumber(io, &vc ->SurroundXYZ)) goto Error;
3879 if (!_cmsReadUInt32Number(io, &vc ->IlluminantType)) goto Error;
3880
3881 *nItems = 1;
3882
3883 return (void*) vc;
3884
3931
3932 static
3933 void* GenericMPEdup(struct _cms_typehandler_struct* self, const void *Ptr, cmsUInt32Number n)
3934 {
3935 return (void*) cmsStageDup((cmsStage*) Ptr);
3936
3937 cmsUNUSED_PARAMETER(n);
3938 cmsUNUSED_PARAMETER(self);
3939 }
3940
3941 static
3942 void GenericMPEfree(struct _cms_typehandler_struct* self, void *Ptr)
3943 {
3944 cmsStageFree((cmsStage*) Ptr);
3945 return;
3946
3947 cmsUNUSED_PARAMETER(self);
3948 }
3949
3950 // Each curve is stored in one or more curve segments, with break-points specified between curve segments.
3951 // The first curve segment always starts at -Infinity, and the last curve segment always ends at +Infinity. The
3952 // first and last curve segments shall be specified in terms of a formula, whereas the other segments shall be
3953 // specified either in terms of a formula, or by a sampled curve.
3954
3955
3956 // Read an embedded segmented curve
3957 static
3958 cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHANDLER* io)
3959 {
3960 cmsCurveSegSignature ElementSig;
3961 cmsUInt32Number i, j;
3962 cmsUInt16Number nSegments;
3963 cmsCurveSegment* Segments;
3964 cmsToneCurve* Curve;
3965 cmsFloat32Number PrevBreak = MINUS_INF; // - infinite
3966
3967 // Take signature and channels for each element.
3968 if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
3969
3970 // That should be a segmented curve
3971 if (ElementSig != cmsSigSegmentedCurve) return NULL;
4212 BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase);
4213
4214 // Write the header. Since those are curves, input and output channels are same
4215 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4216 if (!_cmsWriteUInt16Number(io, (cmsUInt16Number) mpe ->InputChannels)) return FALSE;
4217
4218 if (!WritePositionTable(self, io, 0,
4219 mpe ->InputChannels, BaseOffset, Curves, WriteMPECurve)) return FALSE;
4220
4221
4222 return TRUE;
4223
4224 cmsUNUSED_PARAMETER(nItems);
4225 }
4226
4227
4228
4229 // The matrix is organized as an array of PxQ+Q elements, where P is the number of input channels to the
4230 // matrix, and Q is the number of output channels. The matrix elements are each float32Numbers. The array
4231 // is organized as follows:
4232 // array = [e11, e12, ..., e1P, e21, e22, ..., e2P, ..., eQ1, eQ2, ..., eQP, e1, e2, ..., eQ]
4233
4234 static
4235 void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
4236 {
4237 cmsStage* mpe;
4238 cmsUInt16Number InputChans, OutputChans;
4239 cmsUInt32Number nElems, i;
4240 cmsFloat64Number* Matrix;
4241 cmsFloat64Number* Offsets;
4242
4243 if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
4244 if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
4245
4246
4247 // Input and output chans may be ANY (up to 0xffff),
4248 // but we choose to limit to 16 channels for now
4249 if (InputChans >= cmsMAXCHANNELS) return NULL;
4250 if (OutputChans >= cmsMAXCHANNELS) return NULL;
4251
4252 nElems = (cmsUInt32Number) InputChans * OutputChans;
4735
4736 // In this case, gamma is stored as a formula
4737 case cmsVideoCardGammaFormulaType:
4738 {
4739 _cmsVCGTGAMMA Colorant[3];
4740
4741 // Populate tone curves
4742 for (n=0; n < 3; n++) {
4743
4744 double Params[10];
4745
4746 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Gamma)) goto Error;
4747 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Min)) goto Error;
4748 if (!_cmsRead15Fixed16Number(io, &Colorant[n].Max)) goto Error;
4749
4750 // Parametric curve type 5 is:
4751 // Y = (aX + b)^Gamma + e | X >= d
4752 // Y = cX + f | X < d
4753
4754 // vcgt formula is:
4755 // Y = (Max - Min) * (X ^ Gamma) + Min
4756
4757 // So, the translation is
4758 // a = (Max - Min) ^ ( 1 / Gamma)
4759 // e = Min
4760 // b=c=d=f=0
4761
4762 Params[0] = Colorant[n].Gamma;
4763 Params[1] = pow((Colorant[n].Max - Colorant[n].Min), (1.0 / Colorant[n].Gamma));
4764 Params[2] = 0;
4765 Params[3] = 0;
4766 Params[4] = 0;
4767 Params[5] = Colorant[n].Min;
4768 Params[6] = 0;
4769
4770 Curves[n] = cmsBuildParametricToneCurve(self ->ContextID, 5, Params);
4771 if (Curves[n] == NULL) goto Error;
4772 }
4773 }
4774 break;
4775
4776 // Unsupported
4777 default:
4778 cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported tag type for VCGT '%d'", TagType);
|