File: | IccProfLib/IccCmm.cpp |
Warning: | line 6321, column 17 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /** @file | |||
2 | File: IccCmm.cpp | |||
3 | ||||
4 | Contains: Implementation of the CIccCmm class. | |||
5 | ||||
6 | Version: V1 | |||
7 | ||||
8 | Copyright: � see ICC Software License | |||
9 | */ | |||
10 | ||||
11 | /* | |||
12 | * The ICC Software License, Version 0.2 | |||
13 | * | |||
14 | * | |||
15 | * Copyright (c) 2003-2012 The International Color Consortium. All rights | |||
16 | * reserved. | |||
17 | * | |||
18 | * Redistribution and use in source and binary forms, with or without | |||
19 | * modification, are permitted provided that the following conditions | |||
20 | * are met: | |||
21 | * | |||
22 | * 1. Redistributions of source code must retain the above copyright | |||
23 | * notice, this list of conditions and the following disclaimer. | |||
24 | * | |||
25 | * 2. Redistributions in binary form must reproduce the above copyright | |||
26 | * notice, this list of conditions and the following disclaimer in | |||
27 | * the documentation and/or other materials provided with the | |||
28 | * distribution. | |||
29 | * | |||
30 | * 3. In the absence of prior written permission, the names "ICC" and "The | |||
31 | * International Color Consortium" must not be used to imply that the | |||
32 | * ICC organization endorses or promotes products derived from this | |||
33 | * software. | |||
34 | * | |||
35 | * | |||
36 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED | |||
37 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
38 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||
39 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR | |||
40 | * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
41 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
42 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | |||
43 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |||
44 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |||
45 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |||
46 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
47 | * SUCH DAMAGE. | |||
48 | * ==================================================================== | |||
49 | * | |||
50 | * This software consists of voluntary contributions made by many | |||
51 | * individuals on behalf of the The International Color Consortium. | |||
52 | * | |||
53 | * | |||
54 | * Membership in the ICC is encouraged when this software is used for | |||
55 | * commercial purposes. | |||
56 | * | |||
57 | * | |||
58 | * For more information on The International Color Consortium, please | |||
59 | * see <http://www.color.org/>. | |||
60 | * | |||
61 | * | |||
62 | */ | |||
63 | ||||
64 | ////////////////////////////////////////////////////////////////////// | |||
65 | // HISTORY: | |||
66 | // | |||
67 | // -Initial implementation by Max Derhak 5-15-2003 | |||
68 | // -Added support for Monochrome ICC profile apply by Rohit Patil 12-03-2008 | |||
69 | // -Integrated changes for PCS adjustment by George Pawle 12-09-2008 | |||
70 | // | |||
71 | ////////////////////////////////////////////////////////////////////// | |||
72 | ||||
73 | #ifdef WIN32 | |||
74 | #pragma warning( disable: 4786) //disable warning in <list.h> | |||
75 | #endif | |||
76 | ||||
77 | #include "IccXformFactory.h" | |||
78 | #include "IccTag.h" | |||
79 | #include "IccMpeBasic.h" | |||
80 | #include "IccArrayBasic.h" | |||
81 | #include "IccStructBasic.h" | |||
82 | #include "IccIO.h" | |||
83 | #include "IccApplyBPC.h" | |||
84 | #include "IccSparseMatrix.h" | |||
85 | #include "IccEncoding.h" | |||
86 | #include "IccMatrixMath.h" | |||
87 | ||||
88 | #ifdef USEREFICCMAXNAMESPACE | |||
89 | namespace refIccMAX { | |||
90 | #endif | |||
91 | ||||
92 | //// | |||
93 | // Useful Macros | |||
94 | //// | |||
95 | ||||
96 | static __inlineinline bool IsSpaceSpectralPCS(icUInt32Number sig) | |||
97 | { | |||
98 | sig = icGetColorSpaceType(sig)((icColorSpaceSignature)(((icUInt32Number)sig)&0xffff0000 )); | |||
99 | ||||
100 | return sig==icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData) || | |||
101 | sig==icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData) || | |||
102 | sig==icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData) || | |||
103 | sig==icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData) || | |||
104 | sig==icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData); | |||
105 | } | |||
106 | ||||
107 | #define IsSpaceColorimetricPCS(x)((x)==icSigXYZData || (x)==icSigLabData) ((x)==icSigXYZPcsDataicSigXYZData || (x)==icSigLabPcsDataicSigLabData) | |||
108 | #define IsSpaceNChannel(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigNChannelData) (icGetColorSpaceType(x)((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000))==icSigNChannelData) | |||
109 | #define IsSpacePCS(x)(((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS (x)) (IsSpaceColorimetricPCS(x)((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS(x)) | |||
110 | #define IsSpaceMCS(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigSrcMCSChannelData) (icGetColorSpaceType(x)((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000))==icSigSrcMCSChannelData) | |||
111 | #define IsSpaceCMYK(x)((x)==icSigCmykData || (x)==icSig4colorData) ((x)==icSigCmykData || (x)==icSig4colorData) | |||
112 | ||||
113 | #define IsNChannelCompat(x, y)(((((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000 ))==icSigNChannelData) && (((icUInt32Number)x)&0x0000ffff )==icGetSpaceSamples(y)) || ((((icColorSpaceSignature)(((icUInt32Number )y)&0xffff0000))==icSigNChannelData) && (((icUInt32Number )y)&0x0000ffff)==icGetSpaceSamples(x))) ((IsSpaceNChannel(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigNChannelData) && icNumColorSpaceChannels(x)(((icUInt32Number)x)&0x0000ffff)==icGetSpaceSamples(y)) || (IsSpaceNChannel(y)(((icColorSpaceSignature)(((icUInt32Number)y)&0xffff0000) )==icSigNChannelData) && icNumColorSpaceChannels(y)(((icUInt32Number)y)&0x0000ffff)==icGetSpaceSamples(x))) | |||
114 | ||||
115 | #define IsCompatSpace(x, y)((x)==(y) || ((((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS (x)) && (((y)==icSigXYZData || (y)==icSigLabData) || IsSpaceSpectralPCS (y))) || ((((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000 ))==icSigSrcMCSChannelData) && (((icColorSpaceSignature )(((icUInt32Number)y)&0xffff0000))==icSigSrcMCSChannelData )) ) ((x)==(y) || (IsSpacePCS(x)(((x)==icSigXYZData || (x)==icSigLabData) || IsSpaceSpectralPCS (x)) && IsSpacePCS(y)(((y)==icSigXYZData || (y)==icSigLabData) || IsSpaceSpectralPCS (y))) || (IsSpaceMCS(x)(((icColorSpaceSignature)(((icUInt32Number)x)&0xffff0000) )==icSigSrcMCSChannelData) && IsSpaceMCS(y)(((icColorSpaceSignature)(((icUInt32Number)y)&0xffff0000) )==icSigSrcMCSChannelData))/* || (IsSpaceCMYK(x) && IsSpaceCMYK(y))*/) | |||
116 | ||||
117 | ||||
118 | #define ICCPCSSTEPDUMPFMT" %.8f" ICCMTXSTEPDUMPFMT" %.8f" | |||
119 | ||||
120 | ||||
121 | ////////////////////////////////////////////////////////////////////// | |||
122 | // Construction/Destruction | |||
123 | ////////////////////////////////////////////////////////////////////// | |||
124 | ||||
125 | /** | |||
126 | ************************************************************************** | |||
127 | * Class CIccPCS Constructor | |||
128 | * | |||
129 | * Purpose: | |||
130 | * This is a class constructor. | |||
131 | * | |||
132 | ************************************************************************** | |||
133 | */ | |||
134 | CIccPCS::CIccPCS() | |||
135 | { | |||
136 | m_bIsV2Lab = false; | |||
137 | m_Space = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | |||
138 | m_bLastPcsXform = false; | |||
139 | } | |||
140 | ||||
141 | /** | |||
142 | ************************************************************************** | |||
143 | * Name: CIccPCS::Reset | |||
144 | * | |||
145 | * Purpose: | |||
146 | * This is called with the initial color space and a bool | |||
147 | * argument which is true if the PCS is version 2. | |||
148 | * | |||
149 | * Args: | |||
150 | * Startpsace = Starting Colorspace | |||
151 | * bUseLegacyPCS = legacy PCS flag | |||
152 | ************************************************************************** | |||
153 | */ | |||
154 | void CIccPCS::Reset(icColorSpaceSignature StartSpace, bool bUseLegacyPCS) | |||
155 | { | |||
156 | m_bIsV2Lab = IsSpacePCS(StartSpace)(((StartSpace)==icSigXYZData || (StartSpace)==icSigLabData) || IsSpaceSpectralPCS(StartSpace)) && bUseLegacyPCS; | |||
157 | m_Space = StartSpace; | |||
158 | } | |||
159 | ||||
160 | /** | |||
161 | ************************************************************************** | |||
162 | * Name: CIccPCS::Check | |||
163 | * | |||
164 | * Purpose: | |||
165 | * This is called before the apply of each profile's xform to adjust the PCS | |||
166 | * to the xform's needed PCS. | |||
167 | * | |||
168 | * Args: | |||
169 | * SrcPixel = source pixel data (this may need adjusting), | |||
170 | * pXform = the xform that who's Apply function will shortly be called | |||
171 | * | |||
172 | * Return: | |||
173 | * SrcPixel or ptr to adjusted pixel data (we dont want to modify the source data). | |||
174 | ************************************************************************** | |||
175 | */ | |||
176 | const icFloatNumber *CIccPCS::Check(const icFloatNumber *SrcPixel, const CIccXform *pXform) | |||
177 | { | |||
178 | icColorSpaceSignature NextSpace = pXform->GetSrcSpace(); | |||
179 | bool bIsV2 = pXform->UseLegacyPCS(); | |||
180 | bool bIsNextV2Lab = bIsV2 && (NextSpace == icSigLabData); | |||
181 | const icFloatNumber *rv; | |||
182 | bool bNoClip = pXform->NoClipPCS(); | |||
183 | ||||
184 | if (m_bLastPcsXform) { | |||
185 | rv = SrcPixel; | |||
186 | } | |||
187 | else if (m_bIsV2Lab && !bIsNextV2Lab) { | |||
188 | Lab2ToLab4(m_Convert, SrcPixel, bNoClip); | |||
189 | if (NextSpace==icSigXYZData) { | |||
190 | LabToXyz(m_Convert, m_Convert, bNoClip); | |||
191 | } | |||
192 | rv = m_Convert; | |||
193 | } | |||
194 | else if (!m_bIsV2Lab && bIsNextV2Lab) { | |||
195 | if (m_Space==icSigXYZData) { | |||
196 | XyzToLab(m_Convert, SrcPixel, bNoClip); | |||
197 | SrcPixel = m_Convert; | |||
198 | } | |||
199 | Lab4ToLab2(m_Convert, SrcPixel); | |||
200 | rv = m_Convert; | |||
201 | } | |||
202 | else if (m_Space==NextSpace) { | |||
203 | rv = SrcPixel; | |||
204 | } | |||
205 | else if (m_Space==icSigXYZData && NextSpace==icSigLabData) { | |||
206 | XyzToLab(m_Convert, SrcPixel, bNoClip); | |||
207 | rv = m_Convert; | |||
208 | } | |||
209 | else if (m_Space==icSigLabData && NextSpace==icSigXYZData) { | |||
210 | LabToXyz(m_Convert, SrcPixel, bNoClip); | |||
211 | rv = m_Convert; | |||
212 | } | |||
213 | else { | |||
214 | rv = SrcPixel; | |||
215 | } | |||
216 | ||||
217 | m_Space = pXform->GetDstSpace(); | |||
218 | m_bIsV2Lab = bIsV2 && (m_Space == icSigLabData); | |||
219 | m_bLastPcsXform = (pXform->GetXformType()==icXformTypePCS); | |||
220 | ||||
221 | return rv; | |||
222 | } | |||
223 | ||||
224 | /** | |||
225 | ************************************************************************** | |||
226 | * Name: CIccPCS::CheckLast | |||
227 | * | |||
228 | * Purpose: | |||
229 | * Called after all xforms are applied to adjust PCS to final space if needed | |||
230 | * Note: space will always be V4. | |||
231 | * | |||
232 | * Args: | |||
233 | * Pixel = Pixel data, | |||
234 | * DestSpace = destination color space | |||
235 | * bNoClip = indicates whether PCS should be clipped | |||
236 | ************************************************************************** | |||
237 | */ | |||
238 | void CIccPCS::CheckLast(icFloatNumber *Pixel, icColorSpaceSignature DestSpace, bool bNoClip) | |||
239 | { | |||
240 | if (m_bIsV2Lab) { | |||
241 | Lab2ToLab4(Pixel, Pixel, bNoClip); | |||
242 | if (DestSpace==icSigXYZData) { | |||
243 | LabToXyz(Pixel, Pixel, bNoClip); | |||
244 | } | |||
245 | } | |||
246 | else if (m_Space==DestSpace) { | |||
247 | return; | |||
248 | } | |||
249 | else if (m_Space==icSigXYZData) { | |||
250 | XyzToLab(Pixel, Pixel, bNoClip); | |||
251 | } | |||
252 | else if (m_Space==icSigLabData) { | |||
253 | LabToXyz(Pixel, Pixel, bNoClip); | |||
254 | } | |||
255 | } | |||
256 | ||||
257 | /** | |||
258 | ************************************************************************** | |||
259 | * Name: CIccPCS::UnitClip | |||
260 | * | |||
261 | * Purpose: | |||
262 | * Convert a double to an icUInt16Number with clipping | |||
263 | ************************************************************************** | |||
264 | */ | |||
265 | icFloatNumber CIccPCS::UnitClip(icFloatNumber v) | |||
266 | { | |||
267 | if (v<0) | |||
268 | v = 0; | |||
269 | if (v>1.0) | |||
270 | v = 1.0; | |||
271 | ||||
272 | return v; | |||
273 | } | |||
274 | ||||
275 | /** | |||
276 | ************************************************************************** | |||
277 | * Name: CIccPCS::NegClip | |||
278 | * | |||
279 | * Purpose: | |||
280 | * Convert a double to an icUInt16Number with clipping of negative numbers | |||
281 | ************************************************************************** | |||
282 | */ | |||
283 | icFloatNumber CIccPCS::NegClip(icFloatNumber v) | |||
284 | { | |||
285 | if (v<0) | |||
286 | v=0; | |||
287 | ||||
288 | return v; | |||
289 | } | |||
290 | ||||
291 | /** | |||
292 | ************************************************************************** | |||
293 | * Name: CIccPCS::LabToXyz | |||
294 | * | |||
295 | * Purpose: | |||
296 | * Convert Lab to XYZ | |||
297 | ************************************************************************** | |||
298 | */ | |||
299 | void CIccPCS::LabToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | |||
300 | { | |||
301 | icFloatNumber Lab[3]; | |||
302 | ||||
303 | memcpy(&Lab,Src,sizeof(Lab)); | |||
304 | ||||
305 | icLabFromPcs(Lab); | |||
306 | ||||
307 | icLabtoXYZ(Lab); | |||
308 | ||||
309 | icXyzToPcs(Lab); | |||
310 | ||||
311 | if (!bNoClip) { | |||
312 | Dst[0] = UnitClip(Lab[0]); | |||
313 | Dst[1] = UnitClip(Lab[1]); | |||
314 | Dst[2] = UnitClip(Lab[2]); | |||
315 | } | |||
316 | else { | |||
317 | Dst[0] = Lab[0]; | |||
318 | Dst[1] = Lab[1]; | |||
319 | Dst[2] = Lab[2]; | |||
320 | } | |||
321 | } | |||
322 | ||||
323 | ||||
324 | /** | |||
325 | ************************************************************************** | |||
326 | * Name: CIccPCS::XyzToLab | |||
327 | * | |||
328 | * Purpose: | |||
329 | * Convert XYZ to Lab | |||
330 | ************************************************************************** | |||
331 | */ | |||
332 | void CIccPCS::XyzToLab(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | |||
333 | { | |||
334 | icFloatNumber XYZ[3]; | |||
335 | ||||
336 | ||||
337 | if (!bNoClip) { | |||
338 | XYZ[0] = UnitClip(Src[0]); | |||
339 | XYZ[1] = UnitClip(Src[1]); | |||
340 | XYZ[2] = UnitClip(Src[2]); | |||
341 | } | |||
342 | else { | |||
343 | XYZ[0] = Src[0]; | |||
344 | XYZ[1] = Src[1]; | |||
345 | XYZ[2] = Src[2]; | |||
346 | } | |||
347 | ||||
348 | icXyzFromPcs(XYZ); | |||
349 | ||||
350 | icXYZtoLab(XYZ); | |||
351 | ||||
352 | icLabToPcs(XYZ); | |||
353 | ||||
354 | if (!bNoClip) { | |||
355 | Dst[0] = UnitClip(XYZ[0]); | |||
356 | Dst[1] = UnitClip(XYZ[1]); | |||
357 | Dst[2] = UnitClip(XYZ[2]); | |||
358 | } | |||
359 | else { | |||
360 | Dst[0] = XYZ[0]; | |||
361 | Dst[1] = XYZ[1]; | |||
362 | Dst[2] = XYZ[2]; | |||
363 | } | |||
364 | } | |||
365 | ||||
366 | ||||
367 | /** | |||
368 | ************************************************************************** | |||
369 | * Name: CIccPCS::Lab2ToXyz | |||
370 | * | |||
371 | * Purpose: | |||
372 | * Convert version 2 Lab to XYZ | |||
373 | ************************************************************************** | |||
374 | */ | |||
375 | void CIccPCS::Lab2ToXyz(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | |||
376 | { | |||
377 | Lab2ToLab4(Dst, Src, bNoClip); | |||
378 | LabToXyz(Dst, Dst, bNoClip); | |||
379 | } | |||
380 | ||||
381 | ||||
382 | /** | |||
383 | ************************************************************************** | |||
384 | * Name: CIccPCS::XyzToLab2 | |||
385 | * | |||
386 | * Purpose: | |||
387 | * Convert XYZ to version 2 Lab | |||
388 | ************************************************************************** | |||
389 | */ | |||
390 | void CIccPCS::XyzToLab2(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | |||
391 | { | |||
392 | XyzToLab(Dst, Src, bNoClip); | |||
393 | Lab4ToLab2(Dst, Dst); | |||
394 | } | |||
395 | ||||
396 | ||||
397 | /** | |||
398 | ************************************************************************** | |||
399 | * Name: CIccPCS::Lab2ToLab4 | |||
400 | * | |||
401 | * Purpose: | |||
402 | * Convert version 2 Lab to version 4 Lab | |||
403 | ************************************************************************** | |||
404 | */ | |||
405 | void CIccPCS::Lab2ToLab4(icFloatNumber *Dst, const icFloatNumber *Src, bool bNoClip) | |||
406 | { | |||
407 | if (bNoClip) { | |||
408 | Dst[0] = (icFloatNumber)(Src[0] * 65535.0f / 65280.0f); | |||
409 | Dst[1] = (icFloatNumber)(Src[1] * 65535.0f / 65280.0f); | |||
410 | Dst[2] = (icFloatNumber)(Src[2] * 65535.0f / 65280.0f); | |||
411 | } | |||
412 | else { | |||
413 | Dst[0] = UnitClip((icFloatNumber)(Src[0] * 65535.0f / 65280.0f)); | |||
414 | Dst[1] = UnitClip((icFloatNumber)(Src[1] * 65535.0f / 65280.0f)); | |||
415 | Dst[2] = UnitClip((icFloatNumber)(Src[2] * 65535.0f / 65280.0f)); | |||
416 | } | |||
417 | } | |||
418 | ||||
419 | /** | |||
420 | ************************************************************************** | |||
421 | * Name: CIccPCS::Lab4ToLab2 | |||
422 | * | |||
423 | * Purpose: | |||
424 | * Convert version 4 Lab to version 2 Lab | |||
425 | ************************************************************************** | |||
426 | */ | |||
427 | void CIccPCS::Lab4ToLab2(icFloatNumber *Dst, const icFloatNumber *Src) | |||
428 | { | |||
429 | Dst[0] = (icFloatNumber)(Src[0] * 65280.0f / 65535.0f); | |||
430 | Dst[1] = (icFloatNumber)(Src[1] * 65280.0f / 65535.0f); | |||
431 | Dst[2] = (icFloatNumber)(Src[2] * 65280.0f / 65535.0f); | |||
432 | } | |||
433 | ||||
434 | /** | |||
435 | ************************************************************************** | |||
436 | * Name: CIccCreateXformHintManager::CIccCreateXformHintManager | |||
437 | * | |||
438 | * Purpose: | |||
439 | * Destructor | |||
440 | ************************************************************************** | |||
441 | */ | |||
442 | CIccCreateXformHintManager::~CIccCreateXformHintManager() | |||
443 | { | |||
444 | if (m_pList) { | |||
445 | IIccCreateXformHintList::iterator i; | |||
446 | ||||
447 | for (i=m_pList->begin(); i!=m_pList->end(); i++) { | |||
448 | if (i->ptr) | |||
449 | delete i->ptr; | |||
450 | } | |||
451 | ||||
452 | delete m_pList; | |||
453 | } | |||
454 | } | |||
455 | ||||
456 | /** | |||
457 | ************************************************************************** | |||
458 | * Name: CIccCreateXformHintManager::AddHint | |||
459 | * | |||
460 | * Purpose: | |||
461 | * Adds and owns the passed named hint to it's list. | |||
462 | * | |||
463 | * Args: | |||
464 | * pHint = pointer to the hint object to be added | |||
465 | * | |||
466 | * Return: | |||
467 | * true = hint added to the list | |||
468 | * false = hint not added | |||
469 | ************************************************************************** | |||
470 | */ | |||
471 | bool CIccCreateXformHintManager::AddHint(IIccCreateXformHint* pHint) | |||
472 | { | |||
473 | if (!m_pList) { | |||
474 | m_pList = new IIccCreateXformHintList; | |||
475 | } | |||
476 | ||||
477 | if (pHint) { | |||
478 | if (GetHint(pHint->GetHintType())) { | |||
479 | delete pHint; | |||
480 | return false; | |||
481 | } | |||
482 | IIccCreateXformHintPtr Hint; | |||
483 | Hint.ptr = pHint; | |||
484 | m_pList->push_back(Hint); | |||
485 | return true; | |||
486 | } | |||
487 | ||||
488 | return false; | |||
489 | } | |||
490 | ||||
491 | /** | |||
492 | ************************************************************************** | |||
493 | * Name: CIccCreateXformHintManager::DeleteHint | |||
494 | * | |||
495 | * Purpose: | |||
496 | * Deletes the object referenced by the passed named hint pointer | |||
497 | * and removes it from the list. | |||
498 | * | |||
499 | * Args: | |||
500 | * pHint = pointer to the hint object to be deleted | |||
501 | * | |||
502 | * Return: | |||
503 | * true = hint found and deleted | |||
504 | * false = hint not found | |||
505 | ************************************************************************** | |||
506 | */ | |||
507 | bool CIccCreateXformHintManager::DeleteHint(IIccCreateXformHint* pHint) | |||
508 | { | |||
509 | if (m_pList && pHint) { | |||
510 | IIccCreateXformHintList::iterator i; | |||
511 | for (i=m_pList->begin(); i!=m_pList->end(); i++) { | |||
512 | if (i->ptr) { | |||
513 | if (i->ptr == pHint) { | |||
514 | delete pHint; | |||
515 | pHint = NULL__null; | |||
516 | m_pList->erase(i); | |||
517 | return true; | |||
518 | } | |||
519 | } | |||
520 | } | |||
521 | } | |||
522 | ||||
523 | return false; | |||
524 | } | |||
525 | ||||
526 | /** | |||
527 | ************************************************************************** | |||
528 | * Name: CIccCreateXformHintManager::GetHint | |||
529 | * | |||
530 | * Purpose: | |||
531 | * Finds and returns a pointer to the named hint. | |||
532 | * | |||
533 | * Args: | |||
534 | * hintName = name of the desired hint | |||
535 | * | |||
536 | * Return: | |||
537 | * Appropriate IIccCreateXformHint pointer | |||
538 | ************************************************************************** | |||
539 | */ | |||
540 | IIccCreateXformHint* CIccCreateXformHintManager::GetHint(const char* hintName) | |||
541 | { | |||
542 | IIccCreateXformHint* pHint=NULL__null; | |||
543 | ||||
544 | if (m_pList) { | |||
545 | IIccCreateXformHintList::iterator i; | |||
546 | for (i=m_pList->begin(); i!=m_pList->end(); i++) { | |||
547 | if (i->ptr) { | |||
548 | if (!strcmp(i->ptr->GetHintType(), hintName)) { | |||
549 | pHint = i->ptr; | |||
550 | break; | |||
551 | } | |||
552 | } | |||
553 | } | |||
554 | } | |||
555 | ||||
556 | return pHint; | |||
557 | } | |||
558 | ||||
559 | /** | |||
560 | ************************************************************************** | |||
561 | * Name: CIccXform::CIccXform | |||
562 | * | |||
563 | * Purpose: | |||
564 | * Constructor | |||
565 | ************************************************************************** | |||
566 | */ | |||
567 | CIccXform::CIccXform() | |||
568 | { | |||
569 | m_pProfile = NULL__null; | |||
570 | m_bInput = true; | |||
571 | m_nIntent = icUnknownIntent((icRenderingIntent) 0x3f3f3f3f); | |||
572 | m_pAdjustPCS = NULL__null; | |||
573 | m_bAdjustPCS = false; | |||
574 | m_bAbsToRel = false; | |||
575 | m_nMCS = icNoMCS; | |||
576 | m_bUseSpectralPCS = false; | |||
577 | m_bSrcPcsConversion = true; | |||
578 | m_bDstPcsConversion = true; | |||
579 | m_pConnectionConditions = NULL__null; | |||
580 | m_pCmmEnvVarLookup = NULL__null; | |||
581 | } | |||
582 | ||||
583 | ||||
584 | /** | |||
585 | ************************************************************************** | |||
586 | * Name: CIccXform::~CIccXform | |||
587 | * | |||
588 | * Purpose: | |||
589 | * Destructor | |||
590 | ************************************************************************** | |||
591 | */ | |||
592 | CIccXform::~CIccXform() | |||
593 | { | |||
594 | if (m_pProfile) | |||
595 | delete m_pProfile; | |||
596 | ||||
597 | if (m_pAdjustPCS) { | |||
598 | delete m_pAdjustPCS; | |||
599 | } | |||
600 | ||||
601 | if (m_pCmmEnvVarLookup) { | |||
602 | delete m_pCmmEnvVarLookup; | |||
603 | } | |||
604 | ||||
605 | } | |||
606 | ||||
607 | ||||
608 | void CIccXform::DetachAll() | |||
609 | { | |||
610 | m_pProfile = NULL__null; | |||
611 | m_pConnectionConditions = NULL__null; | |||
612 | } | |||
613 | ||||
614 | /** | |||
615 | ************************************************************************** | |||
616 | * Name: CIccXform::Create | |||
617 | * | |||
618 | * Purpose: | |||
619 | * This is a static Creation function that creates derived CIccXform objects and | |||
620 | * initializes them. | |||
621 | * | |||
622 | * Args: | |||
623 | * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will | |||
624 | * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile | |||
625 | * object needs to be allocated on the heap. | |||
626 | * bInput = flag to indicate whether to use the input or output side of the profile, | |||
627 | * nIntent = the rendering intent to apply to the profile, | |||
628 | * nInterp = the interpolation algorithm to use for N-D luts. | |||
629 | * nLutType = selection of which transform lut to use | |||
630 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | |||
631 | * pHintManager = pointer to object that contains xform creation hints | |||
632 | * | |||
633 | * Return: | |||
634 | * A suitable pXform object | |||
635 | ************************************************************************** | |||
636 | */ | |||
637 | CIccXform *CIccXform::Create(CIccProfile *pProfile, | |||
638 | bool bInput/* =true */, | |||
639 | icRenderingIntent nIntent/* =icUnknownIntent */, | |||
640 | icXformInterp nInterp/* =icInterpLinear */, | |||
641 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
642 | icXformLutType nLutType/* =icXformLutColor */, | |||
643 | bool bUseD2BTags/* =true */, CIccCreateXformHintManager *pHintManager/* =NULL */) | |||
644 | { | |||
645 | CIccXform *rv = NULL__null; | |||
646 | icRenderingIntent nTagIntent = nIntent; | |||
647 | bool bUseSpectralPCS = false; | |||
648 | bool bAbsToRel = false; | |||
649 | bool bRelToAbs = false; | |||
650 | icMCSConnectionType nMCS = icNoMCS; | |||
651 | icXformLutType nUseLutType = nLutType; | |||
652 | bool bUseColorimeticTags = true; | |||
653 | ||||
654 | if (nLutType == icXformLutSpectral) { | |||
655 | nUseLutType = icXformLutColor; | |||
656 | bUseD2BTags = true; | |||
657 | bUseColorimeticTags = false; | |||
658 | } | |||
659 | else if (nLutType == icXformLutColorimetric) { | |||
660 | nUseLutType = icXformLutColor; | |||
661 | } | |||
662 | ||||
663 | if (pProfile->m_Header.deviceClass==icSigColorEncodingClass) { | |||
664 | CIccProfile *pEncProfile; | |||
665 | if (icConvertEncodingProfile(pEncProfile, pProfile)!=icEncConvertOk) | |||
666 | return NULL__null; | |||
667 | delete pProfile; | |||
668 | pProfile = pEncProfile; | |||
669 | } | |||
670 | if (pProfile->m_Header.deviceClass==icSigLinkClass/* && nIntent==icAbsoluteColorimetric*/) { | |||
671 | nIntent = icPerceptual; | |||
672 | } | |||
673 | ||||
674 | if (nTagIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | |||
675 | nTagIntent = icPerceptual; | |||
676 | ||||
677 | switch (nUseLutType) { | |||
678 | case icXformLutColor: | |||
679 | if (bInput) { | |||
680 | CIccTag *pTag = NULL__null; | |||
681 | if (bUseD2BTags) { | |||
682 | if (pProfile->m_Header.spectralPCS && nLutType!=icXformLutColorimetric) { | |||
683 | pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); | |||
684 | ||||
685 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
686 | pTag = pProfile->FindTag(icSigDToB1Tag); | |||
687 | if (pTag) | |||
688 | nTagIntent = icRelativeColorimetric; | |||
689 | } | |||
690 | else if (!pTag && nTagIntent == icRelativeColorimetric) { | |||
691 | pTag = pProfile->FindTag(icSigDToB3Tag); | |||
692 | if (pTag) { | |||
693 | nTagIntent = icAbsoluteColorimetric; | |||
694 | bAbsToRel = true; | |||
695 | } | |||
696 | } | |||
697 | ||||
698 | if (pTag) | |||
699 | bUseSpectralPCS = true; | |||
700 | ||||
701 | if (!pTag) { | |||
702 | pTag = pProfile->FindTag(icSigDToB0Tag); | |||
703 | } | |||
704 | if (!pTag) { | |||
705 | pTag = pProfile->FindTag(icSigDToB1Tag); | |||
706 | } | |||
707 | if (!pTag) { | |||
708 | pTag = pProfile->FindTag(icSigDToB3Tag); | |||
709 | if (pTag) { | |||
710 | nTagIntent = icAbsoluteColorimetric; | |||
711 | bAbsToRel = true; | |||
712 | } | |||
713 | } | |||
714 | } | |||
715 | else if (pProfile->m_Header.version < icVersionNumberV50x05000000) { | |||
716 | pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); | |||
717 | ||||
718 | if (!pTag && nTagIntent ==icAbsoluteColorimetric) { | |||
719 | pTag = pProfile->FindTag(icSigDToB1Tag); | |||
720 | if (pTag) | |||
721 | nTagIntent = icRelativeColorimetric; | |||
722 | } | |||
723 | ||||
724 | //Apparently Using DtoB0 is not prescribed here by the v4 ICC Specification | |||
725 | if (!pTag && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | |||
726 | pTag = pProfile->FindTag(icSigDToB0Tag); | |||
727 | } | |||
728 | } | |||
729 | } | |||
730 | ||||
731 | if (bUseColorimeticTags) { | |||
732 | if (!pTag) { | |||
733 | pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent); | |||
734 | } | |||
735 | ||||
736 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
737 | pTag = pProfile->FindTag(icSigAToB1Tag); | |||
738 | if (pTag) | |||
739 | nTagIntent = icRelativeColorimetric; | |||
740 | } | |||
741 | else if (!pTag && nTagIntent == icRelativeColorimetric) { | |||
742 | pTag = pProfile->FindTag(icSigAToB3Tag); | |||
743 | if (pTag) { | |||
744 | nTagIntent = icAbsoluteColorimetric; | |||
745 | bAbsToRel = true; | |||
746 | } | |||
747 | } | |||
748 | ||||
749 | if (!pTag) { | |||
750 | pTag = pProfile->FindTag(icSigAToB0Tag); | |||
751 | } | |||
752 | if (!pTag) { | |||
753 | pTag = pProfile->FindTag(icSigAToB1Tag); | |||
754 | } | |||
755 | if (!pTag) { | |||
756 | pTag = pProfile->FindTag(icSigAToB3Tag); | |||
757 | if (pTag) { | |||
758 | nTagIntent = icAbsoluteColorimetric; | |||
759 | bAbsToRel = true; | |||
760 | } | |||
761 | } | |||
762 | } | |||
763 | ||||
764 | //Unsupported elements cause fall back behavior | |||
765 | if (pTag && !pTag->IsSupported()) | |||
766 | pTag = NULL__null; | |||
767 | ||||
768 | if (!pTag) { | |||
769 | if (pProfile->m_Header.version < icVersionNumberV50x05000000) { | |||
770 | //Matrix/TRC profiles are deprecated in v5 profiles | |||
771 | if (pProfile->m_Header.colorSpace == icSigRgbData) { | |||
772 | rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, NULL__null, pHintManager); | |||
773 | } | |||
774 | else if (pProfile->m_Header.colorSpace == icSigGrayData) { | |||
775 | rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL__null, pHintManager); | |||
776 | } | |||
777 | else | |||
778 | return NULL__null; | |||
779 | } | |||
780 | else | |||
781 | return NULL__null; | |||
782 | } | |||
783 | else if (pTag->GetType()==icSigMultiProcessElementType) { | |||
784 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | |||
785 | } | |||
786 | else { | |||
787 | switch(pProfile->m_Header.colorSpace) { | |||
788 | case icSigXYZData: | |||
789 | case icSigLabData: | |||
790 | case icSigLuvData: | |||
791 | case icSigYCbCrData: | |||
792 | case icSigYxyData: | |||
793 | case icSigRgbData: | |||
794 | case icSigHsvData: | |||
795 | case icSigHlsData: | |||
796 | case icSigCmyData: | |||
797 | case icSig3colorData: | |||
798 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | |||
799 | break; | |||
800 | ||||
801 | case icSigCmykData: | |||
802 | case icSig4colorData: | |||
803 | rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager); | |||
804 | break; | |||
805 | ||||
806 | default: | |||
807 | rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager); | |||
808 | break; | |||
809 | } | |||
810 | } | |||
811 | } | |||
812 | else { | |||
813 | CIccTag *pTag = NULL__null; | |||
814 | ||||
815 | if (nLutType == icXformLutColorimetric && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | |||
816 | bUseD2BTags = false; | |||
817 | } | |||
818 | ||||
819 | if (bUseD2BTags) { | |||
820 | pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent); | |||
821 | ||||
822 | //Additional precedence not prescribed by the v4 ICC Specification | |||
823 | if (!pTag && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | |||
824 | pTag = pProfile->FindTag(icSigBToD0Tag); | |||
825 | ||||
826 | if (!pTag) { | |||
827 | pTag = pProfile->FindTag(icSigBToD1Tag); | |||
828 | if (pTag) { | |||
829 | nTagIntent = icRelativeColorimetric; | |||
830 | if (nTagIntent==icAbsoluteColorimetric) | |||
831 | bRelToAbs = true; | |||
832 | } | |||
833 | } | |||
834 | ||||
835 | if (!pTag) { | |||
836 | pTag = pProfile->FindTag(icSigBToD3Tag); | |||
837 | if (pTag) { | |||
838 | nTagIntent = icAbsoluteColorimetric; | |||
839 | bAbsToRel = true; | |||
840 | } | |||
841 | } | |||
842 | } | |||
843 | ||||
844 | //Unsupported elements cause fall back behavior | |||
845 | if (pTag && !pTag->IsSupported()) | |||
846 | pTag = NULL__null; | |||
847 | ||||
848 | if (pTag) | |||
849 | bUseSpectralPCS = true; | |||
850 | ||||
851 | if (!pTag && nTagIntent == icAbsoluteColorimetric && pProfile->m_Header.version < icVersionNumberV50x05000000) { | |||
852 | pTag = pProfile->FindTag(icSigBToD1Tag); | |||
853 | ||||
854 | //Unsupported elements cause fall back behavior | |||
855 | if (pTag && !pTag->IsSupported()) | |||
856 | pTag = NULL__null; | |||
857 | ||||
858 | if (pTag) | |||
859 | nTagIntent = icRelativeColorimetric; | |||
860 | } | |||
861 | } | |||
862 | ||||
863 | if (bUseColorimeticTags) { | |||
864 | ||||
865 | if (!pTag) { | |||
866 | pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent); | |||
867 | } | |||
868 | ||||
869 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
870 | pTag = pProfile->FindTag(icSigBToA1Tag); | |||
871 | if (pTag) | |||
872 | nTagIntent = icRelativeColorimetric; | |||
873 | } | |||
874 | ||||
875 | if (!pTag) { | |||
876 | pTag = pProfile->FindTag(icSigBToA0Tag); | |||
877 | } | |||
878 | ||||
879 | //Additional precedence not prescribed by the v4 ICC Specification | |||
880 | if (!pTag && pProfile->m_Header.version >= icVersionNumberV50x05000000) { | |||
881 | ||||
882 | pTag = pProfile->FindTag(icSigBToA1Tag); | |||
883 | if (pTag) { | |||
884 | nTagIntent = icRelativeColorimetric; | |||
885 | if (nTagIntent == icAbsoluteColorimetric) | |||
886 | bRelToAbs = true; | |||
887 | } | |||
888 | ||||
889 | if (!pTag) { | |||
890 | pTag = pProfile->FindTag(icSigBToA3Tag); | |||
891 | if (pTag) { | |||
892 | nTagIntent = icAbsoluteColorimetric; | |||
893 | bAbsToRel = true; | |||
894 | } | |||
895 | } | |||
896 | } | |||
897 | } | |||
898 | ||||
899 | if (!pTag) { | |||
900 | if (pProfile->m_Header.version < icVersionNumberV50x05000000) { | |||
901 | if (pProfile->m_Header.colorSpace == icSigRgbData) { | |||
902 | rv = CIccXformCreator::CreateXform(icXformTypeMatrixTRC, pTag, pHintManager); | |||
903 | } | |||
904 | else if (pProfile->m_Header.colorSpace == icSigGrayData) { | |||
905 | rv = CIccXformCreator::CreateXform(icXformTypeMonochrome, NULL__null, pHintManager); | |||
906 | } | |||
907 | else | |||
908 | return NULL__null; | |||
909 | } | |||
910 | else | |||
911 | return NULL__null; | |||
912 | } | |||
913 | else if (pTag->GetType()==icSigMultiProcessElementType) { | |||
914 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | |||
915 | } | |||
916 | else { | |||
917 | switch(pProfile->m_Header.pcs) { | |||
918 | case icSigXYZData: | |||
919 | case icSigLabData: | |||
920 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | |||
921 | break; | |||
922 | ||||
923 | default: | |||
924 | break; | |||
925 | } | |||
926 | } | |||
927 | } | |||
928 | break; | |||
929 | ||||
930 | case icXformLutNamedColor: | |||
931 | { | |||
932 | CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); | |||
933 | if (!pTag) | |||
934 | return NULL__null; | |||
935 | ||||
936 | CIccCreateNamedColorXformHint* pNamedColorHint = new CIccCreateNamedColorXformHint(); | |||
937 | pNamedColorHint->csPcs = pProfile->m_Header.pcs; | |||
938 | pNamedColorHint->csDevice = pProfile->m_Header.colorSpace; | |||
939 | pNamedColorHint->csSpectralPcs = pProfile->m_Header.spectralPCS; | |||
940 | pNamedColorHint->spectralRange = pProfile->m_Header.spectralRange; | |||
941 | pNamedColorHint->biSpectralRange = pProfile->m_Header.biSpectralRange; | |||
942 | if (pHintManager) { | |||
943 | pHintManager->AddHint(pNamedColorHint); | |||
944 | rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, pHintManager); | |||
945 | pHintManager->DeleteHint(pNamedColorHint); | |||
946 | } | |||
947 | else { | |||
948 | CIccCreateXformHintManager HintManager; | |||
949 | HintManager.AddHint(pNamedColorHint); | |||
950 | rv = CIccXformCreator::CreateXform(icXformTypeNamedColor, pTag, &HintManager); | |||
951 | } | |||
952 | ||||
953 | if (pProfile->m_Header.spectralPCS) | |||
954 | bUseSpectralPCS = true; | |||
955 | } | |||
956 | break; | |||
957 | ||||
958 | case icXformLutPreview: | |||
959 | { | |||
960 | bInput = false; | |||
961 | CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent); | |||
962 | if (!pTag) { | |||
963 | pTag = pProfile->FindTag(icSigPreview0Tag); | |||
964 | } | |||
965 | if (!pTag) { | |||
966 | return NULL__null; | |||
967 | } | |||
968 | else { | |||
969 | switch(pProfile->m_Header.pcs) { | |||
970 | case icSigXYZData: | |||
971 | case icSigLabData: | |||
972 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | |||
973 | ||||
974 | default: | |||
975 | break; | |||
976 | } | |||
977 | } | |||
978 | } | |||
979 | break; | |||
980 | ||||
981 | case icXformLutGamut: | |||
982 | { | |||
983 | bInput = false; | |||
984 | CIccTag *pTag = pProfile->FindTag(icSigGamutTag); | |||
985 | if (!pTag) { | |||
986 | return NULL__null; | |||
987 | } | |||
988 | else { | |||
989 | switch(pProfile->m_Header.pcs) { | |||
990 | case icSigXYZData: | |||
991 | case icSigLabData: | |||
992 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | |||
993 | ||||
994 | default: | |||
995 | break; | |||
996 | } | |||
997 | } | |||
998 | } | |||
999 | break; | |||
1000 | ||||
1001 | case icXformLutBRDFParam: | |||
1002 | { | |||
1003 | // get the correct tag first | |||
1004 | ||||
1005 | CIccTag *pTag = NULL__null; | |||
1006 | if (bUseD2BTags) { | |||
1007 | if (pProfile->m_Header.spectralPCS) { | |||
1008 | ||||
1009 | pTag = pProfile->FindTag(icSigBrdfSpectralParameter0Tag + nTagIntent); | |||
1010 | ||||
1011 | if (pTag) | |||
1012 | bUseSpectralPCS = true; | |||
1013 | } | |||
1014 | } | |||
1015 | else | |||
1016 | { | |||
1017 | pTag = pProfile->FindTag(icSigBrdfColorimetricParameter0Tag + nTagIntent); | |||
1018 | ||||
1019 | //Unsupported elements cause fall back behavior | |||
1020 | if (pTag && !pTag->IsSupported()) | |||
1021 | pTag = NULL__null; | |||
1022 | } | |||
1023 | ||||
1024 | // now extract the correct part from the structure | |||
1025 | CIccStructBRDF* pStructTag = dynamic_cast<CIccStructBRDF*>(pTag); | |||
1026 | ||||
1027 | if (pStructTag != NULL__null) | |||
1028 | { | |||
1029 | CIccTag *pTag2 = NULL__null; | |||
1030 | ||||
1031 | switch (nLutType) { | |||
1032 | case icXformLutBRDFParam: | |||
1033 | pTag2 = pStructTag->GetElem(icSigBrdfTransformMbr); | |||
1034 | break; | |||
1035 | default: | |||
1036 | // can't get here, get rid of warning | |||
1037 | break; | |||
1038 | } | |||
1039 | if (pTag2) | |||
1040 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag2, pHintManager); | |||
1041 | } | |||
1042 | } | |||
1043 | break; | |||
1044 | ||||
1045 | case icXformLutBRDFDirect: | |||
1046 | { | |||
1047 | // get the correct tag first | |||
1048 | ||||
1049 | CIccTag *pTag = NULL__null; | |||
1050 | if (bUseD2BTags) { | |||
1051 | if (pProfile->m_Header.spectralPCS) { | |||
1052 | ||||
1053 | pTag = pProfile->FindTag(icSigBRDFDToB0Tag + nTagIntent); | |||
1054 | ||||
1055 | if (pTag) | |||
1056 | bUseSpectralPCS = true; | |||
1057 | } | |||
1058 | } | |||
1059 | else | |||
1060 | { | |||
1061 | pTag = pProfile->FindTag(icSigBRDFAToB0Tag + nTagIntent); | |||
1062 | ||||
1063 | //Unsupported elements cause fall back behavior | |||
1064 | if (pTag && !pTag->IsSupported()) | |||
1065 | pTag = NULL__null; | |||
1066 | } | |||
1067 | ||||
1068 | if (pTag != NULL__null) | |||
1069 | { | |||
1070 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | |||
1071 | } | |||
1072 | } | |||
1073 | break; | |||
1074 | ||||
1075 | case icXformLutBRDFMcsParam: | |||
1076 | { | |||
1077 | CIccTag *pTag = NULL__null; | |||
1078 | if (pProfile->m_Header.deviceClass == icSigMaterialVisualizationClass) { | |||
1079 | bInput = true; | |||
1080 | nMCS = icFromMCS; | |||
1081 | ||||
1082 | if (pProfile->m_Header.spectralPCS) { | |||
1083 | pTag = pProfile->FindTag(icSigBRDFMToS0Tag + nTagIntent); | |||
1084 | ||||
1085 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
1086 | pTag = pProfile->FindTag(icSigBRDFMToS1Tag); | |||
1087 | if (pTag) | |||
1088 | nTagIntent = icRelativeColorimetric; | |||
1089 | } | |||
1090 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | |||
1091 | pTag = pProfile->FindTag(icSigBRDFMToS3Tag); | |||
1092 | if (pTag) { | |||
1093 | nTagIntent = icAbsoluteColorimetric; | |||
1094 | bAbsToRel = true; | |||
1095 | } | |||
1096 | } | |||
1097 | ||||
1098 | if (!pTag) { | |||
1099 | pTag = pProfile->FindTag(icSigBRDFMToS0Tag); | |||
1100 | } | |||
1101 | if (!pTag) { | |||
1102 | pTag = pProfile->FindTag(icSigBRDFMToS1Tag); | |||
1103 | } | |||
1104 | if (!pTag) { | |||
1105 | pTag = pProfile->FindTag(icSigBRDFMToS3Tag); | |||
1106 | if (pTag) { | |||
1107 | nTagIntent = icAbsoluteColorimetric; | |||
1108 | bAbsToRel = true; | |||
1109 | } | |||
1110 | } | |||
1111 | ||||
1112 | if (pTag) | |||
1113 | bUseSpectralPCS = true; | |||
1114 | } | |||
1115 | if (!pTag && pProfile->m_Header.pcs != 0) { | |||
1116 | pTag = pProfile->FindTag(icSigBRDFMToB0Tag + nTagIntent); | |||
1117 | ||||
1118 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
1119 | pTag = pProfile->FindTag(icSigBRDFMToB1Tag); | |||
1120 | if (pTag) | |||
1121 | nTagIntent = icRelativeColorimetric; | |||
1122 | } | |||
1123 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | |||
1124 | pTag = pProfile->FindTag(icSigBRDFMToB3Tag); | |||
1125 | if (pTag) { | |||
1126 | nTagIntent = icAbsoluteColorimetric; | |||
1127 | bAbsToRel = true; | |||
1128 | } | |||
1129 | } | |||
1130 | if (!pTag) { | |||
1131 | pTag = pProfile->FindTag(icSigBRDFMToB0Tag); | |||
1132 | } | |||
1133 | if (!pTag) { | |||
1134 | pTag = pProfile->FindTag(icSigBRDFMToB1Tag); | |||
1135 | } | |||
1136 | if (!pTag) { | |||
1137 | pTag = pProfile->FindTag(icSigBRDFMToB3Tag); | |||
1138 | if (pTag) { | |||
1139 | nTagIntent = icAbsoluteColorimetric; | |||
1140 | bAbsToRel = true; | |||
1141 | } | |||
1142 | } | |||
1143 | } | |||
1144 | ||||
1145 | //Unsupported elements cause fall back behavior | |||
1146 | if (pTag && !pTag->IsSupported()) | |||
1147 | pTag = NULL__null; | |||
1148 | ||||
1149 | //Unsupported elements cause fall back behavior | |||
1150 | if (pTag && !pTag->IsSupported()) | |||
1151 | pTag = NULL__null; | |||
1152 | } | |||
1153 | if (pTag && pProfile->m_Header.mcs) { | |||
1154 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | |||
1155 | } | |||
1156 | else | |||
1157 | rv = NULL__null; | |||
1158 | } | |||
1159 | break; | |||
1160 | ||||
1161 | case icXformLutMCS: | |||
1162 | { | |||
1163 | CIccTag *pTag = NULL__null; | |||
1164 | if (pProfile->m_Header.deviceClass==icSigMaterialIdentificationClass || | |||
1165 | pProfile->m_Header.deviceClass==icSigInputClass) { | |||
1166 | bInput = true; | |||
1167 | nMCS = icToMCS; | |||
1168 | pTag = pProfile->FindTag(icSigAToM0Tag); | |||
1169 | } | |||
1170 | else if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) { | |||
1171 | bInput = true; | |||
1172 | nMCS = icFromMCS; | |||
1173 | ||||
1174 | if (pProfile->m_Header.spectralPCS) { | |||
1175 | pTag = pProfile->FindTag(icSigMToS0Tag + nTagIntent); | |||
1176 | ||||
1177 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
1178 | pTag = pProfile->FindTag(icSigMToS1Tag); | |||
1179 | if (pTag) | |||
1180 | nTagIntent = icRelativeColorimetric; | |||
1181 | } | |||
1182 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | |||
1183 | pTag = pProfile->FindTag(icSigMToS3Tag); | |||
1184 | if (pTag) { | |||
1185 | nTagIntent = icAbsoluteColorimetric; | |||
1186 | bAbsToRel = true; | |||
1187 | } | |||
1188 | } | |||
1189 | ||||
1190 | if (!pTag) { | |||
1191 | pTag = pProfile->FindTag(icSigMToS0Tag); | |||
1192 | } | |||
1193 | if (!pTag) { | |||
1194 | pTag = pProfile->FindTag(icSigMToS1Tag); | |||
1195 | } | |||
1196 | if (!pTag) { | |||
1197 | pTag = pProfile->FindTag(icSigMToS3Tag); | |||
1198 | if (pTag) { | |||
1199 | nTagIntent = icAbsoluteColorimetric; | |||
1200 | bAbsToRel = true; | |||
1201 | } | |||
1202 | } | |||
1203 | ||||
1204 | if (pTag) | |||
1205 | bUseSpectralPCS = true; | |||
1206 | } | |||
1207 | if (!pTag && pProfile->m_Header.pcs!=0) { | |||
1208 | pTag = pProfile->FindTag(icSigMToB0Tag + nTagIntent); | |||
1209 | ||||
1210 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
1211 | pTag = pProfile->FindTag(icSigMToB1Tag); | |||
1212 | if (pTag) | |||
1213 | nTagIntent = icRelativeColorimetric; | |||
1214 | } | |||
1215 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | |||
1216 | pTag = pProfile->FindTag(icSigMToB3Tag); | |||
1217 | if (pTag) { | |||
1218 | nTagIntent = icAbsoluteColorimetric; | |||
1219 | bAbsToRel = true; | |||
1220 | } | |||
1221 | } | |||
1222 | ||||
1223 | if (!pTag) { | |||
1224 | pTag = pProfile->FindTag(icSigMToB0Tag); | |||
1225 | } | |||
1226 | if (!pTag) { | |||
1227 | pTag = pProfile->FindTag(icSigMToB1Tag); | |||
1228 | } | |||
1229 | if (!pTag) { | |||
1230 | pTag = pProfile->FindTag(icSigMToB3Tag); | |||
1231 | if (pTag) { | |||
1232 | nTagIntent = icAbsoluteColorimetric; | |||
1233 | bAbsToRel = true; | |||
1234 | } | |||
1235 | } | |||
1236 | } | |||
1237 | ||||
1238 | //Unsupported elements cause fall back behavior | |||
1239 | if (pTag && !pTag->IsSupported()) | |||
1240 | pTag = NULL__null; | |||
1241 | } | |||
1242 | else if (pProfile->m_Header.deviceClass==icSigMaterialLinkClass) { | |||
1243 | bInput = false; | |||
1244 | nMCS = icFromMCS; | |||
1245 | pTag = pProfile->FindTag(icSigMToA0Tag); | |||
1246 | } | |||
1247 | if (pTag && pProfile->m_Header.mcs) { | |||
1248 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | |||
1249 | } | |||
1250 | else | |||
1251 | rv = NULL__null; | |||
1252 | } | |||
1253 | break; | |||
1254 | ||||
1255 | } | |||
1256 | ||||
1257 | if (rv) { | |||
1258 | if (pPcc) | |||
1259 | rv->m_pConnectionConditions = pPcc; | |||
1260 | else | |||
1261 | rv->m_pConnectionConditions = pProfile; | |||
1262 | ||||
1263 | rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel, nMCS); | |||
1264 | } | |||
1265 | ||||
1266 | return rv; | |||
1267 | } | |||
1268 | ||||
1269 | /** | |||
1270 | ************************************************************************** | |||
1271 | * Name: CIccXform::Create | |||
1272 | * | |||
1273 | * Purpose: | |||
1274 | * This is a static Creation function that creates derived CIccXform objects and | |||
1275 | * initializes them. | |||
1276 | * | |||
1277 | * Args: | |||
1278 | * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will | |||
1279 | * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile | |||
1280 | * object needs to be allocated on the heap. | |||
1281 | * pTag = tag that specifies transform to use. It is assumed to use colorimetric PCS and have a lut type of icXformLutColor. | |||
1282 | * bInput = flag to indicate whether to use the input or output side of the profile, | |||
1283 | * nIntent = the rendering intent to apply to the profile, | |||
1284 | * nInterp = the interpolation algorithm to use for N-D luts. | |||
1285 | * pPcc = pointer to profile connection conditions to associate with transform | |||
1286 | * pHintManager = pointer to object that contains xform creation hints | |||
1287 | * | |||
1288 | * Return: | |||
1289 | * A suitable pXform object | |||
1290 | ************************************************************************** | |||
1291 | */ | |||
1292 | CIccXform *CIccXform::Create(CIccProfile *pProfile, | |||
1293 | CIccTag *pTag, | |||
1294 | bool bInput/* =true */, | |||
1295 | icRenderingIntent nIntent/* =icUnknownIntent */, | |||
1296 | icXformInterp nInterp/* =icInterpLinear */, | |||
1297 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
1298 | bool bUseSpectralPCS/* =false*/, | |||
1299 | CIccCreateXformHintManager *pHintManager/* =NULL */) | |||
1300 | { | |||
1301 | CIccXform *rv = NULL__null; | |||
1302 | icRenderingIntent nTagIntent = nIntent; | |||
1303 | bool bAbsToRel = false; | |||
1304 | bool bRelToAbs = false; | |||
1305 | icMCSConnectionType nMCS = icNoMCS; | |||
1306 | ||||
1307 | if (pProfile->m_Header.deviceClass == icSigColorEncodingClass) { | |||
1308 | return NULL__null; | |||
1309 | } | |||
1310 | ||||
1311 | if (pProfile->m_Header.deviceClass == icSigLinkClass/* && nIntent==icAbsoluteColorimetric*/) { | |||
1312 | nIntent = icPerceptual; | |||
1313 | } | |||
1314 | ||||
1315 | if (nTagIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | |||
1316 | nTagIntent = icPerceptual; | |||
1317 | ||||
1318 | //Unsupported elements cause fall back behavior | |||
1319 | if (pTag && !pTag->IsSupported()) | |||
1320 | return NULL__null; | |||
1321 | ||||
1322 | if (bInput) { | |||
1323 | if (pTag->GetType() == icSigMultiProcessElementType) { | |||
1324 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | |||
1325 | } | |||
1326 | else { | |||
1327 | switch (pProfile->m_Header.colorSpace) { | |||
1328 | case icSigXYZData: | |||
1329 | case icSigLabData: | |||
1330 | case icSigLuvData: | |||
1331 | case icSigYCbCrData: | |||
1332 | case icSigYxyData: | |||
1333 | case icSigRgbData: | |||
1334 | case icSigHsvData: | |||
1335 | case icSigHlsData: | |||
1336 | case icSigCmyData: | |||
1337 | case icSig3colorData: | |||
1338 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | |||
1339 | break; | |||
1340 | ||||
1341 | case icSigCmykData: | |||
1342 | case icSig4colorData: | |||
1343 | rv = CIccXformCreator::CreateXform(icXformType4DLut, pTag, pHintManager); | |||
1344 | break; | |||
1345 | ||||
1346 | default: | |||
1347 | rv = CIccXformCreator::CreateXform(icXformTypeNDLut, pTag, pHintManager); | |||
1348 | break; | |||
1349 | } | |||
1350 | } | |||
1351 | } | |||
1352 | else { | |||
1353 | if (pTag->GetType() == icSigMultiProcessElementType) { | |||
1354 | rv = CIccXformCreator::CreateXform(icXformTypeMpe, pTag, pHintManager); | |||
1355 | } | |||
1356 | else { | |||
1357 | switch (pProfile->m_Header.pcs) { | |||
1358 | case icSigXYZData: | |||
1359 | case icSigLabData: | |||
1360 | rv = CIccXformCreator::CreateXform(icXformType3DLut, pTag, pHintManager); | |||
1361 | break; | |||
1362 | ||||
1363 | default: | |||
1364 | break; | |||
1365 | } | |||
1366 | } | |||
1367 | } | |||
1368 | ||||
1369 | if (rv) { | |||
1370 | if (pPcc) | |||
1371 | rv->m_pConnectionConditions = pPcc; | |||
1372 | else | |||
1373 | rv->m_pConnectionConditions = pProfile; | |||
1374 | ||||
1375 | rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel, nMCS); | |||
1376 | } | |||
1377 | ||||
1378 | return rv; | |||
1379 | } | |||
1380 | ||||
1381 | /** | |||
1382 | ****************************************************************************** | |||
1383 | * Name: CIccXform::SetParams | |||
1384 | * | |||
1385 | * Purpose: | |||
1386 | * This is an accessor function to set private values. | |||
1387 | * | |||
1388 | * Args: | |||
1389 | * pProfile = pointer to profile associated with transform | |||
1390 | * bInput = indicates whether profile is input profile | |||
1391 | * nIntent = rendering intent to apply to the profile | |||
1392 | * nInterp = the interpolation algorithm to use for N-D luts | |||
1393 | ******************************************************************************/ | |||
1394 | void CIccXform::SetParams(CIccProfile *pProfile, bool bInput, icRenderingIntent nIntent, icRenderingIntent nTagIntent, | |||
1395 | bool bUseSpectralPCS, icXformInterp nInterp, CIccCreateXformHintManager *pHintManager/* =NULL */, | |||
1396 | bool bAbsToRel/*=false*/, icMCSConnectionType nMCS/*=icNoMCS*/) | |||
1397 | { | |||
1398 | m_pProfile = pProfile; | |||
1399 | m_bInput = bInput; | |||
1400 | m_nIntent = nIntent; | |||
1401 | m_nTagIntent = nTagIntent; | |||
1402 | m_nInterp = nInterp; | |||
1403 | m_pAdjustPCS = NULL__null; | |||
1404 | m_bUseSpectralPCS = bUseSpectralPCS; | |||
1405 | m_bAbsToRel = bAbsToRel; | |||
1406 | m_nMCS = nMCS; | |||
1407 | m_bLuminanceMatching = false; | |||
1408 | ||||
1409 | if (pHintManager) { | |||
1410 | IIccCreateXformHint *pHint=NULL__null; | |||
1411 | ||||
1412 | pHint = pHintManager->GetHint("CIccCreateAdjustPCSXformHint"); | |||
1413 | if (pHint) { | |||
1414 | CIccCreateAdjustPCSXformHint *pAdjustPCSHint = (CIccCreateAdjustPCSXformHint*)pHint; | |||
1415 | m_pAdjustPCS = pAdjustPCSHint->GetNewAdjustPCSXform(); | |||
1416 | } | |||
1417 | ||||
1418 | pHint = pHintManager->GetHint("CIccCreateCmmEnvVarXformHint"); | |||
1419 | if (pHint) { | |||
1420 | CIccCreateCmmEnvVarXformHint *pCmmEnvVarHint = (CIccCreateCmmEnvVarXformHint*)pHint; | |||
1421 | m_pCmmEnvVarLookup = pCmmEnvVarHint->GetNewCmmEnvVarLookup(); | |||
1422 | } | |||
1423 | ||||
1424 | pHint = pHintManager->GetHint("CIccLuminanceMatchingHint"); | |||
1425 | if (pHint) { | |||
1426 | m_bLuminanceMatching = true; | |||
1427 | } | |||
1428 | } | |||
1429 | } | |||
1430 | ||||
1431 | /** | |||
1432 | ************************************************************************** | |||
1433 | * Name: CIccXform::Create | |||
1434 | * | |||
1435 | * Purpose: | |||
1436 | * This is a static Creation function that creates derived CIccXform objects and | |||
1437 | * initializes them. | |||
1438 | * | |||
1439 | * Args: | |||
1440 | * Profile = reference to a CIccProfile object that will be used to create the transform. | |||
1441 | * A copy of the CIccProfile object will be created and passed to the pointer based Create(). | |||
1442 | * The copied object will be destroyed when the returned CIccXform object is destroyed. | |||
1443 | * bInput = flag to indicate whether to use the input or output side of the profile, | |||
1444 | * nIntent = the rendering intent to apply to the profile, | |||
1445 | * nInterp = the interpolation algorithm to use for N-D luts. | |||
1446 | * nLutType = selection of which transform lut to use | |||
1447 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | |||
1448 | * pHint = pointer to object passed to CIccXform creation functionality | |||
1449 | * | |||
1450 | * Return: | |||
1451 | * A suitable pXform object | |||
1452 | ************************************************************************** | |||
1453 | */ | |||
1454 | CIccXform *CIccXform::Create(CIccProfile &Profile, | |||
1455 | bool bInput/* =true */, | |||
1456 | icRenderingIntent nIntent/* =icUnknownIntent */, | |||
1457 | icXformInterp nInterp/* =icInterpLinear */, | |||
1458 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
1459 | icXformLutType nLutType/* =icXformLutColor */, | |||
1460 | bool bUseD2BxB2DxTags/* =true */, | |||
1461 | CIccCreateXformHintManager *pHintManager/* =NULL */) | |||
1462 | { | |||
1463 | CIccProfile *pProfile = new CIccProfile(Profile); | |||
1464 | CIccXform *pXform = Create(pProfile, bInput, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | |||
1465 | ||||
1466 | if (!pXform) | |||
1467 | delete pProfile; | |||
1468 | ||||
1469 | return pXform; | |||
1470 | } | |||
1471 | ||||
1472 | ||||
1473 | /** | |||
1474 | ************************************************************************** | |||
1475 | * Name: CIccXform::Begin | |||
1476 | * | |||
1477 | * Purpose: | |||
1478 | * This function will be called before the xform is applied. Derived objects | |||
1479 | * should also call this base class function to initialize for Absolute Colorimetric | |||
1480 | * Intent handling which is performed through the use of the CheckSrcAbs and | |||
1481 | * CheckDstAbs functions. | |||
1482 | ************************************************************************** | |||
1483 | */ | |||
1484 | icStatusCMM CIccXform::Begin() | |||
1485 | { | |||
1486 | IIccProfileConnectionConditions *pCond = GetConnectionConditions(); | |||
1487 | ||||
1488 | icFloatNumber mediaXYZ[3]; | |||
1489 | icFloatNumber illumXYZ[3]; | |||
1490 | ||||
1491 | if (m_nIntent==icAbsoluteColorimetric) { | |||
1492 | if (pCond) { | |||
1493 | pCond->getMediaWhiteXYZ(mediaXYZ); | |||
1494 | ||||
1495 | m_MediaXYZ.X = icFtoF16(mediaXYZ[0]); | |||
1496 | m_MediaXYZ.Y = icFtoF16(mediaXYZ[1]); | |||
1497 | m_MediaXYZ.Z = icFtoF16(mediaXYZ[2]); | |||
1498 | } | |||
1499 | else { | |||
1500 | CIccTag *pTag = m_pProfile->FindTag(icSigMediaWhitePointTag); | |||
1501 | ||||
1502 | if (!pTag || pTag->GetType()!=icSigXYZType) | |||
1503 | return icCmmStatInvalidProfile; | |||
1504 | ||||
1505 | CIccTagXYZ *pXyzTag = (CIccTagXYZ*)pTag; | |||
1506 | ||||
1507 | m_MediaXYZ = (*pXyzTag)[0]; | |||
1508 | mediaXYZ[0] = icFtoD(m_MediaXYZ.X); | |||
1509 | mediaXYZ[1] = icFtoD(m_MediaXYZ.Y); | |||
1510 | mediaXYZ[2] = icFtoD(m_MediaXYZ.Z); | |||
1511 | } | |||
1512 | } | |||
1513 | ||||
1514 | icXYZNumber illXYZ; | |||
1515 | if (pCond) { | |||
1516 | pCond->getNormIlluminantXYZ(illumXYZ); | |||
1517 | illXYZ.X = icDtoF(illumXYZ[0]); | |||
1518 | illXYZ.Y = icDtoF(illumXYZ[1]); | |||
1519 | illXYZ.Z = icDtoF(illumXYZ[2]); | |||
1520 | } | |||
1521 | else { | |||
1522 | illXYZ = m_pProfile->m_Header.illuminant; | |||
1523 | illumXYZ[0] = icFtoD(illXYZ.X); | |||
1524 | illumXYZ[1] = icFtoD(illXYZ.Y); | |||
1525 | illumXYZ[2] = icFtoD(illXYZ.Z); | |||
1526 | } | |||
1527 | ||||
1528 | // set up for any needed PCS adjustment | |||
1529 | if (m_nIntent == icAbsoluteColorimetric && | |||
1530 | (m_MediaXYZ.X != illXYZ.X || | |||
1531 | m_MediaXYZ.Y != illXYZ.Y || | |||
1532 | m_MediaXYZ.Z != illXYZ.Z)) { | |||
1533 | ||||
1534 | icColorSpaceSignature Space = m_pProfile->m_Header.pcs; | |||
1535 | ||||
1536 | if (IsSpacePCS(Space)(((Space)==icSigXYZData || (Space)==icSigLabData) || IsSpaceSpectralPCS (Space))) { | |||
1537 | m_bAdjustPCS = true; // turn ON PCS adjustment | |||
1538 | ||||
1539 | // scale factors depend upon media white point | |||
1540 | // set up for input transform | |||
1541 | if (!m_bInput) { | |||
1542 | m_PCSScale[0] = illumXYZ[0] / mediaXYZ[0]; | |||
1543 | m_PCSScale[1] = illumXYZ[1] / mediaXYZ[1]; | |||
1544 | m_PCSScale[2] = illumXYZ[2] / mediaXYZ[2]; | |||
1545 | } | |||
1546 | else { | |||
1547 | m_PCSScale[0] = mediaXYZ[0] / illumXYZ[0]; | |||
1548 | m_PCSScale[1] = mediaXYZ[1] / illumXYZ[1]; | |||
1549 | m_PCSScale[2] = mediaXYZ[2] / illumXYZ[2]; | |||
1550 | ||||
1551 | } | |||
1552 | ||||
1553 | m_PCSOffset[0] = 0.0; | |||
1554 | m_PCSOffset[1] = 0.0; | |||
1555 | m_PCSOffset[2] = 0.0; | |||
1556 | } | |||
1557 | } | |||
1558 | else if (m_nIntent == icPerceptual && (IsVersion2() || !HasPerceptualHandling())) { | |||
1559 | icColorSpaceSignature Space = m_pProfile->m_Header.pcs; | |||
1560 | ||||
1561 | if (IsSpacePCS(Space)(((Space)==icSigXYZData || (Space)==icSigLabData) || IsSpaceSpectralPCS (Space)) && m_pProfile->m_Header.deviceClass!=icSigAbstractClass) { | |||
1562 | m_bAdjustPCS = true; // turn ON PCS adjustment | |||
1563 | ||||
1564 | // set up for input transform, which needs version 2 black point to version 4 | |||
1565 | m_PCSScale[0] = (icFloatNumber) (1.0 - icPerceptualRefBlackX0.00336 / icPerceptualRefWhiteX0.9642); // scale factors | |||
1566 | m_PCSScale[1] = (icFloatNumber) (1.0 - icPerceptualRefBlackY0.0034731 / icPerceptualRefWhiteY1.0000); | |||
1567 | m_PCSScale[2] = (icFloatNumber) (1.0 - icPerceptualRefBlackZ0.00287 / icPerceptualRefWhiteZ0.8249); | |||
1568 | ||||
1569 | m_PCSOffset[0] = (icFloatNumber) (icPerceptualRefBlackX0.00336 * 32768.0 / 65535.0); // offset factors | |||
1570 | m_PCSOffset[1] = (icFloatNumber) (icPerceptualRefBlackY0.0034731 * 32768.0 / 65535.0); | |||
1571 | m_PCSOffset[2] = (icFloatNumber) (icPerceptualRefBlackZ0.00287 * 32768.0 / 65535.0); | |||
1572 | ||||
1573 | if (!m_bInput) { // output transform must convert version 4 black point to version 2 | |||
1574 | m_PCSScale[0] = (icFloatNumber) 1.0 / m_PCSScale[0]; // invert scale factors | |||
1575 | m_PCSScale[1] = (icFloatNumber) 1.0 / m_PCSScale[1]; | |||
1576 | m_PCSScale[2] = (icFloatNumber) 1.0 / m_PCSScale[2]; | |||
1577 | ||||
1578 | m_PCSOffset[0] = - m_PCSOffset[0] * m_PCSScale[0]; // negate offset factors | |||
1579 | m_PCSOffset[1] = - m_PCSOffset[1] * m_PCSScale[1]; | |||
1580 | m_PCSOffset[2] = - m_PCSOffset[2] * m_PCSScale[2]; | |||
1581 | } | |||
1582 | } | |||
1583 | } | |||
1584 | ||||
1585 | ||||
1586 | if (m_pAdjustPCS) { | |||
1587 | CIccProfile ProfileCopy(*m_pProfile); | |||
1588 | ||||
1589 | // need to read in all the tags, so that a copy of the profile can be made | |||
1590 | if (!ProfileCopy.ReadTags(m_pProfile)) { | |||
1591 | return icCmmStatInvalidProfile; | |||
1592 | } | |||
1593 | ||||
1594 | if (!m_pAdjustPCS->CalcFactors(&ProfileCopy, this, m_PCSScale, m_PCSOffset)) { | |||
1595 | return icCmmStatIncorrectApply; | |||
1596 | } | |||
1597 | ||||
1598 | m_bAdjustPCS = true; | |||
1599 | delete m_pAdjustPCS; | |||
1600 | m_pAdjustPCS = NULL__null; | |||
1601 | } | |||
1602 | ||||
1603 | return icCmmStatOk; | |||
1604 | } | |||
1605 | ||||
1606 | /** | |||
1607 | ************************************************************************** | |||
1608 | * Name: CIccXform::GetNewApply | |||
1609 | * | |||
1610 | * Purpose: | |||
1611 | * This Factory function allocates data specific for the application of the xform. | |||
1612 | * This allows multiple threads to simultaneously use the same xform. | |||
1613 | ************************************************************************** | |||
1614 | */ | |||
1615 | CIccApplyXform *CIccXform::GetNewApply(icStatusCMM &status) | |||
1616 | { | |||
1617 | CIccApplyXform *rv = new CIccApplyXform(this); | |||
1618 | ||||
1619 | if (!rv) { | |||
1620 | status = icCmmStatAllocErr; | |||
1621 | return NULL__null; | |||
1622 | } | |||
1623 | ||||
1624 | status = icCmmStatOk; | |||
1625 | return rv; | |||
1626 | } | |||
1627 | ||||
1628 | /** | |||
1629 | ************************************************************************** | |||
1630 | * Name: CIccXform::AdjustPCS | |||
1631 | * | |||
1632 | * Purpose: | |||
1633 | * This function will take care of any PCS adjustments | |||
1634 | * needed by the xform (the PCS is always version 4 relative). | |||
1635 | * | |||
1636 | * Args: | |||
1637 | * DstPixel = Destination pixel where the result is stored, | |||
1638 | * SrcPixel = Source pixel which is to be applied. | |||
1639 | * | |||
1640 | ************************************************************************** | |||
1641 | */ | |||
1642 | void CIccXform::AdjustPCS(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
1643 | { | |||
1644 | icColorSpaceSignature Space = m_pProfile->m_Header.pcs; | |||
1645 | ||||
1646 | if (Space==icSigLabData) { | |||
1647 | if (UseLegacyPCS()) { | |||
1648 | CIccPCS::Lab2ToXyz(DstPixel, SrcPixel, true); | |||
1649 | } | |||
1650 | else { | |||
1651 | CIccPCS::LabToXyz(DstPixel, SrcPixel, true); | |||
1652 | } | |||
1653 | } | |||
1654 | else { | |||
1655 | DstPixel[0] = SrcPixel[0]; | |||
1656 | DstPixel[1] = SrcPixel[1]; | |||
1657 | DstPixel[2] = SrcPixel[2]; | |||
1658 | } | |||
1659 | ||||
1660 | DstPixel[0] = DstPixel[0] * m_PCSScale[0] + m_PCSOffset[0]; | |||
1661 | DstPixel[1] = DstPixel[1] * m_PCSScale[1] + m_PCSOffset[1]; | |||
1662 | DstPixel[2] = DstPixel[2] * m_PCSScale[2] + m_PCSOffset[2]; | |||
1663 | ||||
1664 | if (Space==icSigLabData) { | |||
1665 | if (UseLegacyPCS()) { | |||
1666 | ||||
1667 | CIccPCS::XyzToLab2(DstPixel, DstPixel, true); | |||
1668 | } | |||
1669 | else { | |||
1670 | CIccPCS::XyzToLab(DstPixel, DstPixel, true); | |||
1671 | } | |||
1672 | } | |||
1673 | #ifndef SAMPLEICC_NOCLIPLABTOXYZ | |||
1674 | else { | |||
1675 | DstPixel[0] = CIccPCS::NegClip(DstPixel[0]); | |||
1676 | DstPixel[1] = CIccPCS::NegClip(DstPixel[1]); | |||
1677 | DstPixel[2] = CIccPCS::NegClip(DstPixel[2]); | |||
1678 | } | |||
1679 | #endif | |||
1680 | } | |||
1681 | ||||
1682 | /** | |||
1683 | ************************************************************************** | |||
1684 | * Name: CIccXform::CheckSrcAbs | |||
1685 | * | |||
1686 | * Purpose: | |||
1687 | * This function will be called by a derived CIccXform object's Apply() function | |||
1688 | * BEFORE the actual xform is performed to take care of Absolute to Relative | |||
1689 | * adjustments needed by the xform (IE the PCS is always version 4 relative). | |||
1690 | * | |||
1691 | * Args: | |||
1692 | * Pixel = src pixel data (will not be modified) | |||
1693 | * | |||
1694 | * Return: | |||
1695 | * returns Pixel or adjusted pixel data. | |||
1696 | ************************************************************************** | |||
1697 | */ | |||
1698 | const icFloatNumber *CIccXform::CheckSrcAbs(CIccApplyXform *pApply, const icFloatNumber *Pixel) const | |||
1699 | { | |||
1700 | if (m_bAdjustPCS && !m_bInput && m_bSrcPcsConversion) { | |||
1701 | icFloatNumber *pAbsLab = pApply->m_AbsLab; | |||
1702 | AdjustPCS(pAbsLab, Pixel); | |||
1703 | return pAbsLab; | |||
1704 | } | |||
1705 | ||||
1706 | return Pixel; | |||
1707 | } | |||
1708 | ||||
1709 | /** | |||
1710 | ************************************************************************** | |||
1711 | * Name: CIccXform::CheckDstAbs | |||
1712 | * | |||
1713 | * Purpose: | |||
1714 | * This function will be called by a derived CIccXform object's Apply() function | |||
1715 | * AFTER the actual xform is performed to take care of Absolute to Relative | |||
1716 | * adjustments needed by the xform (IE the PCS is always version 4 relative). | |||
1717 | * | |||
1718 | * Args: | |||
1719 | * Pixel = source pixel data which will be modified | |||
1720 | * | |||
1721 | ************************************************************************** | |||
1722 | */ | |||
1723 | void CIccXform::CheckDstAbs(icFloatNumber *Pixel) const | |||
1724 | { | |||
1725 | if (m_bAdjustPCS && m_bInput && m_bDstPcsConversion) { | |||
1726 | AdjustPCS(Pixel, Pixel); | |||
1727 | } | |||
1728 | } | |||
1729 | ||||
1730 | /** | |||
1731 | ************************************************************************** | |||
1732 | * Name: CIccXform::GetSrcSpace | |||
1733 | * | |||
1734 | * Purpose: | |||
1735 | * Return the color space that is input to the transform. | |||
1736 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | |||
1737 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | |||
1738 | * and Lab spaces left to the device. | |||
1739 | ************************************************************************** | |||
1740 | */ | |||
1741 | icColorSpaceSignature CIccXform::GetSrcSpace() const | |||
1742 | { | |||
1743 | icColorSpaceSignature rv; | |||
1744 | icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass; | |||
1745 | ||||
1746 | if (m_bInput) { | |||
1747 | rv = m_pProfile->m_Header.colorSpace; | |||
1748 | ||||
1749 | if (deviceClass != icSigAbstractClass) { | |||
1750 | //convert signature to device colorspace signature (avoid confusion about encoding). | |||
1751 | if (rv==icSigXYZData) { | |||
1752 | rv = icSigDevXYZData((icColorSpaceSignature) 0x6458595A); | |||
1753 | } | |||
1754 | else if (rv==icSigLabData) { | |||
1755 | rv = icSigDevLabData((icColorSpaceSignature) 0x644C6162); | |||
1756 | } | |||
1757 | } | |||
1758 | } | |||
1759 | else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) { | |||
1760 | rv = m_pProfile->m_Header.pcs; | |||
1761 | } | |||
1762 | else { | |||
1763 | rv = icGetColorSpaceType(m_pProfile->m_Header.spectralPCS)((icColorSpaceSignature)(((icUInt32Number)m_pProfile->m_Header .spectralPCS)&0xffff0000)); | |||
1764 | } | |||
1765 | ||||
1766 | return rv; | |||
1767 | } | |||
1768 | ||||
1769 | /** | |||
1770 | ************************************************************************** | |||
1771 | * Name: CIccXform::GetNumSrcSamples | |||
1772 | * | |||
1773 | * Purpose: | |||
1774 | * Return the color space that is input to the transform. | |||
1775 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | |||
1776 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | |||
1777 | * and Lab spaces left to the device. | |||
1778 | ************************************************************************** | |||
1779 | */ | |||
1780 | icUInt16Number CIccXform::GetNumSrcSamples() const | |||
1781 | { | |||
1782 | icUInt16Number rv; | |||
1783 | ||||
1784 | if (m_nMCS==icFromMCS) { | |||
1785 | rv = (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)m_pProfile->m_Header.mcs); | |||
1786 | } | |||
1787 | else if (m_bInput) { | |||
1788 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.colorSpace); | |||
1789 | } | |||
1790 | else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) { | |||
1791 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.pcs); | |||
1792 | } | |||
1793 | else { | |||
1794 | rv = (icUInt16Number)icGetSpectralSpaceSamples(&m_pProfile->m_Header); | |||
1795 | } | |||
1796 | ||||
1797 | return rv; | |||
1798 | } | |||
1799 | ||||
1800 | /** | |||
1801 | ************************************************************************** | |||
1802 | * Name: CIccXform::GetDstSpace | |||
1803 | * | |||
1804 | * Purpose: | |||
1805 | * Return the color space that is output by the transform. | |||
1806 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | |||
1807 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | |||
1808 | * and Lab spaces left to the device. | |||
1809 | ************************************************************************** | |||
1810 | */ | |||
1811 | icColorSpaceSignature CIccXform::GetDstSpace() const | |||
1812 | { | |||
1813 | icColorSpaceSignature rv; | |||
1814 | icProfileClassSignature deviceClass = m_pProfile->m_Header.deviceClass; | |||
1815 | ||||
1816 | if (m_nMCS==icToMCS) { | |||
1817 | rv = (icColorSpaceSignature)m_pProfile->m_Header.mcs; | |||
1818 | } | |||
1819 | else if (m_bInput) { | |||
1820 | if (m_bUseSpectralPCS && m_pProfile->m_Header.spectralPCS) | |||
1821 | rv = icGetColorSpaceType(m_pProfile->m_Header.spectralPCS)((icColorSpaceSignature)(((icUInt32Number)m_pProfile->m_Header .spectralPCS)&0xffff0000)); | |||
1822 | else | |||
1823 | rv = m_pProfile->m_Header.pcs; | |||
1824 | } | |||
1825 | else { | |||
1826 | rv = m_pProfile->m_Header.colorSpace; | |||
1827 | ||||
1828 | //convert signature to device colorspace signature (avoid confusion about encoding). | |||
1829 | if (deviceClass != icSigAbstractClass) { | |||
1830 | if (rv==icSigXYZData) { | |||
1831 | rv = icSigDevXYZData((icColorSpaceSignature) 0x6458595A); | |||
1832 | } | |||
1833 | else if (rv==icSigLabData) { | |||
1834 | rv = icSigDevLabData((icColorSpaceSignature) 0x644C6162); | |||
1835 | } | |||
1836 | } | |||
1837 | } | |||
1838 | ||||
1839 | return rv; | |||
1840 | } | |||
1841 | ||||
1842 | /** | |||
1843 | ************************************************************************** | |||
1844 | * Name: CIccXform::GetNumDstSamples | |||
1845 | * | |||
1846 | * Purpose: | |||
1847 | * Return the color space that is input to the transform. | |||
1848 | * If a device space is either XYZ/Lab it is changed to dXYZ/dLab to avoid | |||
1849 | * confusion with PCS encoding of these spaces. Device encoding of XYZ | |||
1850 | * and Lab spaces left to the device. | |||
1851 | ************************************************************************** | |||
1852 | */ | |||
1853 | icUInt16Number CIccXform::GetNumDstSamples() const | |||
1854 | { | |||
1855 | icUInt16Number rv; | |||
1856 | ||||
1857 | if (m_nMCS==icToMCS) { | |||
1858 | rv = (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)m_pProfile->m_Header.mcs); | |||
1859 | } | |||
1860 | else if (!m_bInput) { | |||
1861 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.colorSpace); | |||
1862 | } | |||
1863 | else if (!m_bUseSpectralPCS || !m_pProfile->m_Header.spectralPCS) { | |||
1864 | rv = (icUInt16Number)icGetSpaceSamples(m_pProfile->m_Header.pcs); | |||
1865 | } | |||
1866 | else { | |||
1867 | rv = (icUInt16Number)icGetSpectralSpaceSamples(&m_pProfile->m_Header); | |||
1868 | } | |||
1869 | ||||
1870 | return rv; | |||
1871 | } | |||
1872 | ||||
1873 | ||||
1874 | /** | |||
1875 | ************************************************************************** | |||
1876 | * Name: CIccApplyXform::CIccApplyXform | |||
1877 | * | |||
1878 | * Purpose: | |||
1879 | * Constructor | |||
1880 | ************************************************************************** | |||
1881 | */ | |||
1882 | CIccApplyXform::CIccApplyXform(CIccXform *pXform) | |||
1883 | { | |||
1884 | m_pXform = pXform; | |||
1885 | } | |||
1886 | ||||
1887 | /** | |||
1888 | ************************************************************************** | |||
1889 | * Name: CIccApplyXform::CIccApplyXform | |||
1890 | * | |||
1891 | * Purpose: | |||
1892 | * Destructor | |||
1893 | ************************************************************************** | |||
1894 | */ | |||
1895 | CIccApplyXform::~CIccApplyXform() | |||
1896 | { | |||
1897 | } | |||
1898 | ||||
1899 | ||||
1900 | /** | |||
1901 | ************************************************************************** | |||
1902 | * Name: CIccApplyPcsXform::CIccApplyPcsXform | |||
1903 | * | |||
1904 | * Purpose: | |||
1905 | * Constructor | |||
1906 | ************************************************************************** | |||
1907 | */ | |||
1908 | CIccApplyPcsXform::CIccApplyPcsXform(CIccXform *pXform) : CIccApplyXform(pXform) | |||
1909 | { | |||
1910 | m_list = new CIccApplyPcsStepList(); | |||
1911 | m_temp1 = NULL__null; | |||
1912 | m_temp2 = NULL__null; | |||
1913 | } | |||
1914 | ||||
1915 | /** | |||
1916 | ************************************************************************** | |||
1917 | * Name: CIccApplyPcsXform::~CIccApplyPcsXform | |||
1918 | * | |||
1919 | * Purpose: | |||
1920 | * Destructor | |||
1921 | ************************************************************************** | |||
1922 | */ | |||
1923 | CIccApplyPcsXform::~CIccApplyPcsXform() | |||
1924 | { | |||
1925 | ||||
1926 | if (m_list) { | |||
1927 | CIccApplyPcsStepList::iterator i; | |||
1928 | for (i=m_list->begin(); i!=m_list->end(); i++) { | |||
1929 | if (i->ptr) | |||
1930 | delete i->ptr; | |||
1931 | } | |||
1932 | ||||
1933 | delete m_list; | |||
1934 | } | |||
1935 | ||||
1936 | if (m_temp1) | |||
1937 | delete m_temp1; | |||
1938 | if (m_temp2) | |||
1939 | delete m_temp2; | |||
1940 | } | |||
1941 | ||||
1942 | /** | |||
1943 | ************************************************************************** | |||
1944 | * Name: CIccApplyPcsXform::Init | |||
1945 | * | |||
1946 | * Purpose: | |||
1947 | * Initialize temporary variables used during pcs processing | |||
1948 | ************************************************************************** | |||
1949 | */ | |||
1950 | bool CIccApplyPcsXform::Init() | |||
1951 | { | |||
1952 | CIccPcsXform *pXform = (CIccPcsXform*)m_pXform; | |||
1953 | icUInt16Number nChan = pXform->MaxChannels(); | |||
1954 | ||||
1955 | if (nChan) { | |||
1956 | m_temp1 = new icFloatNumber[nChan]; | |||
1957 | m_temp2 = new icFloatNumber[nChan]; | |||
1958 | } | |||
1959 | ||||
1960 | return m_temp1!=NULL__null && m_temp2!=NULL__null; | |||
1961 | } | |||
1962 | ||||
1963 | ||||
1964 | void CIccApplyPcsXform::AppendApplyStep(CIccApplyPcsStep *pStep) | |||
1965 | { | |||
1966 | CIccApplyPcsStepPtr ptr; | |||
1967 | ||||
1968 | if (pStep && m_list) { | |||
1969 | ptr.ptr = pStep; | |||
1970 | m_list->push_back(ptr); | |||
1971 | } | |||
1972 | } | |||
1973 | ||||
1974 | ||||
1975 | /** | |||
1976 | ************************************************************************** | |||
1977 | * Name: CIccPcsXform::CIccPcsXform | |||
1978 | * | |||
1979 | * Purpose: | |||
1980 | * Constructor | |||
1981 | ************************************************************************** | |||
1982 | */ | |||
1983 | CIccPcsXform::CIccPcsXform() | |||
1984 | { | |||
1985 | m_list = new CIccPcsStepList(); | |||
1986 | ||||
1987 | m_srcSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | |||
1988 | m_nSrcSamples = 0; | |||
1989 | ||||
1990 | m_dstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | |||
1991 | m_nDstSamples = 0; | |||
1992 | } | |||
1993 | ||||
1994 | /** | |||
1995 | ************************************************************************** | |||
1996 | * Name: CIccPcsXform::~CIccPcsXform | |||
1997 | * | |||
1998 | * Purpose: | |||
1999 | * Destructor | |||
2000 | ************************************************************************** | |||
2001 | */ | |||
2002 | CIccPcsXform::~CIccPcsXform() | |||
2003 | { | |||
2004 | if (m_list) { | |||
2005 | CIccPcsStepList::iterator step; | |||
2006 | for (step=m_list->begin(); step!=m_list->end(); step++) { | |||
2007 | if (step->ptr) { | |||
2008 | delete step->ptr; | |||
2009 | step->ptr = NULL__null; | |||
2010 | } | |||
2011 | } | |||
2012 | delete m_list; | |||
2013 | } | |||
2014 | } | |||
2015 | ||||
2016 | /** | |||
2017 | ************************************************************************** | |||
2018 | * Name: CIccPcsXform::Connect | |||
2019 | * | |||
2020 | * Purpose: | |||
2021 | * Insert PCS transform operations to perform PCS processing between | |||
2022 | * pFromXform and pToXform | |||
2023 | ************************************************************************** | |||
2024 | */ | |||
2025 | icStatusCMM CIccPcsXform::Connect(CIccXform *pFromXform, CIccXform *pToXform) | |||
2026 | { | |||
2027 | icStatusCMM stat; | |||
2028 | ||||
2029 | if (!pFromXform || !pToXform) | |||
2030 | return icCmmStatBadXform; | |||
2031 | ||||
2032 | if (pFromXform->IsMCS() && pToXform->IsMCS()) { | |||
2033 | CIccProfile *pFromProfile = pFromXform->GetProfilePtr(); | |||
2034 | CIccProfile *pToProfile = pToXform->GetProfilePtr(); | |||
2035 | ||||
2036 | if (!pFromProfile || !pToProfile) { | |||
2037 | return icCmmStatBadSpaceLink; | |||
2038 | } | |||
2039 | CIccTagArray *pFromChannels = (CIccTagArray*)(pFromProfile->FindTagOfType(icSigMaterialTypeArrayTag, icSigTagArrayType)); | |||
2040 | CIccTagArray *pToChannels = (CIccTagArray*)(pToProfile->FindTagOfType(icSigMaterialTypeArrayTag, icSigTagArrayType)); | |||
2041 | ||||
2042 | if (!pFromChannels || !pToChannels) { | |||
2043 | return icCmmStatBadSpaceLink; | |||
2044 | } | |||
2045 | if (pFromChannels->GetTagArrayType()!=icSigUtf8TextTypeArray || | |||
2046 | pToChannels->GetTagArrayType()!=icSigUtf8TextTypeArray || | |||
2047 | !pFromChannels->AreAllOfType(icSigUtf8TextType) || | |||
2048 | !pToChannels->AreAllOfType(icSigUtf8TextType)) { | |||
2049 | return icCmmStatBadSpaceLink; | |||
2050 | } | |||
2051 | ||||
2052 | m_nSrcSamples = pFromXform->GetNumDstSamples(); | |||
2053 | m_nDstSamples = pToXform->GetNumSrcSamples(); | |||
2054 | ||||
2055 | if (pFromChannels->GetSize() != m_nSrcSamples || pToChannels->GetSize() != m_nDstSamples) { | |||
2056 | return icCmmStatBadSpaceLink; | |||
2057 | } | |||
2058 | int i, j; | |||
2059 | ||||
2060 | if (pFromProfile->m_Header.flags&icMCSNeedsSubsetTrue0x00000004) { | |||
2061 | for (i=0; i<m_nSrcSamples; i++) { | |||
2062 | const icUChar *szSrcChan = ((CIccTagUtf8Text*)pFromChannels->GetIndex(i))->GetText(); | |||
2063 | for (j=0; j<m_nDstSamples; j++) { | |||
2064 | const icUChar *szDstChan = ((CIccTagUtf8Text*)pToChannels->GetIndex(i))->GetText(); | |||
2065 | if (!icUtf8StrCmp(szSrcChan, szDstChan)strcmp((const char*)szSrcChan, (const char*)szDstChan)) | |||
2066 | break; | |||
2067 | } | |||
2068 | if (j==m_nDstSamples) | |||
2069 | return icCmmStatBadMCSLink; | |||
2070 | } | |||
2071 | } | |||
2072 | ||||
2073 | if (pToProfile->m_Header.flags&icMCSNeedsSubsetTrue0x00000004) { | |||
2074 | for (i=0; i<m_nDstSamples; i++) { | |||
2075 | const icUChar *szDstChan = ((CIccTagUtf8Text*)pToChannels->GetIndex(i))->GetText(); | |||
2076 | for (j=0; j<m_nSrcSamples; j++) { | |||
2077 | const icUChar *szSrcChan = ((CIccTagUtf8Text*)pFromChannels->GetIndex(i))->GetText(); | |||
2078 | if (!icUtf8StrCmp(szSrcChan, szDstChan)strcmp((const char*)szSrcChan, (const char*)szDstChan)) | |||
2079 | break; | |||
2080 | } | |||
2081 | if (j==m_nSrcSamples) | |||
2082 | return icCmmStatBadMCSLink; | |||
2083 | } | |||
2084 | } | |||
2085 | CIccTag *pTag = pToProfile->FindTag(icSigMaterialDefaultValuesTag); | |||
2086 | CIccTagNumArray *pDefaults = NULL__null; | |||
2087 | if (pTag && pTag->IsNumArrayType()) { | |||
2088 | pDefaults = (CIccTagNumArray *)pTag; | |||
2089 | } | |||
2090 | ||||
2091 | pushRouteMcs(pFromChannels, pToChannels, pDefaults); | |||
2092 | } | |||
2093 | else { | |||
2094 | if (!pFromXform->IsInput() || (pToXform->IsInput() && !pToXform->IsAbstract())) { | |||
2095 | return icCmmStatBadSpaceLink; | |||
2096 | } | |||
2097 | ||||
2098 | m_srcSpace = pFromXform->GetDstSpace(); | |||
2099 | if (IsSpaceSpectralPCS(m_srcSpace)) | |||
2100 | m_srcSpace = icGetColorSpaceType(m_srcSpace)((icColorSpaceSignature)(((icUInt32Number)m_srcSpace)&0xffff0000 )); | |||
2101 | ||||
2102 | m_nSrcSamples = pFromXform->GetNumDstSamples(); | |||
2103 | ||||
2104 | m_dstSpace = pToXform->GetSrcSpace(); | |||
2105 | if (IsSpaceSpectralPCS(m_dstSpace)) | |||
2106 | m_dstSpace = icGetColorSpaceType(m_dstSpace)((icColorSpaceSignature)(((icUInt32Number)m_dstSpace)&0xffff0000 )); | |||
2107 | ||||
2108 | m_nDstSamples = pToXform->GetNumSrcSamples(); | |||
2109 | ||||
2110 | switch (m_srcSpace) { | |||
2111 | case icSigLabPcsDataicSigLabData: | |||
2112 | switch (m_dstSpace) { | |||
2113 | case icSigLabPcsDataicSigLabData: | |||
2114 | if (pFromXform->UseLegacyPCS()) | |||
2115 | pushLab2ToXyz(pFromXform->m_pConnectionConditions); | |||
2116 | else | |||
2117 | pushLabToXyz(pFromXform->m_pConnectionConditions); | |||
2118 | if (pFromXform->NeedAdjustPCS()) { | |||
2119 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | |||
2120 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | |||
2121 | } | |||
2122 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2123 | return stat; | |||
2124 | } | |||
2125 | if (pToXform->NeedAdjustPCS()) { | |||
2126 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2127 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2128 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2129 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2130 | } | |||
2131 | if (pToXform->UseLegacyPCS()) | |||
2132 | pushXyzToLab2(pToXform->m_pConnectionConditions); | |||
2133 | else | |||
2134 | pushXyzToLab(pToXform->m_pConnectionConditions); | |||
2135 | break; | |||
2136 | ||||
2137 | case icSigXYZPcsDataicSigXYZData: | |||
2138 | if (pFromXform->UseLegacyPCS()) | |||
2139 | pushLab2ToXyz(pFromXform->m_pConnectionConditions); | |||
2140 | else | |||
2141 | pushLabToXyz(pFromXform->m_pConnectionConditions); | |||
2142 | if (pFromXform->NeedAdjustPCS()) { | |||
2143 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | |||
2144 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | |||
2145 | } | |||
2146 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2147 | return stat; | |||
2148 | } | |||
2149 | if (pToXform->NeedAdjustPCS()) { | |||
2150 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2151 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2152 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2153 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2154 | } | |||
2155 | pushXyzToXyzIn(); | |||
2156 | break; | |||
2157 | ||||
2158 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | |||
2159 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | |||
2160 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | |||
2161 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | |||
2162 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | |||
2163 | return icCmmStatUnsupportedPcsLink; | |||
2164 | } | |||
2165 | break; | |||
2166 | ||||
2167 | case icSigXYZPcsDataicSigXYZData: | |||
2168 | switch (m_dstSpace) { | |||
2169 | case icSigLabPcsDataicSigLabData: | |||
2170 | pushXyzInToXyz(); | |||
2171 | if (pFromXform->NeedAdjustPCS()) { | |||
2172 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | |||
2173 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | |||
2174 | } | |||
2175 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2176 | return stat; | |||
2177 | } | |||
2178 | if (pToXform->NeedAdjustPCS()) { | |||
2179 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2180 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2181 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2182 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2183 | } | |||
2184 | if (pToXform->UseLegacyPCS()) | |||
2185 | pushXyzToLab2(pToXform->m_pConnectionConditions); | |||
2186 | else | |||
2187 | pushXyzToLab(pToXform->m_pConnectionConditions); | |||
2188 | break; | |||
2189 | ||||
2190 | case icSigXYZPcsDataicSigXYZData: | |||
2191 | pushXyzInToXyz(); | |||
2192 | if (pFromXform->NeedAdjustPCS()) { | |||
2193 | pushScale3(pFromXform->m_PCSScale[0], pFromXform->m_PCSScale[1], pFromXform->m_PCSScale[2]); | |||
2194 | pushOffset3(pFromXform->m_PCSOffset[0], pFromXform->m_PCSOffset[1], pFromXform->m_PCSOffset[2]); | |||
2195 | } | |||
2196 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2197 | return stat; | |||
2198 | } | |||
2199 | if (pToXform->NeedAdjustPCS()) { | |||
2200 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2201 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2202 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2203 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2204 | } | |||
2205 | pushXyzToXyzIn(); | |||
2206 | break; | |||
2207 | ||||
2208 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | |||
2209 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | |||
2210 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | |||
2211 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | |||
2212 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | |||
2213 | return icCmmStatUnsupportedPcsLink; | |||
2214 | } | |||
2215 | break; | |||
2216 | ||||
2217 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | |||
2218 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | |||
2219 | switch (m_dstSpace) { | |||
2220 | case icSigLabPcsDataicSigLabData: | |||
2221 | pushRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | |||
2222 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2223 | return stat; | |||
2224 | } | |||
2225 | if (pToXform->NeedAdjustPCS()) { | |||
2226 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2227 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2228 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2229 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2230 | } | |||
2231 | if (pToXform->UseLegacyPCS()) | |||
2232 | pushXyzToLab2(pToXform->m_pConnectionConditions); | |||
2233 | else | |||
2234 | pushXyzToLab(pToXform->m_pConnectionConditions); | |||
2235 | break; | |||
2236 | ||||
2237 | case icSigXYZPcsDataicSigXYZData: | |||
2238 | pushRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | |||
2239 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2240 | return stat; | |||
2241 | } | |||
2242 | if (pToXform->NeedAdjustPCS()) { | |||
2243 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2244 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2245 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2246 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2247 | } | |||
2248 | pushXyzToXyzIn(); | |||
2249 | break; | |||
2250 | ||||
2251 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | |||
2252 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | |||
2253 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | |||
2254 | pToXform->m_pProfile->m_Header.spectralRange); | |||
2255 | break; | |||
2256 | ||||
2257 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | |||
2258 | pushApplyIllum(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | |||
2259 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | |||
2260 | pToXform->m_pProfile->m_Header.spectralRange); | |||
2261 | break; | |||
2262 | ||||
2263 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | |||
2264 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | |||
2265 | return icCmmStatUnsupportedPcsLink; | |||
2266 | } | |||
2267 | break; | |||
2268 | ||||
2269 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): { | |||
2270 | CIccProfile *pFromProfile = pFromXform->GetProfilePtr(); | |||
2271 | CIccProfile *pToProfile = pToXform->GetProfilePtr(); | |||
2272 | ||||
2273 | switch (m_dstSpace) { | |||
2274 | case icSigLabPcsDataicSigLabData: | |||
2275 | pushRad2Xyz(pFromProfile, pFromXform->m_pConnectionConditions, false); | |||
2276 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2277 | return stat; | |||
2278 | } | |||
2279 | if (pToXform->NeedAdjustPCS()) { | |||
2280 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2281 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2282 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2283 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2284 | } | |||
2285 | if (pToXform->UseLegacyPCS()) | |||
2286 | pushXyzToLab2(pToXform->m_pConnectionConditions); | |||
2287 | else | |||
2288 | pushXyzToLab(pToXform->m_pConnectionConditions); | |||
2289 | break; | |||
2290 | ||||
2291 | case icSigXYZPcsDataicSigXYZData: | |||
2292 | pushRad2Xyz(pFromProfile, pFromXform->m_pConnectionConditions, false); | |||
2293 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2294 | return stat; | |||
2295 | } | |||
2296 | if (pToXform->NeedAdjustPCS()) { | |||
2297 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2298 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2299 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2300 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2301 | } | |||
2302 | pushXyzToXyzIn(); | |||
2303 | break; | |||
2304 | ||||
2305 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | |||
2306 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | |||
2307 | return icCmmStatUnsupportedPcsLink; | |||
2308 | ||||
2309 | ||||
2310 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | |||
2311 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | |||
2312 | pToXform->m_pProfile->m_Header.spectralRange); | |||
2313 | break; | |||
2314 | ||||
2315 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | |||
2316 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | |||
2317 | return icCmmStatUnsupportedPcsLink; | |||
2318 | } | |||
2319 | } | |||
2320 | break; | |||
2321 | ||||
2322 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | |||
2323 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | |||
2324 | switch (m_dstSpace) { | |||
2325 | case icSigLabPcsDataicSigLabData: | |||
2326 | pushBiRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions); | |||
2327 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2328 | return stat; | |||
2329 | } | |||
2330 | if (pToXform->NeedAdjustPCS()) { | |||
2331 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2332 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2333 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2334 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2335 | } | |||
2336 | if (pToXform->UseLegacyPCS()) | |||
2337 | pushXyzToLab2(pToXform->m_pConnectionConditions); | |||
2338 | else | |||
2339 | pushXyzToLab(pToXform->m_pConnectionConditions); | |||
2340 | break; | |||
2341 | ||||
2342 | case icSigXYZPcsDataicSigXYZData: | |||
2343 | if ((stat=pushBiRef2Xyz(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) { | |||
2344 | return stat; | |||
2345 | } | |||
2346 | if ((stat=pushXYZConvert(pFromXform, pToXform))!=icCmmStatOk) { | |||
2347 | return stat; | |||
2348 | } | |||
2349 | if (pToXform->NeedAdjustPCS()) { | |||
2350 | pushOffset3(pToXform->m_PCSOffset[0]/pToXform->m_PCSScale[0], | |||
2351 | pToXform->m_PCSOffset[1]/pToXform->m_PCSScale[1], | |||
2352 | pToXform->m_PCSOffset[2]/pToXform->m_PCSScale[2]); | |||
2353 | pushScale3(pToXform->m_PCSScale[0], pToXform->m_PCSScale[1], pToXform->m_PCSScale[2]); | |||
2354 | } | |||
2355 | pushXyzToXyzIn(); | |||
2356 | break; | |||
2357 | ||||
2358 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | |||
2359 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | |||
2360 | if ((stat=pushBiRef2Ref(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) { | |||
2361 | return stat; | |||
2362 | } | |||
2363 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | |||
2364 | pToXform->m_pProfile->m_Header.spectralRange); | |||
2365 | break; | |||
2366 | ||||
2367 | case icSigRadiantSpectralPcsData((icColorSpaceSignature)icSigRadiantSpectralData): | |||
2368 | if ((stat=pushBiRef2Rad(pFromXform->m_pProfile, pFromXform->m_pConnectionConditions))!=icCmmStatOk) { | |||
2369 | return stat; | |||
2370 | } | |||
2371 | pushSpecToRange(pFromXform->m_pProfile->m_Header.spectralRange, | |||
2372 | pToXform->m_pProfile->m_Header.spectralRange); | |||
2373 | break; | |||
2374 | ||||
2375 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | |||
2376 | if (icSameSpectralRange(pFromXform->m_pProfile->m_Header.spectralRange, pToXform->m_pProfile->m_Header.spectralRange) && | |||
2377 | icSameSpectralRange(pFromXform->m_pProfile->m_Header.biSpectralRange, pToXform->m_pProfile->m_Header.biSpectralRange)) | |||
2378 | break; | |||
2379 | else | |||
2380 | return icCmmStatUnsupportedPcsLink; | |||
2381 | ||||
2382 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | |||
2383 | return icCmmStatUnsupportedPcsLink; | |||
2384 | } | |||
2385 | break; | |||
2386 | } | |||
2387 | } | |||
2388 | ||||
2389 | icStatusCMM rv = Optimize(); | |||
2390 | if (rv!=icCmmStatOk) | |||
2391 | return rv; | |||
2392 | ||||
2393 | if (m_list->begin()==m_list->end()) | |||
2394 | return icCmmStatIdentityXform; | |||
2395 | ||||
2396 | return icCmmStatOk; | |||
2397 | } | |||
2398 | ||||
2399 | ||||
2400 | /** | |||
2401 | ************************************************************************** | |||
2402 | * Name: CIccPcsXform::Optimize | |||
2403 | * | |||
2404 | * Purpose: | |||
2405 | * Analyzes and concatenates/removes transforms in pcs transformation chain | |||
2406 | ************************************************************************** | |||
2407 | */ | |||
2408 | icStatusCMM CIccPcsXform::Optimize() | |||
2409 | { | |||
2410 | if (!m_list) | |||
2411 | return icCmmStatBadXform; | |||
2412 | ||||
2413 | CIccPcsStepList steps = *m_list; | |||
2414 | CIccPcsStepList::iterator next, last; | |||
2415 | bool done=false; | |||
2416 | ||||
2417 | #if 0 | |||
2418 | std::string str; | |||
2419 | for (next = steps.begin(); next != steps.end(); next++) { | |||
2420 | next->ptr->dump(str); | |||
2421 | } | |||
2422 | printf("PCS_Steps:\r\n%s", str.c_str()); | |||
2423 | #endif | |||
2424 | ||||
2425 | while (!done) { | |||
2426 | CIccPcsStepList newSteps; | |||
2427 | CIccPcsStepPtr ptr; | |||
2428 | ||||
2429 | done = true; | |||
2430 | ||||
2431 | next = steps.begin(); | |||
2432 | if (next==steps.end()) { | |||
2433 | *m_list = steps; | |||
2434 | return icCmmStatIdentityXform; | |||
2435 | } | |||
2436 | last = next; | |||
2437 | next++; | |||
2438 | ||||
2439 | ptr.ptr = last->ptr; | |||
2440 | ||||
2441 | for (;next!=steps.end(); next++) { | |||
2442 | CIccPcsStep *pStep = ptr.ptr->concat(next->ptr); | |||
2443 | ||||
2444 | if (pStep) { | |||
2445 | done = false; | |||
2446 | ||||
2447 | delete ptr.ptr; | |||
2448 | delete next->ptr; | |||
2449 | ptr.ptr = pStep; | |||
2450 | } | |||
2451 | else { | |||
2452 | if (!ptr.ptr->isIdentity()) { | |||
2453 | newSteps.push_back(ptr); | |||
2454 | } | |||
2455 | ptr.ptr = next->ptr; | |||
2456 | } | |||
2457 | } | |||
2458 | if (!ptr.ptr->isIdentity()) { | |||
2459 | newSteps.push_back(ptr); | |||
2460 | } | |||
2461 | ||||
2462 | steps = newSteps; | |||
2463 | ||||
2464 | // for (next=steps.begin(); next!=steps.end(); next++) { | |||
2465 | // ptr.ptr = next->ptr; | |||
2466 | // done = true; | |||
2467 | // } | |||
2468 | ||||
2469 | } | |||
2470 | ||||
2471 | if (!steps.empty()) { | |||
2472 | CIccPcsStepList newSteps; | |||
2473 | CIccPcsStepPtr ptr; | |||
2474 | ||||
2475 | for (next=steps.begin(); next != steps.end(); next++) { | |||
2476 | ptr.ptr = next->ptr->reduce(); | |||
2477 | if (ptr.ptr != next->ptr) | |||
2478 | delete next->ptr; | |||
2479 | newSteps.push_back(ptr); | |||
2480 | } | |||
2481 | steps = newSteps; | |||
2482 | } | |||
2483 | ||||
2484 | *m_list = steps; | |||
2485 | ||||
2486 | return icCmmStatOk; | |||
2487 | } | |||
2488 | ||||
2489 | ||||
2490 | /** | |||
2491 | ************************************************************************** | |||
2492 | * Name: CIccPcsXform::GetNewApply | |||
2493 | * | |||
2494 | * Purpose: | |||
2495 | * Allocates a CIccApplyXform based object that can store local data for | |||
2496 | * processing (needed by CIccPcsStepMpe). | |||
2497 | ************************************************************************** | |||
2498 | */ | |||
2499 | CIccApplyXform *CIccPcsXform::GetNewApply(icStatusCMM &status) | |||
2500 | { | |||
2501 | CIccApplyPcsXform *pNew = new CIccApplyPcsXform(this); | |||
2502 | ||||
2503 | if (pNew) { | |||
2504 | if (!pNew->Init()) { | |||
2505 | delete pNew; | |||
2506 | status = icCmmStatAllocErr; | |||
2507 | return NULL__null; | |||
2508 | } | |||
2509 | } | |||
2510 | else { | |||
2511 | status = icCmmStatAllocErr; | |||
2512 | return NULL__null; | |||
2513 | } | |||
2514 | ||||
2515 | CIccPcsStepList::iterator i; | |||
2516 | CIccApplyPcsStep *pStep; | |||
2517 | ||||
2518 | for (i=m_list->begin(); i!=m_list->end(); i++) { | |||
2519 | pStep = i->ptr->GetNewApply(); | |||
2520 | if (!pStep || status != icCmmStatOk) { | |||
2521 | delete pNew; | |||
2522 | return NULL__null; | |||
2523 | } | |||
2524 | pNew->AppendApplyStep(pStep); | |||
2525 | } | |||
2526 | ||||
2527 | return pNew; | |||
2528 | } | |||
2529 | ||||
2530 | ||||
2531 | /** | |||
2532 | ************************************************************************** | |||
2533 | * Name: CIccPcsXform::MaxChannels | |||
2534 | * | |||
2535 | * Purpose: | |||
2536 | * Returns the maximum number of channels used by PCS xform steps | |||
2537 | ************************************************************************** | |||
2538 | */ | |||
2539 | icUInt16Number CIccPcsXform::MaxChannels() | |||
2540 | { | |||
2541 | icUInt16Number nMax = 0; | |||
2542 | CIccPcsStepList::const_iterator s = m_list->begin(); | |||
2543 | if (s==m_list->end()) | |||
2544 | return nMax; | |||
2545 | nMax = s->ptr->GetDstChannels(); | |||
2546 | s++; | |||
2547 | for (; s!= m_list->end(); s++) { | |||
2548 | if (s->ptr->GetSrcChannels()>nMax) | |||
2549 | nMax = s->ptr->GetSrcChannels(); | |||
2550 | } | |||
2551 | return nMax; | |||
2552 | } | |||
2553 | ||||
2554 | /** | |||
2555 | ************************************************************************** | |||
2556 | * Name: CIccPcsXform::pushRouteMcs | |||
2557 | * | |||
2558 | * Purpose: | |||
2559 | * Insert PCS step that routes MCS channel data from one profile to another | |||
2560 | ************************************************************************** | |||
2561 | */ | |||
2562 | void CIccPcsXform::pushRouteMcs(CIccTagArray *pSrcChannels, CIccTagArray *pDstChannels, CIccTagNumArray *pDefaults) | |||
2563 | { | |||
2564 | CIccPcsStepPtr ptr; | |||
2565 | ||||
2566 | ptr.ptr = new CIccPcsStepRouteMcs(pSrcChannels, pDstChannels, pDefaults); | |||
2567 | m_list->push_back(ptr); | |||
2568 | } | |||
2569 | ||||
2570 | ||||
2571 | /** | |||
2572 | ************************************************************************** | |||
2573 | * Name: CIccPcsXform::pushLab2ToXyz | |||
2574 | * | |||
2575 | * Purpose: | |||
2576 | * Insert PCS step that converts from V2 Lab internal to actual XYZ | |||
2577 | ************************************************************************** | |||
2578 | */ | |||
2579 | void CIccPcsXform::pushLab2ToXyz( IIccProfileConnectionConditions *pPCC) | |||
2580 | { | |||
2581 | icFloatNumber xyzWhite[3]; | |||
2582 | pPCC->getNormIlluminantXYZ(xyzWhite); | |||
2583 | ||||
2584 | CIccPcsStepPtr ptr; | |||
2585 | ||||
2586 | ptr.ptr = new CIccPcsStepLab2ToXYZ(xyzWhite); | |||
2587 | m_list->push_back(ptr); | |||
2588 | } | |||
2589 | ||||
2590 | ||||
2591 | /** | |||
2592 | ************************************************************************** | |||
2593 | * Name: CIccPcsXform::pushXyzToLab2 | |||
2594 | * | |||
2595 | * Purpose: | |||
2596 | * Insert PCS step that converts from actual XYZ to V2 Lab internal | |||
2597 | ************************************************************************** | |||
2598 | */ | |||
2599 | void CIccPcsXform::pushXyzToLab2(IIccProfileConnectionConditions *pPCC) | |||
2600 | { | |||
2601 | icFloatNumber xyzWhite[3]; | |||
2602 | pPCC->getNormIlluminantXYZ(xyzWhite); | |||
2603 | ||||
2604 | CIccPcsStepPtr ptr; | |||
2605 | ||||
2606 | ptr.ptr = new CIccPcsStepXYZToLab2(xyzWhite); | |||
2607 | m_list->push_back(ptr); | |||
2608 | } | |||
2609 | ||||
2610 | ||||
2611 | /** | |||
2612 | ************************************************************************** | |||
2613 | * Name: CIccPcsXform::pushLabToXyz | |||
2614 | * | |||
2615 | * Purpose: | |||
2616 | * Insert PCS step that converts from V4 Lab internal to actual XYZ | |||
2617 | ************************************************************************** | |||
2618 | */ | |||
2619 | void CIccPcsXform::pushLabToXyz(IIccProfileConnectionConditions *pPCC) | |||
2620 | { | |||
2621 | icFloatNumber xyzWhite[3]; | |||
2622 | pPCC->getNormIlluminantXYZ(xyzWhite); | |||
2623 | ||||
2624 | CIccPcsStepPtr ptr; | |||
2625 | ||||
2626 | ptr.ptr = new CIccPcsStepLabToXYZ(xyzWhite); | |||
2627 | m_list->push_back(ptr); | |||
2628 | } | |||
2629 | ||||
2630 | ||||
2631 | /** | |||
2632 | ************************************************************************** | |||
2633 | * Name: CIccPcsXform::pushXyzToLab | |||
2634 | * | |||
2635 | * Purpose: | |||
2636 | * Insert PCS step that converts from actual XYZ to V4 Lab internal | |||
2637 | ************************************************************************** | |||
2638 | */ | |||
2639 | void CIccPcsXform::pushXyzToLab( IIccProfileConnectionConditions *pPCC) | |||
2640 | { | |||
2641 | icFloatNumber xyzWhite[3]; | |||
2642 | pPCC->getNormIlluminantXYZ(xyzWhite); | |||
2643 | ||||
2644 | CIccPcsStepPtr ptr; | |||
2645 | ||||
2646 | ptr.ptr = new CIccPcsStepXYZToLab(xyzWhite); | |||
2647 | m_list->push_back(ptr); | |||
2648 | } | |||
2649 | ||||
2650 | /** | |||
2651 | ************************************************************************** | |||
2652 | * Name: CIccPcsXform::pushScale3 | |||
2653 | * | |||
2654 | * Purpose: | |||
2655 | * Insert PCS step that individually scaled three channels (conceptually | |||
2656 | * equivalent to inserting a 3x3 diagonal matrix). | |||
2657 | ************************************************************************** | |||
2658 | */ | |||
2659 | void CIccPcsXform::pushScale3(icFloatNumber v1, icFloatNumber v2, icFloatNumber v3) | |||
2660 | { | |||
2661 | CIccPcsStepScale *scale; | |||
2662 | CIccPcsStepPtr ptr; | |||
2663 | ||||
2664 | scale = new CIccPcsStepScale(3); | |||
2665 | icFloatNumber *data = scale->data(); | |||
2666 | data[0] = v1; | |||
2667 | data[1] = v2; | |||
2668 | data[2] = v3; | |||
2669 | ||||
2670 | ptr.ptr = scale; | |||
2671 | m_list->push_back(ptr); | |||
2672 | } | |||
2673 | ||||
2674 | /** | |||
2675 | ************************************************************************** | |||
2676 | * Name: CIccPcsXform::pushXyzToXyzIn | |||
2677 | * | |||
2678 | * Purpose: | |||
2679 | * Insert PCS step that converts from actual XYZ to internal XYZ | |||
2680 | ************************************************************************** | |||
2681 | */ | |||
2682 | void CIccPcsXform::pushXyzToXyzIn() | |||
2683 | { | |||
2684 | icFloatNumber scale = (icFloatNumber) (32768.0 / 65535.0); | |||
2685 | pushScale3(scale, scale, scale); | |||
2686 | } | |||
2687 | ||||
2688 | ||||
2689 | /** | |||
2690 | ************************************************************************** | |||
2691 | * Name: CIccPcsXform::pushXyzInToXyz | |||
2692 | * | |||
2693 | * Purpose: | |||
2694 | * Insert PCS step that converts from internal XYZ to actual XYZ | |||
2695 | ************************************************************************** | |||
2696 | */ | |||
2697 | void CIccPcsXform::pushXyzInToXyz() | |||
2698 | { | |||
2699 | icFloatNumber scale = (icFloatNumber) (65535.0 / 32768.0); | |||
2700 | return pushScale3(scale, scale, scale); | |||
2701 | } | |||
2702 | ||||
2703 | ||||
2704 | /** | |||
2705 | ************************************************************************** | |||
2706 | * Name: CIccPcsXform::pushXyzToXyzLum | |||
2707 | * | |||
2708 | * Purpose: | |||
2709 | * Insert PCS step that converts from normalized XYZ to XYZ Luminance | |||
2710 | ************************************************************************** | |||
2711 | */ | |||
2712 | void CIccPcsXform::pushXyzToXyzLum(IIccProfileConnectionConditions *pPCC) | |||
2713 | { | |||
2714 | icFloatNumber XYZLum[3]; | |||
2715 | pPCC->getLumIlluminantXYZ(&XYZLum[0]); | |||
2716 | ||||
2717 | icFloatNumber scale = XYZLum[1]; | |||
2718 | ||||
2719 | return pushScale3(scale, scale, scale); | |||
2720 | } | |||
2721 | ||||
2722 | ||||
2723 | /** | |||
2724 | ************************************************************************** | |||
2725 | * Name: CIccPcsXform::pushXyzLumToXyz | |||
2726 | * | |||
2727 | * Purpose: | |||
2728 | * Insert PCS step that converts from XYZ Luminance to normalized XYZ | |||
2729 | ************************************************************************** | |||
2730 | */ | |||
2731 | void CIccPcsXform::pushXyzLumToXyz(IIccProfileConnectionConditions *pPCC) | |||
2732 | { | |||
2733 | icFloatNumber XYZLum[3]; | |||
2734 | pPCC->getLumIlluminantXYZ(&XYZLum[0]); | |||
2735 | ||||
2736 | icFloatNumber scale = 1.0f / XYZLum[1]; | |||
2737 | ||||
2738 | return pushScale3(scale, scale, scale); | |||
2739 | } | |||
2740 | ||||
2741 | ||||
2742 | /** | |||
2743 | ************************************************************************** | |||
2744 | * Name: CIccPcsXform::pushXyzToXyzIn | |||
2745 | * | |||
2746 | * Purpose: | |||
2747 | * Insert PCS step that adds an offset to 3 channels. If bConvertIntXyzOffset | |||
2748 | * is true the the offset is assumed to be in Internal XYZ format and | |||
2749 | * will be converted to be an actual XYZ offset. | |||
2750 | ************************************************************************** | |||
2751 | */ | |||
2752 | void CIccPcsXform::pushOffset3(icFloatNumber v1, icFloatNumber v2, icFloatNumber v3, bool bConvertIntXyzOffset/*=true*/) | |||
2753 | { | |||
2754 | CIccPcsStepOffset *offset; | |||
2755 | CIccPcsStepPtr ptr; | |||
2756 | ||||
2757 | offset = new CIccPcsStepOffset(3); | |||
2758 | icFloatNumber *data = offset->data(); | |||
2759 | if (bConvertIntXyzOffset) { | |||
2760 | data[0] = v1*65535.0f/32768.0f; | |||
2761 | data[1] = v2*65535.0f/32768.0f; | |||
2762 | data[2] = v3*65535.0f/32768.0f; | |||
2763 | } | |||
2764 | else { | |||
2765 | data[0] = v1; | |||
2766 | data[1] = v2; | |||
2767 | data[2] = v3; | |||
2768 | } | |||
2769 | ||||
2770 | ptr.ptr = offset; | |||
2771 | m_list->push_back(ptr); | |||
2772 | } | |||
2773 | ||||
2774 | ||||
2775 | /** | |||
2776 | ************************************************************************** | |||
2777 | * Name: CIccPcsXform::pushScale | |||
2778 | * | |||
2779 | * Purpose: | |||
2780 | * Insert PCS step that individually n channels (conceptually | |||
2781 | * equivalent to inserting a nxn diagonal matrix). | |||
2782 | ************************************************************************** | |||
2783 | */ | |||
2784 | void CIccPcsXform::pushScale(icUInt16Number n, const icFloatNumber *vals) | |||
2785 | { | |||
2786 | CIccPcsStepScale *scale = new CIccPcsStepScale(n); | |||
2787 | memcpy(scale->data(), vals, n*sizeof(icFloatNumber)); | |||
2788 | ||||
2789 | CIccPcsStepPtr ptr; | |||
2790 | ptr.ptr = scale; | |||
2791 | m_list->push_back(ptr); | |||
2792 | } | |||
2793 | ||||
2794 | ||||
2795 | /** | |||
2796 | ************************************************************************** | |||
2797 | * Name: CIccPcsXform::pushMatrix | |||
2798 | * | |||
2799 | * Purpose: | |||
2800 | * Insert PCS step defined by a nRows x nCols matrix with specified vals | |||
2801 | ************************************************************************** | |||
2802 | */ | |||
2803 | void CIccPcsXform::pushMatrix(icUInt16Number nRows, icUInt16Number nCols, const icFloatNumber *vals) | |||
2804 | { | |||
2805 | CIccPcsStepMatrix *mtx = new CIccPcsStepMatrix(nRows, nCols); | |||
2806 | memcpy(mtx->entry(0), vals, nRows*nCols*sizeof(icFloatNumber)); | |||
2807 | ||||
2808 | CIccPcsStepPtr ptr; | |||
2809 | ptr.ptr = mtx; | |||
2810 | m_list->push_back(ptr); | |||
2811 | } | |||
2812 | ||||
2813 | ||||
2814 | /** | |||
2815 | ************************************************************************** | |||
2816 | * Name: CIccPcsXform::pushXYZConvert | |||
2817 | * | |||
2818 | * Purpose: | |||
2819 | * Insert PCS step that converts from source XYZ colorimetry to dest XYZ | |||
2820 | * colorimetry accounting for possible changes in illuminant and/or observer. | |||
2821 | * Luminance matching is also accounted for. | |||
2822 | ************************************************************************** | |||
2823 | */ | |||
2824 | icStatusCMM CIccPcsXform::pushXYZConvert(CIccXform *pFromXform, CIccXform *pToXform) | |||
2825 | { | |||
2826 | IIccProfileConnectionConditions *pSrcPcc = pFromXform->GetConnectionConditions(); | |||
2827 | IIccProfileConnectionConditions *pDstPcc = pToXform->GetConnectionConditions(); | |||
2828 | ||||
2829 | if (!pSrcPcc || !pDstPcc) | |||
2830 | return icCmmStatBadConnection; | |||
2831 | ||||
2832 | //If source and dest observer and illuminant are same then no transform is needed | |||
2833 | if (pSrcPcc->isEquivalentPcc(*pDstPcc)) { | |||
2834 | return icCmmStatOk; | |||
2835 | } | |||
2836 | ||||
2837 | CIccPcsStepPtr ptr; | |||
2838 | ||||
2839 | if (!pSrcPcc->isStandardPcc()) { | |||
2840 | ||||
2841 | CIccTagMultiProcessElement *pMpe = pSrcPcc->getCustomToStandardPcc(); | |||
2842 | ||||
2843 | if (!pMpe || pMpe->NumInputChannels()!=3 || pMpe->NumOutputChannels()!=3) | |||
2844 | return icCmmStatBadSpaceLink; | |||
2845 | ||||
2846 | ptr.ptr = NULL__null; | |||
2847 | ||||
2848 | //push single matrix element as a CIccPcsStepMatrix so it can be optimized | |||
2849 | if (pMpe->NumElements()==1) { | |||
2850 | CIccMultiProcessElement *pElem = pMpe->GetElement(0); | |||
2851 | if (pElem) { | |||
2852 | if (pElem->GetType()==icSigMatrixElemType) { | |||
2853 | CIccMpeMatrix *pMatElem = (CIccMpeMatrix*)pElem; | |||
2854 | ||||
2855 | icFloatNumber *pMat = pMatElem->GetMatrix(); | |||
2856 | icFloatNumber *pOffset = pMatElem->GetConstants(); | |||
2857 | ||||
2858 | if (pMat && (!pOffset || (pOffset[0]==0.0 && pOffset[1]==0.0 && pOffset[2]==0.0))) { | |||
2859 | CIccPcsStepMatrix *pStepMtx = new CIccPcsStepMatrix(3, 3); | |||
2860 | ||||
2861 | if (pStepMtx ) { | |||
2862 | memcpy(pStepMtx->entry(0,0), pMat, 9*sizeof(icFloatNumber)); | |||
2863 | } | |||
2864 | ptr.ptr = pStepMtx; | |||
2865 | } | |||
2866 | } | |||
2867 | } | |||
2868 | } | |||
2869 | ||||
2870 | if (!ptr.ptr) { | |||
2871 | CIccPcsStepMpe *pStepMpe = new CIccPcsStepMpe((CIccTagMultiProcessElement*)pMpe->NewCopy()); | |||
2872 | ||||
2873 | if (!pStepMpe) | |||
2874 | return icCmmStatAllocErr; | |||
2875 | ||||
2876 | if (!pStepMpe->Begin()) { | |||
2877 | delete pStepMpe; | |||
2878 | return icCmmStatBadConnection; | |||
2879 | } | |||
2880 | ||||
2881 | ptr.ptr = pStepMpe; | |||
2882 | } | |||
2883 | ||||
2884 | m_list->push_back(ptr); | |||
2885 | } | |||
2886 | ||||
2887 | if (!pDstPcc->isStandardPcc()) { | |||
2888 | ||||
2889 | CIccTagMultiProcessElement *pMpe = pDstPcc->getStandardToCustomPcc(); | |||
2890 | ||||
2891 | if (!pMpe || pMpe->NumInputChannels()!=3 || pMpe->NumOutputChannels()!=3) | |||
2892 | return icCmmStatBadSpaceLink; | |||
2893 | ||||
2894 | ptr.ptr = NULL__null; | |||
2895 | ||||
2896 | //push single matrix element as a CIccPcsStepMatrix so it can be optimized | |||
2897 | if (pMpe->NumElements()==1) { | |||
2898 | CIccMultiProcessElement *pElem = pMpe->GetElement(0); | |||
2899 | if (pElem) { | |||
2900 | if (pElem->GetType()==icSigMatrixElemType) { | |||
2901 | CIccMpeMatrix *pMatElem = (CIccMpeMatrix*)pElem; | |||
2902 | ||||
2903 | icFloatNumber *pMat = pMatElem->GetMatrix(); | |||
2904 | icFloatNumber *pOffset = pMatElem->GetConstants(); | |||
2905 | ||||
2906 | if (pMat && (!pOffset || (pOffset[0]==0.0 && pOffset[1]==0.0 && pOffset[2]==0.0))) { | |||
2907 | CIccPcsStepMatrix *pStepMtx = new CIccPcsStepMatrix(3, 3); | |||
2908 | ||||
2909 | if (pStepMtx ) { | |||
2910 | memcpy(pStepMtx->entry(0,0), pMat, 9*sizeof(icFloatNumber)); | |||
2911 | } | |||
2912 | ptr.ptr = pStepMtx; | |||
2913 | } | |||
2914 | } | |||
2915 | } | |||
2916 | } | |||
2917 | ||||
2918 | if (!ptr.ptr) { | |||
2919 | CIccPcsStepMpe *pStepMpe = new CIccPcsStepMpe((CIccTagMultiProcessElement*)pMpe->NewCopy()); | |||
2920 | ||||
2921 | if (!pStepMpe) | |||
2922 | return icCmmStatAllocErr; | |||
2923 | ||||
2924 | if (!pStepMpe->Begin()) { | |||
2925 | delete pStepMpe; | |||
2926 | return icCmmStatBadConnection; | |||
2927 | } | |||
2928 | ||||
2929 | ptr.ptr = pStepMpe; | |||
2930 | } | |||
2931 | ||||
2932 | m_list->push_back(ptr); | |||
2933 | } | |||
2934 | ||||
2935 | if (pFromXform->LuminanceMatching()) { | |||
2936 | pushXyzToXyzLum(pSrcPcc); | |||
2937 | } | |||
2938 | if (pToXform->LuminanceMatching()) { | |||
2939 | pushXyzLumToXyz(pDstPcc); | |||
2940 | } | |||
2941 | ||||
2942 | return icCmmStatOk; | |||
2943 | } | |||
2944 | ||||
2945 | void CIccPcsXform::pushXYZNormalize(IIccProfileConnectionConditions *pPcc, const icSpectralRange &srcRange, const icSpectralRange &dstRange) | |||
2946 | { | |||
2947 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | |||
2948 | CIccPcsXform tmp; | |||
2949 | ||||
2950 | icSpectralRange illuminantRange; | |||
2951 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | |||
2952 | ||||
2953 | icSpectralRange observerRange; | |||
2954 | const icFloatNumber *observer = pView->getObserver(observerRange); | |||
2955 | ||||
2956 | //make sure illuminant goes through identical conversion steps | |||
2957 | if (!icSameSpectralRange(srcRange, illuminantRange) || !icSameSpectralRange(dstRange, illuminantRange)) { | |||
2958 | tmp.pushSpecToRange(illuminantRange, srcRange); | |||
2959 | tmp.pushSpecToRange(srcRange, dstRange); | |||
2960 | tmp.pushSpecToRange(dstRange, observerRange); | |||
2961 | } | |||
2962 | else { | |||
2963 | tmp.pushSpecToRange(illuminantRange, observerRange); | |||
2964 | } | |||
2965 | tmp.pushMatrix(3, observerRange.steps, observer); | |||
2966 | ||||
2967 | icStatusCMM stat=icCmmStatOk; | |||
2968 | CIccApplyXform *pApply = tmp.GetNewApply(stat); | |||
2969 | if (pApply) { | |||
2970 | icFloatNumber xyz[3], normxyz[3], pccxyz[3]; | |||
2971 | ||||
2972 | //Get absolute xyz for illuminant and observer | |||
2973 | tmp.Apply(pApply, xyz, illuminant); | |||
2974 | ||||
2975 | //calculate normalized XYZ | |||
2976 | normxyz[0] = xyz[0] / xyz[1]; | |||
2977 | normxyz[1] = xyz[1] / xyz[1]; | |||
2978 | normxyz[2] = xyz[2] / xyz[1]; | |||
2979 | ||||
2980 | //get desired XYZ from pcc (might be slightly different from calculated normxyz) | |||
2981 | pPcc->getNormIlluminantXYZ(pccxyz); | |||
2982 | ||||
2983 | #if 1 | |||
2984 | //push scale factor to normalize XYZ values and correct for difference between calculated and desired XYZ | |||
2985 | pushScale3(pccxyz[0] / (normxyz[0] * xyz[1]), | |||
2986 | pccxyz[1] / (normxyz[1] * xyz[1]), | |||
2987 | pccxyz[2] / (normxyz[2] * xyz[1])); | |||
2988 | #else | |||
2989 | pushScale3(1.0f/xyz[1], 1.0f/xyz[1], 1.0f/xyz[1]); | |||
2990 | #endif | |||
2991 | ||||
2992 | delete pApply; | |||
2993 | } | |||
2994 | } | |||
2995 | ||||
2996 | /** | |||
2997 | ************************************************************************** | |||
2998 | * Name: CIccPcsXform::pushRef2Xyz | |||
2999 | * | |||
3000 | * Purpose: | |||
3001 | * Insert PCS step that convert reflectance to XYZ colorimetry defined by the | |||
3002 | * observer and illuminant accessed through the Profile Connections Conditions | |||
3003 | * handle pPcc. | |||
3004 | ************************************************************************** | |||
3005 | */ | |||
3006 | void CIccPcsXform::pushRef2Xyz(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | |||
3007 | { | |||
3008 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | |||
3009 | ||||
3010 | if (pView) { | |||
3011 | icSpectralRange illuminantRange; | |||
3012 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | |||
3013 | ||||
3014 | icSpectralRange observerRange; | |||
3015 | const icFloatNumber *observer = pView->getObserver(observerRange); | |||
3016 | ||||
3017 | pushSpecToRange(pProfile->m_Header.spectralRange, illuminantRange); | |||
3018 | pushScale(illuminantRange.steps, illuminant); | |||
3019 | pushSpecToRange(illuminantRange, observerRange); | |||
3020 | pushMatrix(3, observerRange.steps, observer); | |||
3021 | ||||
3022 | pushXYZNormalize(pPcc, illuminantRange, illuminantRange); | |||
3023 | } | |||
3024 | } | |||
3025 | ||||
3026 | ||||
3027 | /** | |||
3028 | ************************************************************************** | |||
3029 | * Name: CIccPcsXform::rangeMap | |||
3030 | * | |||
3031 | * Purpose: | |||
3032 | * This helper function generates a PCS step matrix that can be used to convert | |||
3033 | * spectral vectors from one spectral range to another using linear interpolation. | |||
3034 | ************************************************************************** | |||
3035 | */ | |||
3036 | CIccPcsStepMatrix *CIccPcsXform::rangeMap(const icSpectralRange &srcRange, const icSpectralRange &dstRange) | |||
3037 | { | |||
3038 | if (srcRange.steps != dstRange.steps || | |||
3039 | srcRange.start != dstRange.start || | |||
3040 | srcRange.end != dstRange.end) { | |||
3041 | CIccPcsStepMatrix *mtx = new CIccPcsStepMatrix(dstRange.steps, srcRange.steps); | |||
3042 | if (!mtx->SetRange(srcRange, dstRange)) | |||
3043 | { | |||
3044 | delete mtx; | |||
3045 | return NULL__null; | |||
3046 | } | |||
3047 | return mtx; | |||
3048 | } | |||
3049 | ||||
3050 | return NULL__null; | |||
3051 | } | |||
3052 | ||||
3053 | ||||
3054 | /** | |||
3055 | ************************************************************************** | |||
3056 | * Name: CIccPcsXform::pushSpecToRange | |||
3057 | * | |||
3058 | * Purpose: | |||
3059 | * Insert PCS step that res-samples spectral vector data from a source spectral | |||
3060 | * range to a destination spectral range. | |||
3061 | ************************************************************************** | |||
3062 | */ | |||
3063 | void CIccPcsXform::pushSpecToRange(const icSpectralRange &srcRange, const icSpectralRange &dstRange) | |||
3064 | { | |||
3065 | if (!icSameSpectralRange(srcRange, dstRange)) { | |||
3066 | CIccPcsStepPtr ptr; | |||
3067 | ptr.ptr = rangeMap(srcRange, dstRange); | |||
3068 | ||||
3069 | if (ptr.ptr) | |||
3070 | m_list->push_back(ptr); | |||
3071 | } | |||
3072 | } | |||
3073 | ||||
3074 | ||||
3075 | /** | |||
3076 | ************************************************************************** | |||
3077 | * Name: CIccPcsXform::pushApplyIllum | |||
3078 | * | |||
3079 | * Purpose: | |||
3080 | * Insert PCS step that applies an illuminant to incoming spectral transmissive | |||
3081 | * vectors to . Illuminant from Profile Connection | |||
3082 | * Conditions will be resampled to match the sampling range of the incoming | |||
3083 | * vectors. | |||
3084 | ************************************************************************** | |||
3085 | */ | |||
3086 | void CIccPcsXform::pushApplyIllum(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | |||
3087 | { | |||
3088 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | |||
3089 | ||||
3090 | if (pView) { | |||
3091 | CIccPcsStepPtr ptr; | |||
3092 | ||||
3093 | icSpectralRange illuminantRange; | |||
3094 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | |||
3095 | ||||
3096 | CIccPcsStepScale *pScale = new CIccPcsStepScale(illuminantRange.steps); | |||
3097 | memcpy(pScale->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber)); | |||
3098 | ||||
3099 | if (icSameSpectralRange(pProfile->m_Header.spectralRange, illuminantRange)) { | |||
3100 | ptr.ptr = pScale; | |||
3101 | m_list->push_back(ptr); | |||
3102 | } | |||
3103 | else { | |||
3104 | ptr.ptr = rangeMap(pProfile->m_Header.spectralRange, illuminantRange); | |||
3105 | if (ptr.ptr) { | |||
3106 | m_list->push_back(ptr); | |||
3107 | } | |||
3108 | ||||
3109 | ptr.ptr = pScale; | |||
3110 | m_list->push_back(ptr); | |||
3111 | ||||
3112 | ptr.ptr = rangeMap(illuminantRange, pProfile->m_Header.spectralRange); | |||
3113 | if (ptr.ptr) | |||
3114 | m_list->push_back(ptr); | |||
3115 | } | |||
3116 | } | |||
3117 | } | |||
3118 | ||||
3119 | ||||
3120 | /** | |||
3121 | ************************************************************************** | |||
3122 | * Name: CIccPcsXform::pushRad2Xyz | |||
3123 | * | |||
3124 | * Purpose: | |||
3125 | * Insert PCS step that converts from source spectral radiometric vectors to | |||
3126 | * actual XYZ colorimetry based upon observer information in Profile | |||
3127 | * Connection Conditions. | |||
3128 | ************************************************************************** | |||
3129 | */ | |||
3130 | void CIccPcsXform::pushRad2Xyz(CIccProfile* pProfile, IIccProfileConnectionConditions *pPcc, bool bAbsoluteCIEColorimetry) | |||
3131 | { | |||
3132 | const CIccTagSpectralViewingConditions *pProfView = pProfile ? pProfile->getPccViewingConditions() : NULL__null; | |||
3133 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | |||
3134 | if (pProfView && pView) { | |||
3135 | icSpectralRange illuminantRange; | |||
3136 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | |||
3137 | ||||
3138 | icSpectralRange observerRange; | |||
3139 | const icFloatNumber *observer = pView->getObserver(observerRange); | |||
3140 | ||||
3141 | //Preserve smallest step size | |||
3142 | icFloatNumber dPCSStepSize = (icF16toF(pProfile->m_Header.spectralRange.end) - icF16toF(pProfile->m_Header.spectralRange.start))/(icFloatNumber)pProfile->m_Header.spectralRange.steps; | |||
3143 | icFloatNumber dObsStepSize = (icF16toF(observerRange.end) - icF16toF(observerRange.start)) / (icFloatNumber) observerRange.steps; | |||
3144 | ||||
3145 | if (dPCSStepSize<dObsStepSize) { | |||
3146 | icFloatNumber *obs = pView->applyRangeToObserver(pProfile->m_Header.spectralRange); | |||
3147 | ||||
3148 | pushMatrix(3, pProfile->m_Header.spectralRange.steps, obs); | |||
3149 | free(obs); | |||
3150 | } | |||
3151 | else { | |||
3152 | pushSpecToRange(pProfile->m_Header.spectralRange, observerRange); | |||
3153 | pushMatrix(3, observerRange.steps, observer); | |||
3154 | ||||
3155 | } | |||
3156 | icFloatNumber k; | |||
3157 | if (bAbsoluteCIEColorimetry) { | |||
3158 | k = 683; | |||
3159 | } | |||
3160 | else { | |||
3161 | k = 1.0f / pPcc->getObserverWhiteScaleFactor(illuminant, illuminantRange); | |||
3162 | } | |||
3163 | pushScale3(k, k, k); | |||
3164 | } | |||
3165 | } | |||
3166 | ||||
3167 | ||||
3168 | /** | |||
3169 | ************************************************************************** | |||
3170 | * Name: CIccPcsXform::pushBiRef2Rad | |||
3171 | * | |||
3172 | * Purpose: | |||
3173 | * Insert PCS steps that apply an illuminant to incoming bi-spectral reflectance | |||
3174 | * matrices to get estimate of light "reflected" by surface. | |||
3175 | ************************************************************************** | |||
3176 | */ | |||
3177 | icStatusCMM CIccPcsXform::pushBiRef2Rad(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | |||
3178 | { | |||
3179 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | |||
3180 | ||||
3181 | if (pView) { | |||
3182 | icSpectralRange illuminantRange; | |||
3183 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | |||
3184 | ||||
3185 | if (icGetColorSpaceType(pProfile->m_Header.spectralPCS)((icColorSpaceSignature)(((icUInt32Number)pProfile->m_Header .spectralPCS)&0xffff0000))==icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData)) { | |||
3186 | CIccPcsStepSrcSparseMatrix *pMtx = new CIccPcsStepSrcSparseMatrix(pProfile->m_Header.spectralRange.steps, | |||
3187 | pProfile->m_Header.biSpectralRange.steps, | |||
3188 | (icUInt16Number)icGetSpaceSamples((icColorSpaceSignature)pProfile->m_Header.spectralPCS)); | |||
3189 | if (!pMtx) | |||
3190 | return icCmmStatAllocErr; | |||
3191 | ||||
3192 | CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.biSpectralRange); | |||
3193 | if (illumMtx) { | |||
3194 | illumMtx->Apply(NULL__null, pMtx->data(), illuminant); | |||
3195 | delete illumMtx; | |||
3196 | } | |||
3197 | else { | |||
3198 | memcpy(pMtx->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber)); | |||
3199 | } | |||
3200 | ||||
3201 | CIccPcsStepPtr ptr; | |||
3202 | ptr.ptr = pMtx; | |||
3203 | m_list->push_back(ptr); | |||
3204 | ||||
3205 | } | |||
3206 | else { | |||
3207 | CIccPcsStepSrcMatrix *pMtx = new CIccPcsStepSrcMatrix(pProfile->m_Header.spectralRange.steps, pProfile->m_Header.biSpectralRange.steps); | |||
3208 | if (!pMtx) | |||
3209 | return icCmmStatAllocErr; | |||
3210 | ||||
3211 | CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.biSpectralRange); | |||
3212 | if (illumMtx) { | |||
3213 | illumMtx->Apply(NULL__null, pMtx->data(), illuminant); | |||
3214 | delete illumMtx; | |||
3215 | } | |||
3216 | else { | |||
3217 | memcpy(pMtx->data(), illuminant, illuminantRange.steps*sizeof(icFloatNumber)); | |||
3218 | } | |||
3219 | ||||
3220 | CIccPcsStepPtr ptr; | |||
3221 | ptr.ptr = pMtx; | |||
3222 | m_list->push_back(ptr); | |||
3223 | ||||
3224 | } | |||
3225 | } | |||
3226 | ||||
3227 | return icCmmStatOk; | |||
3228 | } | |||
3229 | ||||
3230 | ||||
3231 | /** | |||
3232 | ************************************************************************** | |||
3233 | * Name: CIccPcsXform::pushBiRef2Xyz | |||
3234 | * | |||
3235 | * Purpose: | |||
3236 | * Insert PCS step that applies an illuminant to incoming bi-spectral reflectance | |||
3237 | * matrices to get actual XYZ values. The illuminant from the Profile | |||
3238 | * Connection Conditions is re-sampled to match the number of columns in | |||
3239 | * the incoming matrices. | |||
3240 | ************************************************************************** | |||
3241 | */ | |||
3242 | icStatusCMM CIccPcsXform::pushBiRef2Xyz(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | |||
3243 | { | |||
3244 | icStatusCMM stat = pushBiRef2Rad(pProfile, pPcc); | |||
3245 | if (stat!=icCmmStatOk) | |||
3246 | return stat; | |||
3247 | ||||
3248 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | |||
3249 | ||||
3250 | if (pView) { | |||
3251 | icSpectralRange observerRange; | |||
3252 | const icFloatNumber *observer = pView->getObserver(observerRange); | |||
3253 | ||||
3254 | pushSpecToRange(pProfile->m_Header.spectralRange, observerRange); | |||
3255 | pushMatrix(3, observerRange.steps, observer); | |||
3256 | pushXYZNormalize(pPcc, pProfile->m_Header.biSpectralRange, pProfile->m_Header.spectralRange); | |||
3257 | } | |||
3258 | else { | |||
3259 | return icCmmStatBadConnection; | |||
3260 | } | |||
3261 | ||||
3262 | return icCmmStatOk; | |||
3263 | } | |||
3264 | ||||
3265 | ||||
3266 | /** | |||
3267 | ************************************************************************** | |||
3268 | * Name: CIccPcsXform::pushBiRef2Ref | |||
3269 | * | |||
3270 | * Purpose: | |||
3271 | * Insert PCS steps that apply an illuminant to incoming bi-spectral reflectance | |||
3272 | * matrices and then normalizes by the illuminant to get an estimate of | |||
3273 | * reflectance factor under that illuminant. | |||
3274 | ************************************************************************** | |||
3275 | */ | |||
3276 | icStatusCMM CIccPcsXform::pushBiRef2Ref(CIccProfile *pProfile, IIccProfileConnectionConditions *pPcc) | |||
3277 | { | |||
3278 | icStatusCMM stat = pushBiRef2Rad(pProfile, pPcc); | |||
3279 | if (stat!=icCmmStatOk) | |||
3280 | return stat; | |||
3281 | ||||
3282 | const CIccTagSpectralViewingConditions *pView = pPcc->getPccViewingConditions(); | |||
3283 | ||||
3284 | if (pView) { | |||
3285 | icSpectralRange illuminantRange; | |||
3286 | const icFloatNumber *illuminant = pView->getIlluminant(illuminantRange); | |||
3287 | ||||
3288 | CIccPcsStepScale *pScale = new CIccPcsStepScale(pProfile->m_Header.spectralRange.steps); | |||
3289 | ||||
3290 | if (pScale) { | |||
3291 | icFloatNumber *pData = pScale->data(); | |||
3292 | CIccPcsStepMatrix *illumMtx = rangeMap(illuminantRange, pProfile->m_Header.spectralRange); | |||
3293 | int i; | |||
3294 | ||||
3295 | if (illumMtx) { | |||
3296 | illumMtx->Apply(NULL__null, pData, illuminant); | |||
3297 | for (i=0; i<pProfile->m_Header.spectralRange.steps; i++) | |||
3298 | pData[i] = 1.0f / pData[i]; | |||
3299 | ||||
3300 | delete illumMtx; | |||
3301 | ||||
3302 | CIccPcsStepPtr ptr; | |||
3303 | ptr.ptr = pScale; | |||
3304 | m_list->push_back(ptr); | |||
3305 | } | |||
3306 | else { | |||
3307 | for (i=0; i<pProfile->m_Header.spectralRange.steps; i++) { | |||
3308 | pData[i] = 1.0f / illuminant[i]; | |||
3309 | } | |||
3310 | } | |||
3311 | } | |||
3312 | else | |||
3313 | return icCmmStatAllocErr; | |||
3314 | } | |||
3315 | else | |||
3316 | return icCmmStatBadConnection; | |||
3317 | ||||
3318 | return icCmmStatOk; | |||
3319 | } | |||
3320 | ||||
3321 | ||||
3322 | #ifdef _DEBUG | |||
3323 | //#define DUMPCSSTEPRESULTS | |||
3324 | #ifdef DUMPCSSTEPRESULTS | |||
3325 | #define ICCDUMPPIXEL(n, pix) \ | |||
3326 | if ((n)<96) { \ | |||
3327 | printf("["); \ | |||
3328 | int i; \ | |||
3329 | for (i=0; i<(n); i++) { \ | |||
3330 | if (i && !(i%12)) \ | |||
3331 | printf("...\n"); \ | |||
3332 | printf(" %.5f", pix[i]); \ | |||
3333 | } \ | |||
3334 | printf("]\n"); \ | |||
3335 | } \ | |||
3336 | else { \ | |||
3337 | printf("[ BigAray with %d elements]\n", (n)); \ | |||
3338 | } | |||
3339 | #else | |||
3340 | #define ICCDUMPPIXEL(n, pix) | |||
3341 | #endif | |||
3342 | #else | |||
3343 | #define ICCDUMPPIXEL(n, pix) | |||
3344 | #endif | |||
3345 | ||||
3346 | ||||
3347 | /** | |||
3348 | ************************************************************************** | |||
3349 | * Name: CIccPcsXform::Apply | |||
3350 | * | |||
3351 | * Purpose: | |||
3352 | * Applies the PcsXfrom steps using the apply pXform data to SrcPixel to get DstPixel | |||
3353 | ************************************************************************** | |||
3354 | */ | |||
3355 | void CIccPcsXform::Apply(CIccApplyXform *pXform, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
3356 | { | |||
3357 | CIccApplyPcsXform *pApplyXform = (CIccApplyPcsXform*)pXform; | |||
3358 | CIccApplyPcsStepList *pList = pApplyXform->m_list; | |||
3359 | ||||
3360 | ICCDUMPPIXEL(GetNumSrcSamples(), SrcPixel); | |||
3361 | ||||
3362 | if (!pList) { | |||
3363 | memcpy(DstPixel, SrcPixel, GetNumSrcSamples()*sizeof(icFloatNumber)); | |||
3364 | ICCDUMPPIXEL(GetNumSrcSamples(), DstPixel); | |||
3365 | return; | |||
3366 | } | |||
3367 | ||||
3368 | CIccApplyPcsStepList::iterator s, n; | |||
3369 | s = n =pList->begin(); | |||
3370 | ||||
3371 | if (s==pList->end()) { | |||
3372 | memcpy(DstPixel, SrcPixel, GetNumSrcSamples()*sizeof(icFloatNumber)); | |||
3373 | ICCDUMPPIXEL(GetNumSrcSamples(), DstPixel); | |||
3374 | return; | |||
3375 | } | |||
3376 | ||||
3377 | n++; | |||
3378 | ||||
3379 | if (n==pList->end()) { | |||
3380 | s->ptr->Apply(DstPixel, SrcPixel); | |||
3381 | ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), DstPixel); | |||
3382 | } | |||
3383 | else { | |||
3384 | const icFloatNumber *src = SrcPixel; | |||
3385 | icFloatNumber *p1 = pApplyXform->m_temp1; | |||
3386 | icFloatNumber *p2 = pApplyXform->m_temp2; | |||
3387 | icFloatNumber *t; | |||
3388 | ||||
3389 | for (;n!=pList->end(); s=n, n++) { | |||
3390 | s->ptr->Apply(p1, src); | |||
3391 | ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), p1); | |||
3392 | src=p1; | |||
3393 | t=p1; p1=p2; p2=t; | |||
3394 | } | |||
3395 | s->ptr->Apply(DstPixel, src); | |||
3396 | ICCDUMPPIXEL(s->ptr->GetStep()->GetDstChannels(), DstPixel); | |||
3397 | } | |||
3398 | } | |||
3399 | ||||
3400 | /** | |||
3401 | ************************************************************************** | |||
3402 | * Name: CIccPcsStep::GetNewApply | |||
3403 | * | |||
3404 | * Purpose: | |||
3405 | * Allocates a new CIccApplyPcsStep to be used with processing. | |||
3406 | ************************************************************************** | |||
3407 | */ | |||
3408 | CIccApplyPcsStep* CIccPcsStep::GetNewApply() | |||
3409 | { | |||
3410 | return new CIccApplyPcsStep(this); | |||
3411 | } | |||
3412 | ||||
3413 | ||||
3414 | /** | |||
3415 | ************************************************************************** | |||
3416 | * Name: CIccPcsStepIdentity::Apply | |||
3417 | * | |||
3418 | * Purpose: | |||
3419 | * Copies pSrc to pDst | |||
3420 | ************************************************************************** | |||
3421 | */ | |||
3422 | void CIccPcsStepIdentity::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
3423 | { | |||
3424 | if (pDst != pSrc) | |||
3425 | memcpy(pDst, pSrc, m_nChannels*sizeof(icFloatNumber)); | |||
3426 | } | |||
3427 | ||||
3428 | ||||
3429 | /** | |||
3430 | ************************************************************************** | |||
3431 | * Name: CIccPcsStepIdentity::dump | |||
3432 | * | |||
3433 | * Purpose: | |||
3434 | * dumps the context of the step | |||
3435 | ************************************************************************** | |||
3436 | */ | |||
3437 | void CIccPcsStepIdentity::dump(std::string &str) const | |||
3438 | { | |||
3439 | str += "\nCIccPcsStepIdentity\n\n"; | |||
3440 | } | |||
3441 | ||||
3442 | ||||
3443 | /** | |||
3444 | ************************************************************************** | |||
3445 | * Name: CIccPcsStepIdentity::CIccPcsStepIdentity | |||
3446 | * | |||
3447 | * Purpose: | |||
3448 | * Constructor | |||
3449 | ************************************************************************** | |||
3450 | */ | |||
3451 | CIccPcsStepRouteMcs::CIccPcsStepRouteMcs(CIccTagArray *pSrcChannels, CIccTagArray *pDstChannels, CIccTagNumArray *pDefaults) | |||
3452 | { | |||
3453 | m_nSrcChannels = (icUInt16Number)pSrcChannels->GetSize(); | |||
3454 | m_nDstChannels = (icUInt16Number)pDstChannels->GetSize(); | |||
3455 | m_Index = new int[m_nDstChannels]; | |||
3456 | m_Defaults = new icFloatNumber[m_nDstChannels]; | |||
3457 | ||||
3458 | memset(m_Defaults, 0, m_nDstChannels*sizeof(icFloatNumber)); | |||
3459 | ||||
3460 | if (pDefaults) { | |||
3461 | pDefaults->GetValues(m_Defaults, 0, m_nDstChannels); | |||
3462 | } | |||
3463 | ||||
3464 | int i, j; | |||
3465 | char *szSrc; | |||
3466 | ||||
3467 | for (i=0; i<m_nDstChannels; i++) { | |||
3468 | const icUChar *szDstChan = ((CIccTagUtf8Text*)(pDstChannels->GetIndex(i)))->GetText(); | |||
3469 | for (j=0; j<m_nSrcChannels; j++) { | |||
3470 | const icUChar *szSrcChan = ((CIccTagUtf8Text*)(pSrcChannels->GetIndex(j)))->GetText(); | |||
3471 | szSrc = (char*)szSrcChan; | |||
3472 | if (!icUtf8StrCmp(szDstChan, szSrcChan)strcmp((const char*)szDstChan, (const char*)szSrcChan)) | |||
3473 | break; | |||
3474 | } | |||
3475 | if (j==m_nSrcChannels) { | |||
3476 | m_Index[i] = -1; | |||
3477 | } | |||
3478 | else { | |||
3479 | m_Index[i] = j; | |||
3480 | } | |||
3481 | //printf("%d - %d %s\n", m_Index[i], i, szDstChan); | |||
3482 | } | |||
3483 | } | |||
3484 | ||||
3485 | ||||
3486 | /** | |||
3487 | ************************************************************************** | |||
3488 | * Name: CIccPcsStepIdentity::~CIccPcsStepIdentity | |||
3489 | * | |||
3490 | * Purpose: | |||
3491 | * Destructor | |||
3492 | ************************************************************************** | |||
3493 | */ | |||
3494 | CIccPcsStepRouteMcs::~CIccPcsStepRouteMcs() | |||
3495 | { | |||
3496 | if (m_Index) | |||
3497 | delete [] m_Index; | |||
3498 | if (m_Defaults) | |||
3499 | delete [] m_Defaults; | |||
3500 | } | |||
3501 | ||||
3502 | ||||
3503 | /** | |||
3504 | ************************************************************************** | |||
3505 | * Name: CIccPcsStepRouteMcs::isIdentity | |||
3506 | * | |||
3507 | * Purpose: | |||
3508 | * Determines if applying this step will result in negligible change in data | |||
3509 | ************************************************************************** | |||
3510 | */ | |||
3511 | bool CIccPcsStepRouteMcs::isIdentity() const | |||
3512 | { | |||
3513 | if (m_nSrcChannels!=m_nDstChannels) | |||
3514 | return false; | |||
3515 | ||||
3516 | int i; | |||
3517 | for (i=0; i<m_nDstChannels; i++) { | |||
3518 | if (m_Index[i]!=i) | |||
3519 | return false; | |||
3520 | } | |||
3521 | ||||
3522 | return true; | |||
3523 | } | |||
3524 | ||||
3525 | ||||
3526 | ||||
3527 | /** | |||
3528 | ************************************************************************** | |||
3529 | * Name: CIccPcsStepRouteMcs::Apply | |||
3530 | * | |||
3531 | * Purpose: | |||
3532 | * Copies pSrc to pDst | |||
3533 | ************************************************************************** | |||
3534 | */ | |||
3535 | void CIccPcsStepRouteMcs::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
3536 | { | |||
3537 | if (pDst != pSrc) { | |||
3538 | int i; | |||
3539 | for (i=0; i<m_nDstChannels; i++) { | |||
3540 | if (m_Index[i]>=0) | |||
3541 | pDst[i] = pSrc[m_Index[i]]; | |||
3542 | else | |||
3543 | pDst[i] = m_Defaults[i]; | |||
3544 | } | |||
3545 | } | |||
3546 | } | |||
3547 | ||||
3548 | ||||
3549 | /** | |||
3550 | ************************************************************************** | |||
3551 | * Name: CIccPcsStepRouteMcs::dump | |||
3552 | * | |||
3553 | * Purpose: | |||
3554 | * dumps the context of the step | |||
3555 | ************************************************************************** | |||
3556 | */ | |||
3557 | void CIccPcsStepRouteMcs::dump(std::string &str) const | |||
3558 | { | |||
3559 | str += "\nCIccPcsStepRouteMcs\n\n"; | |||
3560 | } | |||
3561 | ||||
3562 | extern icFloatNumber icD50XYZ[3]; | |||
3563 | ||||
3564 | /** | |||
3565 | ************************************************************************** | |||
3566 | * Name: CIccPcsLabStep::isSameWhite | |||
3567 | * | |||
3568 | * Purpose: | |||
3569 | * Determines if this step has same white point as that passed in | |||
3570 | ************************************************************************** | |||
3571 | */ | |||
3572 | bool CIccPcsLabStep::isSameWhite(const icFloatNumber *xyzWhite) | |||
3573 | { | |||
3574 | return (m_xyzWhite[0]==xyzWhite[0] && | |||
3575 | m_xyzWhite[1]==xyzWhite[1] && | |||
3576 | m_xyzWhite[2]==xyzWhite[2]); | |||
3577 | } | |||
3578 | ||||
3579 | ||||
3580 | ||||
3581 | /** | |||
3582 | ************************************************************************** | |||
3583 | * Name: CIccPcsStepLabToXYZ::CIccPcsStepLabToXYZ | |||
3584 | * | |||
3585 | * Purpose: | |||
3586 | * Constructor | |||
3587 | ************************************************************************** | |||
3588 | */ | |||
3589 | CIccPcsStepLabToXYZ::CIccPcsStepLabToXYZ(const icFloatNumber *xyzWhite/*=NULL*/) | |||
3590 | { | |||
3591 | if (xyzWhite) { | |||
3592 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | |||
3593 | } | |||
3594 | else { | |||
3595 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | |||
3596 | } | |||
3597 | } | |||
3598 | ||||
3599 | ||||
3600 | /** | |||
3601 | ************************************************************************** | |||
3602 | * Name: CIccPcsStepLabToXYZ::Apply | |||
3603 | * | |||
3604 | * Purpose: | |||
3605 | * Converts from V4 Internal Lab to actual XYZ | |||
3606 | ************************************************************************** | |||
3607 | */ | |||
3608 | void CIccPcsStepLabToXYZ::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
3609 | { | |||
3610 | icFloatNumber Lab[3]; | |||
3611 | ||||
3612 | //lab4 to XYZ | |||
3613 | Lab[0] = pSrc[0] * 100.0f; | |||
3614 | Lab[1] = (icFloatNumber)(pSrc[1]*255.0f - 128.0f); | |||
3615 | Lab[2] = (icFloatNumber)(pSrc[2]*255.0f - 128.0f); | |||
3616 | ||||
3617 | icLabtoXYZ(pDst, Lab, m_xyzWhite); | |||
3618 | } | |||
3619 | ||||
3620 | ||||
3621 | /** | |||
3622 | ************************************************************************** | |||
3623 | * Name: CIccPcsStepLabToXYZ::dump | |||
3624 | * | |||
3625 | * Purpose: | |||
3626 | * dumps the context of the step | |||
3627 | ************************************************************************** | |||
3628 | */ | |||
3629 | void CIccPcsStepLabToXYZ::dump(std::string &str) const | |||
3630 | { | |||
3631 | str += "\nCIccPcsStepLabToXYZ\n\n"; | |||
3632 | } | |||
3633 | ||||
3634 | ||||
3635 | /** | |||
3636 | ************************************************************************** | |||
3637 | * Name: CIccPcsStepLabToXYZ::concat | |||
3638 | * | |||
3639 | * Purpose: | |||
3640 | * Determines if this step can be combined with the next step. | |||
3641 | * Checks if next step is an icPcsStepXyzToLab step resulting in a combined | |||
3642 | * identity transform. | |||
3643 | ************************************************************************** | |||
3644 | */ | |||
3645 | CIccPcsStep *CIccPcsStepLabToXYZ::concat(CIccPcsStep *pNext) const | |||
3646 | { | |||
3647 | if (pNext && pNext->GetType()==icPcsStepXYZToLab) { | |||
3648 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | |||
3649 | if (pStep->isSameWhite(m_xyzWhite)) | |||
3650 | return new CIccPcsStepIdentity(3); | |||
3651 | } | |||
3652 | return NULL__null; | |||
3653 | } | |||
3654 | ||||
3655 | ||||
3656 | /** | |||
3657 | ************************************************************************** | |||
3658 | * Name: CIccPcsStepXYZToLab::CIccPcsStepXYZToLab | |||
3659 | * | |||
3660 | * Purpose: | |||
3661 | * Constructor | |||
3662 | ************************************************************************** | |||
3663 | */ | |||
3664 | CIccPcsStepXYZToLab::CIccPcsStepXYZToLab(const icFloatNumber *xyzWhite/*=NULL*/) | |||
3665 | { | |||
3666 | if (xyzWhite) { | |||
3667 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | |||
3668 | } | |||
3669 | else { | |||
3670 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | |||
3671 | } | |||
3672 | } | |||
3673 | ||||
3674 | ||||
3675 | /** | |||
3676 | ************************************************************************** | |||
3677 | * Name: CIccPcsStepXYZToLab::Apply | |||
3678 | * | |||
3679 | * Purpose: | |||
3680 | * Converts from actual XYZ to V4 Internal Lab | |||
3681 | ************************************************************************** | |||
3682 | */ | |||
3683 | void CIccPcsStepXYZToLab::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
3684 | { | |||
3685 | icFloatNumber Lab[3]; | |||
3686 | icXYZtoLab(Lab, (icFloatNumber*)pSrc, m_xyzWhite); | |||
3687 | //lab4 from XYZ | |||
3688 | pDst[0] = Lab[0] / 100.0f; | |||
3689 | pDst[1] = (icFloatNumber)((Lab[1] + 128.0f) / 255.0f); | |||
3690 | pDst[2] = (icFloatNumber)((Lab[2] + 128.0f) / 255.0f); | |||
3691 | } | |||
3692 | ||||
3693 | ||||
3694 | /** | |||
3695 | ************************************************************************** | |||
3696 | * Name: CIccPcsStepXYZToLab::dump | |||
3697 | * | |||
3698 | * Purpose: | |||
3699 | * dumps the context of the step | |||
3700 | ************************************************************************** | |||
3701 | */ | |||
3702 | void CIccPcsStepXYZToLab::dump(std::string &str) const | |||
3703 | { | |||
3704 | str += "\nCIccPcsStepXYZToLab\n\n"; | |||
3705 | } | |||
3706 | ||||
3707 | ||||
3708 | /** | |||
3709 | ************************************************************************** | |||
3710 | * Name: CIccPcsStepXYZToLab::concat | |||
3711 | * | |||
3712 | * Purpose: | |||
3713 | * Determines if this step can be combined with the next step. | |||
3714 | * Checks if next step is an icPcsStepLabToXYZ step resulting in a combined | |||
3715 | * identity transform. | |||
3716 | ************************************************************************** | |||
3717 | */ | |||
3718 | CIccPcsStep *CIccPcsStepXYZToLab::concat(CIccPcsStep *pNext) const | |||
3719 | { | |||
3720 | if (pNext && pNext->GetType()==icPcsStepLabToXYZ) { | |||
3721 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | |||
3722 | if (pStep->isSameWhite(m_xyzWhite)) | |||
3723 | return new CIccPcsStepIdentity(3); | |||
3724 | } | |||
3725 | return NULL__null; | |||
3726 | } | |||
3727 | ||||
3728 | ||||
3729 | /** | |||
3730 | ************************************************************************** | |||
3731 | * Name: CIccPcsStepLab2ToXYZ::CIccPcsStepLab2ToXYZ | |||
3732 | * | |||
3733 | * Purpose: | |||
3734 | * Constructor | |||
3735 | ************************************************************************** | |||
3736 | */ | |||
3737 | CIccPcsStepLab2ToXYZ::CIccPcsStepLab2ToXYZ(const icFloatNumber *xyzWhite/*=NULL*/) | |||
3738 | { | |||
3739 | if (xyzWhite) { | |||
3740 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | |||
3741 | } | |||
3742 | else { | |||
3743 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | |||
3744 | } | |||
3745 | } | |||
3746 | ||||
3747 | /** | |||
3748 | ************************************************************************** | |||
3749 | * Name: CIccPcsStepLab2ToXYZ::Apply | |||
3750 | * | |||
3751 | * Purpose: | |||
3752 | * Converts from actual XYZ to V2 Internal Lab | |||
3753 | ************************************************************************** | |||
3754 | */ | |||
3755 | void CIccPcsStepLab2ToXYZ::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
3756 | { | |||
3757 | icFloatNumber Lab[3]; | |||
3758 | ||||
3759 | //lab2 to XYZ | |||
3760 | Lab[0] = pSrc[0] * (65535.0f / 65280.0f) * 100.0f; | |||
3761 | Lab[1] = (icFloatNumber)(pSrc[1] * 65535.0f / 65280.0f * 255.0f - 128.0f); | |||
3762 | Lab[2] = (icFloatNumber)(pSrc[2] * 65535.0f / 65280.0f * 255.0f - 128.0f); | |||
3763 | ||||
3764 | icLabtoXYZ(pDst, Lab, m_xyzWhite); | |||
3765 | } | |||
3766 | ||||
3767 | ||||
3768 | /** | |||
3769 | ************************************************************************** | |||
3770 | * Name: CIccPcsStepLab2ToXYZ::dump | |||
3771 | * | |||
3772 | * Purpose: | |||
3773 | * dumps the context of the step | |||
3774 | ************************************************************************** | |||
3775 | */ | |||
3776 | void CIccPcsStepLab2ToXYZ::dump(std::string &str) const | |||
3777 | { | |||
3778 | str += "\nCIccPcsStepLab2ToXYZ\n\n"; | |||
3779 | } | |||
3780 | ||||
3781 | ||||
3782 | /** | |||
3783 | ************************************************************************** | |||
3784 | * Name: CIccPcsStepLab2ToXYZ::concat | |||
3785 | * | |||
3786 | * Purpose: | |||
3787 | * Determines if this step can be combined with the next step. | |||
3788 | * Checks if next step is an icPcsStepXYZToLab2 step resulting in a combined | |||
3789 | * identity transform. | |||
3790 | ************************************************************************** | |||
3791 | */ | |||
3792 | CIccPcsStep *CIccPcsStepLab2ToXYZ::concat(CIccPcsStep *pNext) const | |||
3793 | { | |||
3794 | if (pNext && pNext->GetType()==icPcsStepXYZToLab2) { | |||
3795 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | |||
3796 | if (pStep->isSameWhite(m_xyzWhite)) | |||
3797 | return new CIccPcsStepIdentity(3); | |||
3798 | } | |||
3799 | return NULL__null; | |||
3800 | } | |||
3801 | ||||
3802 | ||||
3803 | /** | |||
3804 | ************************************************************************** | |||
3805 | * Name: CIccPcsStepXYZToLab2::CIccPcsStepXYZToLab2 | |||
3806 | * | |||
3807 | * Purpose: | |||
3808 | * Constructor | |||
3809 | ************************************************************************** | |||
3810 | */ | |||
3811 | CIccPcsStepXYZToLab2::CIccPcsStepXYZToLab2(const icFloatNumber *xyzWhite/*=NULL*/) | |||
3812 | { | |||
3813 | if (xyzWhite) { | |||
3814 | memcpy(m_xyzWhite, xyzWhite, sizeof(m_xyzWhite)); | |||
3815 | } | |||
3816 | else { | |||
3817 | memcpy(m_xyzWhite, icD50XYZ, sizeof(m_xyzWhite)); | |||
3818 | } | |||
3819 | } | |||
3820 | ||||
3821 | ||||
3822 | /** | |||
3823 | ************************************************************************** | |||
3824 | * Name: CIccPcsStepXYZToLab2::Apply | |||
3825 | * | |||
3826 | * Purpose: | |||
3827 | * Converts from V2 Internal Lab to actual XYZ | |||
3828 | ************************************************************************** | |||
3829 | */ | |||
3830 | void CIccPcsStepXYZToLab2::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
3831 | { | |||
3832 | icFloatNumber Lab[3]; | |||
3833 | icXYZtoLab(Lab, (icFloatNumber*)pSrc, m_xyzWhite); | |||
3834 | //lab2 from XYZ | |||
3835 | pDst[0] = (Lab[0] / 100.0f) * (65280.0f / 65535.0f); | |||
3836 | pDst[1] = (icFloatNumber)((Lab[1] + 128.0f) / 255.0f) * (65280.0f / 65535.0f); | |||
3837 | pDst[2] = (icFloatNumber)((Lab[2] + 128.0f) / 255.0f) * (65280.0f / 65535.0f); | |||
3838 | } | |||
3839 | ||||
3840 | ||||
3841 | /** | |||
3842 | ************************************************************************** | |||
3843 | * Name: CIccPcsStepXYZToLab2::dump | |||
3844 | * | |||
3845 | * Purpose: | |||
3846 | * dumps the context of the step | |||
3847 | ************************************************************************** | |||
3848 | */ | |||
3849 | void CIccPcsStepXYZToLab2::dump(std::string &str) const | |||
3850 | { | |||
3851 | str += "\nCIccPcsStepXYZToLab2\n\n"; | |||
3852 | } | |||
3853 | ||||
3854 | ||||
3855 | /** | |||
3856 | ************************************************************************** | |||
3857 | * Name: CIccPcsStepXYZToLab2::concat | |||
3858 | * | |||
3859 | * Purpose: | |||
3860 | * Determines if this step can be combined with the next step. | |||
3861 | * Checks if next step is an icPcsStepLab2ToXYZ step resulting in a combined | |||
3862 | * identity transform. | |||
3863 | ************************************************************************** | |||
3864 | */ | |||
3865 | CIccPcsStep *CIccPcsStepXYZToLab2::concat(CIccPcsStep *pNext) const | |||
3866 | { | |||
3867 | if (pNext && pNext->GetType()==icPcsStepLab2ToXYZ) { | |||
3868 | CIccPcsLabStep *pStep = (CIccPcsLabStep *)pNext; | |||
3869 | if (pStep->isSameWhite(m_xyzWhite)) | |||
3870 | return new CIccPcsStepIdentity(3); | |||
3871 | } | |||
3872 | return NULL__null; | |||
3873 | } | |||
3874 | ||||
3875 | ||||
3876 | /** | |||
3877 | ************************************************************************** | |||
3878 | * Name: CIccPcsStepOffset::CIccPcsStepOffset | |||
3879 | * | |||
3880 | * Purpose: | |||
3881 | * Constructor | |||
3882 | ************************************************************************** | |||
3883 | */ | |||
3884 | CIccPcsStepOffset::CIccPcsStepOffset(icUInt16Number nChannels) | |||
3885 | { | |||
3886 | m_nChannels = nChannels; | |||
3887 | m_vals = new icFloatNumber[nChannels]; | |||
3888 | } | |||
3889 | ||||
3890 | ||||
3891 | /** | |||
3892 | ************************************************************************** | |||
3893 | * Name: CIccPcsStepOffset::CIccPcsStepOffset | |||
3894 | * | |||
3895 | * Purpose: | |||
3896 | * Destructor | |||
3897 | ************************************************************************** | |||
3898 | */ | |||
3899 | CIccPcsStepOffset::~CIccPcsStepOffset() | |||
3900 | { | |||
3901 | if (m_vals) | |||
3902 | delete m_vals; | |||
3903 | } | |||
3904 | ||||
3905 | ||||
3906 | /** | |||
3907 | ************************************************************************** | |||
3908 | * Name: CIccPcsStepOffset::Apply | |||
3909 | * | |||
3910 | * Purpose: | |||
3911 | * Added a fixed offset to the pSrc vector passed in | |||
3912 | ************************************************************************** | |||
3913 | */ | |||
3914 | void CIccPcsStepOffset::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
3915 | { | |||
3916 | if (m_nChannels==3) { | |||
3917 | pDst[0] = m_vals[0] + pSrc[0]; | |||
3918 | pDst[1] = m_vals[1] + pSrc[1]; | |||
3919 | pDst[2] = m_vals[2] + pSrc[2]; | |||
3920 | } | |||
3921 | else { | |||
3922 | int i; | |||
3923 | for (i=0; i<m_nChannels; i++) { | |||
3924 | pDst[i] = m_vals[i] + pSrc[i]; | |||
3925 | } | |||
3926 | } | |||
3927 | } | |||
3928 | ||||
3929 | ||||
3930 | /** | |||
3931 | ************************************************************************** | |||
3932 | * Name: CIccPcsStepOffset::dump | |||
3933 | * | |||
3934 | * Purpose: | |||
3935 | * dumps the context of the step | |||
3936 | ************************************************************************** | |||
3937 | */ | |||
3938 | void CIccPcsStepOffset::dump(std::string &str) const | |||
3939 | { | |||
3940 | str += "\nCIccPcsStepOffset\n\n"; | |||
3941 | char buf[80]; | |||
3942 | for (int i=0; i<m_nChannels; i++) { | |||
3943 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | |||
3944 | str += buf; | |||
3945 | } | |||
3946 | str +="\n"; | |||
3947 | } | |||
3948 | ||||
3949 | ||||
3950 | /** | |||
3951 | ************************************************************************** | |||
3952 | * Name: CIccPcsStepOffset::Apply | |||
3953 | * | |||
3954 | * Purpose: | |||
3955 | * Creates a new CIccPcsStepOffet step that is the result of adding the | |||
3956 | * offset of this object to the offset of another object. | |||
3957 | ************************************************************************** | |||
3958 | */ | |||
3959 | CIccPcsStepOffset *CIccPcsStepOffset::Add(const CIccPcsStepOffset *offset) const | |||
3960 | { | |||
3961 | if (offset->m_nChannels != m_nChannels) | |||
3962 | return NULL__null; | |||
3963 | ||||
3964 | CIccPcsStepOffset *pNew = new CIccPcsStepOffset(m_nChannels); | |||
3965 | ||||
3966 | if (pNew) { | |||
3967 | int i; | |||
3968 | for (i=0; i<m_nChannels; i++) { | |||
3969 | pNew->m_vals[i] = m_vals[i] + offset->m_vals[i]; | |||
3970 | } | |||
3971 | } | |||
3972 | ||||
3973 | return pNew; | |||
3974 | } | |||
3975 | ||||
3976 | /** | |||
3977 | ************************************************************************** | |||
3978 | * Name: CIccPcsStepOffset::concat | |||
3979 | * | |||
3980 | * Purpose: | |||
3981 | * Determines if this step can be combined with the next step. | |||
3982 | * Checks if next step is a compatible icPcsStepOffset step resulting in a | |||
3983 | * single combined offset. | |||
3984 | ************************************************************************** | |||
3985 | */ | |||
3986 | CIccPcsStep *CIccPcsStepOffset::concat(CIccPcsStep *pNext) const | |||
3987 | { | |||
3988 | if (pNext && pNext->GetType()==icPcsStepOffset && m_nChannels==pNext->GetSrcChannels()) | |||
3989 | return Add((const CIccPcsStepOffset*)pNext); | |||
3990 | ||||
3991 | return NULL__null; | |||
3992 | } | |||
3993 | ||||
3994 | ||||
3995 | /** | |||
3996 | ************************************************************************** | |||
3997 | * Name: CIccPcsStepOffset::isIdentity | |||
3998 | * | |||
3999 | * Purpose: | |||
4000 | * Determines if applying this step will result in negligible change in data | |||
4001 | ************************************************************************** | |||
4002 | */ | |||
4003 | bool CIccPcsStepOffset::isIdentity() const | |||
4004 | { | |||
4005 | int i; | |||
4006 | for (i=0; i<m_nChannels; i++) { | |||
4007 | if (m_vals[i]<-icNearRange0.000001 || m_vals[i]>icNearRange0.000001) | |||
4008 | return false; | |||
4009 | } | |||
4010 | ||||
4011 | return true; | |||
4012 | } | |||
4013 | ||||
4014 | ||||
4015 | /** | |||
4016 | ************************************************************************** | |||
4017 | * Name: CIccPcsStepScale::CIccPcsStepScale | |||
4018 | * | |||
4019 | * Purpose: | |||
4020 | * Constructor | |||
4021 | ************************************************************************** | |||
4022 | */ | |||
4023 | CIccPcsStepScale::CIccPcsStepScale(icUInt16Number nChannels) | |||
4024 | { | |||
4025 | m_nChannels = nChannels; | |||
4026 | m_vals = new icFloatNumber[nChannels]; | |||
4027 | } | |||
4028 | ||||
4029 | ||||
4030 | /** | |||
4031 | ************************************************************************** | |||
4032 | * Name: CIccPcsStepScale::~CIccPcsStepScale | |||
4033 | * | |||
4034 | * Purpose: | |||
4035 | * Destructor | |||
4036 | ************************************************************************** | |||
4037 | */ | |||
4038 | CIccPcsStepScale::~CIccPcsStepScale() | |||
4039 | { | |||
4040 | if (m_vals) | |||
4041 | delete m_vals; | |||
4042 | } | |||
4043 | ||||
4044 | /** | |||
4045 | ************************************************************************** | |||
4046 | * Name: CIccPcsStepScale::Apply | |||
4047 | * | |||
4048 | * Purpose: | |||
4049 | * Multiplies fixed scale values to the pSrc vector passed in | |||
4050 | ************************************************************************** | |||
4051 | */ | |||
4052 | void CIccPcsStepScale::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
4053 | { | |||
4054 | if (m_nChannels==3) { | |||
4055 | pDst[0] = m_vals[0] * pSrc[0]; | |||
4056 | pDst[1] = m_vals[1] * pSrc[1]; | |||
4057 | pDst[2] = m_vals[2] * pSrc[2]; | |||
4058 | } | |||
4059 | else { | |||
4060 | int i; | |||
4061 | for (i=0; i<m_nChannels; i++) { | |||
4062 | pDst[i] = m_vals[i] * pSrc[i]; | |||
4063 | } | |||
4064 | } | |||
4065 | } | |||
4066 | ||||
4067 | ||||
4068 | /** | |||
4069 | ************************************************************************** | |||
4070 | * Name: CIccPcsStepScale::dump | |||
4071 | * | |||
4072 | * Purpose: | |||
4073 | * dumps the context of the step | |||
4074 | ************************************************************************** | |||
4075 | */ | |||
4076 | void CIccPcsStepScale::dump(std::string &str) const | |||
4077 | { | |||
4078 | str += "\nCIccPcsStepScale\n\n"; | |||
4079 | char buf[80]; | |||
4080 | for (int i=0; i<m_nChannels; i++) { | |||
4081 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | |||
4082 | str += buf; | |||
4083 | } | |||
4084 | str +="\n"; | |||
4085 | } | |||
4086 | ||||
4087 | ||||
4088 | /** | |||
4089 | ************************************************************************** | |||
4090 | * Name: CIccPcsStepScale::Mult | |||
4091 | * | |||
4092 | * Purpose: | |||
4093 | * Creates a new CIccPcsStepScale step that is the result of multiplying the | |||
4094 | * scale of this object to the scale of another object. | |||
4095 | ************************************************************************** | |||
4096 | */ | |||
4097 | CIccPcsStepScale *CIccPcsStepScale::Mult(const CIccPcsStepScale *scale) const | |||
4098 | { | |||
4099 | if (scale->m_nChannels != m_nChannels) | |||
4100 | return NULL__null; | |||
4101 | ||||
4102 | CIccPcsStepScale *pNew = new CIccPcsStepScale(m_nChannels); | |||
4103 | ||||
4104 | if (pNew) { | |||
4105 | int i; | |||
4106 | for (i=0; i<m_nChannels; i++) { | |||
4107 | pNew->m_vals[i] = m_vals[i] * scale->m_vals[i]; | |||
4108 | } | |||
4109 | } | |||
4110 | return pNew; | |||
4111 | } | |||
4112 | ||||
4113 | /** | |||
4114 | ************************************************************************** | |||
4115 | * Name: CIccPcsStepScale::Mult | |||
4116 | * | |||
4117 | * Purpose: | |||
4118 | * Creates a new CIccPcsStepMatrix step that is the result of multiplying the | |||
4119 | * scale of this object to the scale of another matrix. | |||
4120 | ************************************************************************** | |||
4121 | */ | |||
4122 | CIccPcsStepMatrix *CIccPcsStepScale::Mult(const CIccPcsStepMatrix *matrix) const | |||
4123 | { | |||
4124 | if (matrix->GetSrcChannels() != m_nChannels) | |||
4125 | return NULL__null; | |||
4126 | ||||
4127 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(matrix->GetDstChannels(), matrix->GetSrcChannels()); | |||
4128 | ||||
4129 | if (pNew) { | |||
4130 | int i, j; | |||
4131 | for (j=0; j<matrix->GetDstChannels(); j++) { | |||
4132 | const icFloatNumber *row = matrix->entry(j); | |||
4133 | icFloatNumber *to=pNew->entry(j); | |||
4134 | ||||
4135 | for (i=0; i<m_nChannels; i++) { | |||
4136 | to[i] = m_vals[i] * row[i]; | |||
4137 | } | |||
4138 | } | |||
4139 | } | |||
4140 | ||||
4141 | return pNew; | |||
4142 | } | |||
4143 | ||||
4144 | /** | |||
4145 | ************************************************************************** | |||
4146 | * Name: CIccPcsStepScale::Mult | |||
4147 | * | |||
4148 | * Purpose: | |||
4149 | * Creates a new CIccPcsStepMatrix step that is the result of multiplying the | |||
4150 | * scale of this object to the scale of another matrix. | |||
4151 | ************************************************************************** | |||
4152 | */ | |||
4153 | CIccPcsStepMatrix *CIccPcsStepScale::Mult(const CIccMpeMatrix *matrix) const | |||
4154 | { | |||
4155 | if (matrix->NumInputChannels() != m_nChannels) | |||
4156 | return NULL__null; | |||
4157 | ||||
4158 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(matrix->NumOutputChannels(), matrix->NumInputChannels()); | |||
4159 | ||||
4160 | if (pNew) { | |||
4161 | int i, j; | |||
4162 | icFloatNumber *mtx = matrix->GetMatrix(); | |||
4163 | for (j = 0; j < matrix->NumOutputChannels(); j++) { | |||
4164 | const icFloatNumber *row = &mtx[j*matrix->NumInputChannels()]; | |||
4165 | icFloatNumber *to = pNew->entry(j); | |||
4166 | ||||
4167 | for (i = 0; i < m_nChannels; i++) { | |||
4168 | to[i] = m_vals[i] * row[i]; | |||
4169 | } | |||
4170 | } | |||
4171 | } | |||
4172 | ||||
4173 | return pNew; | |||
4174 | } | |||
4175 | ||||
4176 | ||||
4177 | /** | |||
4178 | ************************************************************************** | |||
4179 | * Name: CIccPcsStepScale::concat | |||
4180 | * | |||
4181 | * Purpose: | |||
4182 | * Determines if this step can be combined with the next step. | |||
4183 | * Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step | |||
4184 | * resulting in a single combined object. | |||
4185 | ************************************************************************** | |||
4186 | */ | |||
4187 | CIccPcsStep *CIccPcsStepScale::concat(CIccPcsStep *pNext) const | |||
4188 | { | |||
4189 | if (pNext) { | |||
4190 | if (pNext->GetType()==icPcsStepScale && m_nChannels==pNext->GetSrcChannels()) | |||
4191 | return Mult((const CIccPcsStepScale*)pNext); | |||
4192 | if (pNext->GetType()==icPcsStepMatrix && m_nChannels==pNext->GetSrcChannels()) | |||
4193 | return Mult((const CIccPcsStepMatrix*)pNext); | |||
4194 | if (pNext->GetType() == icPcsStepMpe && m_nChannels == pNext->GetSrcChannels()) { | |||
4195 | CIccPcsStepMpe *pMpe = (CIccPcsStepMpe*)pNext; | |||
4196 | CIccMpeMatrix *pMatrix = pMpe->GetMatrix(); | |||
4197 | if (pMatrix) | |||
4198 | return Mult(pMatrix); | |||
4199 | } | |||
4200 | } | |||
4201 | ||||
4202 | return NULL__null; | |||
4203 | } | |||
4204 | ||||
4205 | ||||
4206 | /** | |||
4207 | ************************************************************************** | |||
4208 | * Name: CIccPcsStepScale::isIdentity | |||
4209 | * | |||
4210 | * Purpose: | |||
4211 | * Determines if applying this step will result in negligible change in data | |||
4212 | ************************************************************************** | |||
4213 | */ | |||
4214 | bool CIccPcsStepScale::isIdentity() const | |||
4215 | { | |||
4216 | int i; | |||
4217 | for (i=0; i<m_nChannels; i++) { | |||
4218 | if (m_vals[i]<1.0f-icNearRange0.000001 || m_vals[i]>1.0f+icNearRange0.000001) | |||
4219 | return false; | |||
4220 | } | |||
4221 | ||||
4222 | return true; | |||
4223 | } | |||
4224 | ||||
4225 | ||||
4226 | ||||
4227 | /** | |||
4228 | ************************************************************************** | |||
4229 | * Name: CIccPcsStepMatrix::dump | |||
4230 | * | |||
4231 | * Purpose: | |||
4232 | * dumps the context of the step | |||
4233 | ************************************************************************** | |||
4234 | */ | |||
4235 | void CIccPcsStepMatrix::dump(std::string &str) const | |||
4236 | { | |||
4237 | str += "\nCIccPcsStepMatrix\n\n"; | |||
4238 | dumpMtx(str); | |||
4239 | } | |||
4240 | ||||
4241 | ||||
4242 | /** | |||
4243 | ************************************************************************** | |||
4244 | * Name: CIccPcsStepMatrix::Mult | |||
4245 | * | |||
4246 | * Purpose: | |||
4247 | * Creates a new CIccPcsStepMatrix step that is the result of multiplying the | |||
4248 | * matrix of this object to the scale of another object. | |||
4249 | ************************************************************************** | |||
4250 | */ | |||
4251 | CIccPcsStepMatrix *CIccPcsStepMatrix::Mult(const CIccPcsStepScale *scale) const | |||
4252 | { | |||
4253 | icUInt16Number mCols = scale->GetSrcChannels(); | |||
4254 | icUInt16Number mRows = mCols; | |||
4255 | ||||
4256 | if (m_nRows != mCols) | |||
4257 | return NULL__null; | |||
4258 | ||||
4259 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(m_nRows, m_nCols); | |||
4260 | const icFloatNumber *data = scale->data(); | |||
4261 | ||||
4262 | int i, j; | |||
4263 | for (j=0; j<m_nRows; j++) { | |||
4264 | const icFloatNumber *row = entry(j); | |||
4265 | icFloatNumber *to = pNew->entry(j); | |||
4266 | for (i=0; i<m_nCols; i++) { | |||
4267 | to[i] = data[j] * row[i]; | |||
4268 | } | |||
4269 | } | |||
4270 | ||||
4271 | return pNew; | |||
4272 | } | |||
4273 | ||||
4274 | /** | |||
4275 | ************************************************************************** | |||
4276 | * Name: CIccPcsStepMatrix::Mult | |||
4277 | * | |||
4278 | * Purpose: | |||
4279 | * Creates a new CIccPcsStepMatrix step that is the result of concatentating | |||
4280 | * another matrix with this matrix. (IE result = matrix * this). | |||
4281 | ************************************************************************** | |||
4282 | */ | |||
4283 | CIccPcsStepMatrix *CIccPcsStepMatrix::Mult(const CIccPcsStepMatrix *matrix) const | |||
4284 | { | |||
4285 | icUInt16Number mCols = matrix->m_nCols; | |||
4286 | icUInt16Number mRows = matrix->m_nRows; | |||
4287 | ||||
4288 | if (m_nRows != mCols) | |||
4289 | return NULL__null; | |||
4290 | ||||
4291 | CIccPcsStepMatrix *pNew = new CIccPcsStepMatrix(mRows, m_nCols); | |||
4292 | ||||
4293 | int i, j, k; | |||
4294 | for (j=0; j<mRows; j++) { | |||
4295 | const icFloatNumber *row = matrix->entry(j); | |||
4296 | for (i=0; i<m_nCols; i++) { | |||
4297 | icFloatNumber *to = pNew->entry(j, i); | |||
4298 | const icFloatNumber *from = entry(0, i); | |||
4299 | ||||
4300 | *to = 0.0f; | |||
4301 | for (k=0; k<m_nRows; k++) { | |||
4302 | *to += row[k] * (*from); | |||
4303 | from += m_nCols; | |||
4304 | } | |||
4305 | } | |||
4306 | } | |||
4307 | ||||
4308 | return pNew; | |||
4309 | } | |||
4310 | ||||
4311 | ||||
4312 | /** | |||
4313 | ************************************************************************** | |||
4314 | * Name: CIccPcsStepMatrix::concat | |||
4315 | * | |||
4316 | * Purpose: | |||
4317 | * Determines if this step can be combined with the next step. | |||
4318 | * Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step | |||
4319 | * resulting in a single combined object. | |||
4320 | ************************************************************************** | |||
4321 | */ | |||
4322 | CIccPcsStep *CIccPcsStepMatrix::concat(CIccPcsStep *pNext) const | |||
4323 | { | |||
4324 | if (pNext) { | |||
4325 | if (pNext->GetType()==icPcsStepScale && GetDstChannels()==pNext->GetSrcChannels()) | |||
4326 | return Mult((const CIccPcsStepScale*)pNext); | |||
4327 | if (pNext->GetType()==icPcsStepMatrix && GetDstChannels()==pNext->GetSrcChannels()) | |||
4328 | return Mult((const CIccPcsStepMatrix*)pNext); | |||
4329 | } | |||
4330 | ||||
4331 | return NULL__null; | |||
4332 | } | |||
4333 | ||||
4334 | /** | |||
4335 | ************************************************************************** | |||
4336 | * Name: CIccPcsStepMatrix::concat | |||
4337 | * | |||
4338 | * Purpose: | |||
4339 | * Determines if this step can be combined with the next step. | |||
4340 | * Checks if next step is a compatible icPcsStepScale or icPcsStepMatrix step | |||
4341 | * resulting in a single combined object. | |||
4342 | ************************************************************************** | |||
4343 | */ | |||
4344 | CIccPcsStep *CIccPcsStepMatrix::reduce() const | |||
4345 | { | |||
4346 | int nVals = m_nRows*m_nCols; | |||
4347 | int nNonZeros = 0; | |||
4348 | int i; | |||
4349 | ||||
4350 | for (i=0; i<nVals; i++) { | |||
4351 | icFloatNumber v = m_vals[i]; | |||
4352 | if (icNotZero(v)((v)>1.0e-8 || (v)<-1.0e-8)) | |||
4353 | nNonZeros++; | |||
4354 | } | |||
4355 | if (nNonZeros<nVals*3/4) { | |||
4356 | icUInt32Number nMatrixBytes = CIccSparseMatrix::MemSize(nNonZeros, m_nRows, sizeof(icFloatNumber))+4*sizeof(icFloatNumber); | |||
4357 | CIccPcsStepSparseMatrix *pMtx = new CIccPcsStepSparseMatrix(m_nRows, m_nCols, nMatrixBytes); | |||
4358 | CIccSparseMatrix mtx(pMtx->data(), nMatrixBytes); | |||
4359 | mtx.Init(m_nRows, m_nCols, true); | |||
4360 | mtx.FillFromFullMatrix(m_vals); | |||
4361 | return pMtx; | |||
4362 | } | |||
4363 | ||||
4364 | return (CIccPcsStep*)this; | |||
4365 | } | |||
4366 | ||||
4367 | ||||
4368 | ||||
4369 | /** | |||
4370 | ************************************************************************** | |||
4371 | * Name: CIccPcsStepMpe::CIccPcsStepMpe | |||
4372 | * | |||
4373 | * Purpose: | |||
4374 | * Constructor | |||
4375 | ************************************************************************** | |||
4376 | */ | |||
4377 | CIccPcsStepMpe::CIccPcsStepMpe(CIccTagMultiProcessElement *pMpe) | |||
4378 | { | |||
4379 | m_pMpe = pMpe; | |||
4380 | } | |||
4381 | ||||
4382 | ||||
4383 | /** | |||
4384 | ************************************************************************** | |||
4385 | * Name: CIccPcsStepMpe::~CIccPcsStepMpe | |||
4386 | * | |||
4387 | * Purpose: | |||
4388 | * Destructor | |||
4389 | ************************************************************************** | |||
4390 | */ | |||
4391 | CIccPcsStepMpe::~CIccPcsStepMpe() | |||
4392 | { | |||
4393 | if (m_pMpe) | |||
4394 | delete m_pMpe; | |||
4395 | } | |||
4396 | ||||
4397 | ||||
4398 | /** | |||
4399 | ************************************************************************** | |||
4400 | * Name: CIccPcsStepMpe::GetNewApply | |||
4401 | * | |||
4402 | * Purpose: | |||
4403 | * Allocates a new CIccApplyPcsStep to be used with processing. | |||
4404 | ************************************************************************** | |||
4405 | */ | |||
4406 | CIccApplyPcsStep* CIccPcsStepMpe::GetNewApply() | |||
4407 | { | |||
4408 | CIccApplyPcsStepMpe *rv = new CIccApplyPcsStepMpe(this, m_pMpe->GetNewApply()); | |||
4409 | ||||
4410 | return rv; | |||
4411 | } | |||
4412 | ||||
4413 | ||||
4414 | /** | |||
4415 | ************************************************************************** | |||
4416 | * Name: CIccPcsStepMpe::Apply | |||
4417 | * | |||
4418 | * Purpose: | |||
4419 | * Applies a MultiProcessingElement to a Source vector to get a Dest vector | |||
4420 | ************************************************************************** | |||
4421 | */ | |||
4422 | void CIccPcsStepMpe::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
4423 | { | |||
4424 | CIccApplyPcsStepMpe *pMpeApply = (CIccApplyPcsStepMpe*)pApply; | |||
4425 | ||||
4426 | m_pMpe->Apply(pMpeApply->m_pApply, pDst, pSrc); | |||
4427 | } | |||
4428 | ||||
4429 | ||||
4430 | /** | |||
4431 | ************************************************************************** | |||
4432 | * Name: CIccPcsStepMpe::dump | |||
4433 | * | |||
4434 | * Purpose: | |||
4435 | * dumps the context of the step | |||
4436 | ************************************************************************** | |||
4437 | */ | |||
4438 | void CIccPcsStepMpe::dump(std::string &str) const | |||
4439 | { | |||
4440 | str += "\nCIccPcsStepMpe\n\n"; | |||
4441 | m_pMpe->Describe(str); | |||
4442 | } | |||
4443 | ||||
4444 | ||||
4445 | /** | |||
4446 | ************************************************************************** | |||
4447 | * Name: CIccPcsStepMpe::isIdentity | |||
4448 | * | |||
4449 | * Purpose: | |||
4450 | * Determines if applying this step will obviously result in no change in data | |||
4451 | ************************************************************************** | |||
4452 | */ | |||
4453 | bool CIccPcsStepMpe::isIdentity() const | |||
4454 | { | |||
4455 | if (!m_pMpe || !m_pMpe->NumElements()) | |||
4456 | return true; | |||
4457 | return false; | |||
4458 | } | |||
4459 | ||||
4460 | /** | |||
4461 | ************************************************************************** | |||
4462 | * Name: CIccPcsStepMpe::GetSrcChannels | |||
4463 | * | |||
4464 | * Purpose: | |||
4465 | * Returns the number of channels of data required going into the multi- | |||
4466 | * processing element | |||
4467 | ************************************************************************** | |||
4468 | */ | |||
4469 | icUInt16Number CIccPcsStepMpe::GetSrcChannels() const | |||
4470 | { | |||
4471 | return m_pMpe->NumInputChannels(); | |||
4472 | } | |||
4473 | ||||
4474 | ||||
4475 | /** | |||
4476 | ************************************************************************** | |||
4477 | * Name: CIccPcsStepMpe::GetDstChannels | |||
4478 | * | |||
4479 | * Purpose: | |||
4480 | * Returns the number of channels of data coming out of the multi- | |||
4481 | * processing element | |||
4482 | ************************************************************************** | |||
4483 | */ | |||
4484 | icUInt16Number CIccPcsStepMpe::GetDstChannels() const | |||
4485 | { | |||
4486 | return m_pMpe->NumOutputChannels(); | |||
4487 | } | |||
4488 | ||||
4489 | ||||
4490 | /** | |||
4491 | ************************************************************************** | |||
4492 | * Name: CIccPcsStepMpe::GetMatrix() | |||
4493 | * | |||
4494 | * Purpose: | |||
4495 | * Returns single CIccMpeMatrix element associated with PCS step or | |||
4496 | * NULL if the MPE is more complex | |||
4497 | ************************************************************************** | |||
4498 | */ | |||
4499 | CIccMpeMatrix *CIccPcsStepMpe::GetMatrix() const | |||
4500 | { | |||
4501 | //Must be single element | |||
4502 | if (m_pMpe->NumElements() == 1) { | |||
4503 | CIccMultiProcessElement *pElem = m_pMpe->GetElement(0); | |||
4504 | //Must be a matrix | |||
4505 | if (pElem && pElem->GetType() == icSigMatrixElemType) { | |||
4506 | CIccMpeMatrix *pMtx = (CIccMpeMatrix*)pElem; | |||
4507 | ||||
4508 | //Should not apply any constants | |||
4509 | if (!pMtx->GetConstants() || !pMtx->GetApplyConstants()) | |||
4510 | return pMtx; | |||
4511 | } | |||
4512 | } | |||
4513 | ||||
4514 | return NULL__null; | |||
4515 | } | |||
4516 | ||||
4517 | ||||
4518 | ||||
4519 | ||||
4520 | /** | |||
4521 | ************************************************************************** | |||
4522 | * Name: CIccPcsStepMpe::Begin | |||
4523 | * | |||
4524 | * Purpose: | |||
4525 | * Initializes multi-processing element for processing. Must be called before | |||
4526 | * Apply is called | |||
4527 | ************************************************************************** | |||
4528 | */ | |||
4529 | bool CIccPcsStepMpe::Begin() | |||
4530 | { | |||
4531 | return m_pMpe->Begin(); | |||
4532 | } | |||
4533 | ||||
4534 | ||||
4535 | /** | |||
4536 | ************************************************************************** | |||
4537 | * Name: CIccPcsStepSrcMatrix::CIccPcsStepSrcMatrix | |||
4538 | * | |||
4539 | * Purpose: | |||
4540 | * Constructor | |||
4541 | ************************************************************************** | |||
4542 | */ | |||
4543 | CIccPcsStepSrcMatrix::CIccPcsStepSrcMatrix(icUInt16Number nRows, icUInt16Number nCols) | |||
4544 | { | |||
4545 | m_nRows = nRows; | |||
4546 | m_nCols = nCols; | |||
4547 | m_vals = new icFloatNumber[nCols]; | |||
4548 | } | |||
4549 | ||||
4550 | ||||
4551 | /** | |||
4552 | ************************************************************************** | |||
4553 | * Name: CIccPcsStepSrcMatrix::~CIccPcsStepSrcMatrix | |||
4554 | * | |||
4555 | * Purpose: | |||
4556 | * Destructor | |||
4557 | ************************************************************************** | |||
4558 | */ | |||
4559 | CIccPcsStepSrcMatrix::~CIccPcsStepSrcMatrix() | |||
4560 | { | |||
4561 | if (m_vals) | |||
4562 | delete m_vals; | |||
4563 | } | |||
4564 | ||||
4565 | ||||
4566 | /** | |||
4567 | ************************************************************************** | |||
4568 | * Name: CIccPcsStepSrcMatrix::Apply | |||
4569 | * | |||
4570 | * Purpose: | |||
4571 | * Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting | |||
4572 | * in a pDst vector | |||
4573 | ************************************************************************** | |||
4574 | */ | |||
4575 | void CIccPcsStepSrcMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
4576 | { | |||
4577 | int i, j; | |||
4578 | const icFloatNumber *row = pSrc; | |||
4579 | for (j=0; j<m_nRows; j++) { | |||
4580 | pDst[j] = 0.0f; | |||
4581 | for (i=0; i<m_nCols; i++) { | |||
4582 | pDst[j] += row[i] * m_vals[i]; | |||
4583 | } | |||
4584 | row += m_nCols; | |||
4585 | } | |||
4586 | } | |||
4587 | ||||
4588 | ||||
4589 | /** | |||
4590 | ************************************************************************** | |||
4591 | * Name: CIccPcsStepSrcMatrix::dump | |||
4592 | * | |||
4593 | * Purpose: | |||
4594 | * dumps the context of the step | |||
4595 | ************************************************************************** | |||
4596 | */ | |||
4597 | void CIccPcsStepSrcMatrix::dump(std::string &str) const | |||
4598 | { | |||
4599 | str += "\nCIccPcsStepSrcMatrix\n\n"; | |||
4600 | char buf[80]; | |||
4601 | for (int i=0; i<m_nCols; i++) { | |||
4602 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | |||
4603 | str += buf; | |||
4604 | } | |||
4605 | str += "\n"; | |||
4606 | } | |||
4607 | ||||
4608 | ||||
4609 | /** | |||
4610 | ************************************************************************** | |||
4611 | * Name: CIccPcsStepSparseMatrix::CIccPcsStepSparseMatrix | |||
4612 | * | |||
4613 | * Purpose: | |||
4614 | * Constructor | |||
4615 | ************************************************************************** | |||
4616 | */ | |||
4617 | CIccPcsStepSparseMatrix::CIccPcsStepSparseMatrix(icUInt16Number nRows, icUInt16Number nCols, icUInt32Number nBytesPerMatrix) | |||
4618 | { | |||
4619 | m_nRows = nRows; | |||
4620 | m_nCols = nCols; | |||
4621 | m_nBytesPerMatrix = nBytesPerMatrix; | |||
4622 | ||||
4623 | m_vals = new icFloatNumber[m_nBytesPerMatrix/sizeof(icFloatNumber)]; | |||
4624 | } | |||
4625 | ||||
4626 | ||||
4627 | /** | |||
4628 | ************************************************************************** | |||
4629 | * Name: CIccPcsStepSparseMatrix::~CIccPcsStepSparseMatrix | |||
4630 | * | |||
4631 | * Purpose: | |||
4632 | * Destructor | |||
4633 | ************************************************************************** | |||
4634 | */ | |||
4635 | CIccPcsStepSparseMatrix::~CIccPcsStepSparseMatrix() | |||
4636 | { | |||
4637 | if (m_vals) | |||
4638 | delete [] m_vals; | |||
4639 | } | |||
4640 | ||||
4641 | ||||
4642 | /** | |||
4643 | ************************************************************************** | |||
4644 | * Name: CIccPcsStepSparseMatrix::Apply | |||
4645 | * | |||
4646 | * Purpose: | |||
4647 | * Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting | |||
4648 | * in a pDst vector | |||
4649 | ************************************************************************** | |||
4650 | */ | |||
4651 | void CIccPcsStepSparseMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
4652 | { | |||
4653 | CIccSparseMatrix mtx((icUInt8Number*)m_vals, m_nBytesPerMatrix, icSparseMatrixFloatNum((icSparseMatrixType)0x0000), true); | |||
4654 | ||||
4655 | mtx.MultiplyVector(pDst, pSrc); | |||
4656 | } | |||
4657 | ||||
4658 | ||||
4659 | /** | |||
4660 | ************************************************************************** | |||
4661 | * Name: CIccPcsStepSparseMatrix::dump | |||
4662 | * | |||
4663 | * Purpose: | |||
4664 | * dumps the context of the step | |||
4665 | ************************************************************************** | |||
4666 | */ | |||
4667 | void CIccPcsStepSparseMatrix::dump(std::string &str) const | |||
4668 | { | |||
4669 | str += "\nCIccPcsStepSparseMatrix\n\n"; | |||
4670 | // char buf[80]; | |||
4671 | // for (int i=0; i<m_nCols; i++) { | |||
4672 | // sprintf(buf, ICCPCSSTEPDUMPFMT, m_vals[i]); | |||
4673 | // str += buf; | |||
4674 | // } | |||
4675 | // str += "\n"; | |||
4676 | } | |||
4677 | ||||
4678 | ||||
4679 | /** | |||
4680 | ************************************************************************** | |||
4681 | * Name: CIccPcsStepSrcSparseMatrix::CIccPcsStepSrcSparseMatrix | |||
4682 | * | |||
4683 | * Purpose: | |||
4684 | * Constructor | |||
4685 | ************************************************************************** | |||
4686 | */ | |||
4687 | CIccPcsStepSrcSparseMatrix::CIccPcsStepSrcSparseMatrix(icUInt16Number nRows, icUInt16Number nCols, icUInt16Number nChannels) | |||
4688 | { | |||
4689 | m_nRows = nRows; | |||
4690 | m_nCols = nCols; | |||
4691 | m_nChannels = nChannels; | |||
4692 | m_nBytesPerMatrix = nChannels * sizeof(icFloatNumber); | |||
4693 | ||||
4694 | m_vals = new icFloatNumber[nCols]; | |||
4695 | } | |||
4696 | ||||
4697 | ||||
4698 | /** | |||
4699 | ************************************************************************** | |||
4700 | * Name: CIccPcsStepSrcSparseMatrix::~CIccPcsSrcStepSparseMatrix | |||
4701 | * | |||
4702 | * Purpose: | |||
4703 | * Destructor | |||
4704 | ************************************************************************** | |||
4705 | */ | |||
4706 | CIccPcsStepSrcSparseMatrix::~CIccPcsStepSrcSparseMatrix() | |||
4707 | { | |||
4708 | if (m_vals) | |||
4709 | delete [] m_vals; | |||
4710 | } | |||
4711 | ||||
4712 | ||||
4713 | /** | |||
4714 | ************************************************************************** | |||
4715 | * Name: CIccPcsStepSrcSparseMatrix::Apply | |||
4716 | * | |||
4717 | * Purpose: | |||
4718 | * Multiplies illuminant stored in m_vals by pSrc matrix passed in resulting | |||
4719 | * in a pDst vector | |||
4720 | ************************************************************************** | |||
4721 | */ | |||
4722 | void CIccPcsStepSrcSparseMatrix::Apply(CIccApplyPcsStep *pApply, icFloatNumber *pDst, const icFloatNumber *pSrc) const | |||
4723 | { | |||
4724 | CIccSparseMatrix mtx((icUInt8Number*)pSrc, m_nBytesPerMatrix, icSparseMatrixFloatNum((icSparseMatrixType)0x0000), true); | |||
4725 | ||||
4726 | mtx.MultiplyVector(pDst, m_vals); | |||
4727 | } | |||
4728 | ||||
4729 | ||||
4730 | /** | |||
4731 | ************************************************************************** | |||
4732 | * Name: CIccPcsStepSrcSparseMatrix::dump | |||
4733 | * | |||
4734 | * Purpose: | |||
4735 | * dumps the context of the step | |||
4736 | ************************************************************************** | |||
4737 | */ | |||
4738 | void CIccPcsStepSrcSparseMatrix::dump(std::string &str) const | |||
4739 | { | |||
4740 | str += "\nCIccPcsStepSrcSparseMatrix\n\n"; | |||
4741 | char buf[80]; | |||
4742 | for (int i=0; i<m_nCols; i++) { | |||
4743 | sprintf(buf, ICCPCSSTEPDUMPFMT" %.8f", m_vals[i]); | |||
4744 | str += buf; | |||
4745 | } | |||
4746 | str += "\n"; | |||
4747 | } | |||
4748 | ||||
4749 | ||||
4750 | /** | |||
4751 | ************************************************************************** | |||
4752 | * Name: CIccXformMonochrome::CIccXformMonochrome | |||
4753 | * | |||
4754 | * Purpose: | |||
4755 | * Constructor | |||
4756 | ************************************************************************** | |||
4757 | */ | |||
4758 | CIccXformMonochrome::CIccXformMonochrome() | |||
4759 | { | |||
4760 | m_Curve = NULL__null; | |||
4761 | m_ApplyCurvePtr = NULL__null; | |||
4762 | m_bFreeCurve = false; | |||
4763 | } | |||
4764 | ||||
4765 | /** | |||
4766 | ************************************************************************** | |||
4767 | * Name: CIccXformMonochrome::~CIccXformMonochrome | |||
4768 | * | |||
4769 | * Purpose: | |||
4770 | * Destructor | |||
4771 | ************************************************************************** | |||
4772 | */ | |||
4773 | CIccXformMonochrome::~CIccXformMonochrome() | |||
4774 | { | |||
4775 | if (m_bFreeCurve && m_Curve) { | |||
4776 | delete m_Curve; | |||
4777 | } | |||
4778 | } | |||
4779 | ||||
4780 | /** | |||
4781 | ************************************************************************** | |||
4782 | * Name: CIccXformMonochrome::Begin | |||
4783 | * | |||
4784 | * Purpose: | |||
4785 | * Does the initialization of the Xform before Apply() is called. | |||
4786 | * Must be called before Apply(). | |||
4787 | * | |||
4788 | ************************************************************************** | |||
4789 | */ | |||
4790 | icStatusCMM CIccXformMonochrome::Begin() | |||
4791 | { | |||
4792 | icStatusCMM status; | |||
4793 | ||||
4794 | status = CIccXform::Begin(); | |||
4795 | if (status != icCmmStatOk) | |||
4796 | return status; | |||
4797 | ||||
4798 | m_ApplyCurvePtr = NULL__null; | |||
4799 | ||||
4800 | if (m_bInput) { | |||
4801 | m_Curve = GetCurve(icSigGrayTRCTag); | |||
4802 | ||||
4803 | if (!m_Curve) { | |||
4804 | return icCmmStatProfileMissingTag; | |||
4805 | } | |||
4806 | } | |||
4807 | else { | |||
4808 | m_Curve = GetInvCurve(icSigGrayTRCTag); | |||
4809 | m_bFreeCurve = true; | |||
4810 | ||||
4811 | if (!m_Curve) { | |||
4812 | return icCmmStatProfileMissingTag; | |||
4813 | } | |||
4814 | } | |||
4815 | ||||
4816 | m_Curve->Begin(); | |||
4817 | if (!m_Curve->IsIdentity()) { | |||
4818 | m_ApplyCurvePtr = m_Curve; | |||
4819 | } | |||
4820 | ||||
4821 | return icCmmStatOk; | |||
4822 | } | |||
4823 | ||||
4824 | /** | |||
4825 | ************************************************************************** | |||
4826 | * Name: CIccXformMonochrome::Apply | |||
4827 | * | |||
4828 | * Purpose: | |||
4829 | * Does the actual application of the Xform. | |||
4830 | * | |||
4831 | * Args: | |||
4832 | * pApply = ApplyXform object containing temporary storage used during Apply | |||
4833 | * DstPixel = Destination pixel where the result is stored, | |||
4834 | * SrcPixel = Source pixel which is to be applied. | |||
4835 | ************************************************************************** | |||
4836 | */ | |||
4837 | void CIccXformMonochrome::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
4838 | { | |||
4839 | icFloatNumber Pixel[3]; | |||
4840 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
4841 | ||||
4842 | if (m_bInput) { | |||
4843 | Pixel[0] = SrcPixel[0]; | |||
4844 | ||||
4845 | if (m_ApplyCurvePtr) { | |||
4846 | Pixel[0] = m_ApplyCurvePtr->Apply(Pixel[0]); | |||
4847 | } | |||
4848 | ||||
4849 | DstPixel[0] = icFloatNumber(icPerceptualRefWhiteX0.9642); | |||
4850 | DstPixel[1] = icFloatNumber(icPerceptualRefWhiteY1.0000); | |||
4851 | DstPixel[2] = icFloatNumber(icPerceptualRefWhiteZ0.8249); | |||
4852 | ||||
4853 | icXyzToPcs(DstPixel); | |||
4854 | ||||
4855 | if (m_pProfile->m_Header.pcs==icSigLabData) { | |||
4856 | if (UseLegacyPCS()) { | |||
4857 | CIccPCS::XyzToLab2(DstPixel, DstPixel, true); | |||
4858 | } | |||
4859 | else { | |||
4860 | CIccPCS::XyzToLab(DstPixel, DstPixel, true); | |||
4861 | } | |||
4862 | } | |||
4863 | ||||
4864 | DstPixel[0] *= Pixel[0]; | |||
4865 | DstPixel[1] *= Pixel[0]; | |||
4866 | DstPixel[2] *= Pixel[0]; | |||
4867 | } | |||
4868 | else { | |||
4869 | Pixel[0] = icFloatNumber(icPerceptualRefWhiteX0.9642); | |||
4870 | Pixel[1] = icFloatNumber(icPerceptualRefWhiteY1.0000); | |||
4871 | Pixel[2] = icFloatNumber(icPerceptualRefWhiteZ0.8249); | |||
4872 | ||||
4873 | icXyzToPcs(Pixel); | |||
4874 | ||||
4875 | if (m_pProfile->m_Header.pcs==icSigLabData) { | |||
4876 | if (UseLegacyPCS()) { | |||
4877 | CIccPCS::XyzToLab2(Pixel, Pixel, true); | |||
4878 | } | |||
4879 | else { | |||
4880 | CIccPCS::XyzToLab(Pixel, Pixel, true); | |||
4881 | } | |||
4882 | DstPixel[0] = SrcPixel[0]/Pixel[0]; | |||
4883 | } | |||
4884 | else { | |||
4885 | DstPixel[0] = SrcPixel[1]/Pixel[1]; | |||
4886 | } | |||
4887 | ||||
4888 | if (m_ApplyCurvePtr) { | |||
4889 | DstPixel[0] = m_ApplyCurvePtr->Apply(DstPixel[0]); | |||
4890 | } | |||
4891 | } | |||
4892 | ||||
4893 | CheckDstAbs(DstPixel); | |||
4894 | } | |||
4895 | ||||
4896 | /** | |||
4897 | ************************************************************************** | |||
4898 | * Name: CIccXformMonochrome::GetCurve | |||
4899 | * | |||
4900 | * Purpose: | |||
4901 | * Gets the curve having the passed signature, from the profile. | |||
4902 | * | |||
4903 | * Args: | |||
4904 | * sig = signature of the curve to be found | |||
4905 | * | |||
4906 | * Return: | |||
4907 | * Pointer to the curve. | |||
4908 | ************************************************************************** | |||
4909 | */ | |||
4910 | CIccCurve *CIccXformMonochrome::GetCurve(icSignature sig) const | |||
4911 | { | |||
4912 | CIccTag *pTag = m_pProfile->FindTag(sig); | |||
4913 | ||||
4914 | if (pTag && (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType)) { | |||
4915 | return (CIccCurve*)pTag; | |||
4916 | } | |||
4917 | ||||
4918 | return NULL__null; | |||
4919 | } | |||
4920 | ||||
4921 | /** | |||
4922 | ************************************************************************** | |||
4923 | * Name: CIccXformMonochrome::GetInvCurve | |||
4924 | * | |||
4925 | * Purpose: | |||
4926 | * Gets the inverted curve having the passed signature, from the profile. | |||
4927 | * | |||
4928 | * Args: | |||
4929 | * sig = signature of the curve to be inverted | |||
4930 | * | |||
4931 | * Return: | |||
4932 | * Pointer to the inverted curve. | |||
4933 | ************************************************************************** | |||
4934 | */ | |||
4935 | CIccCurve *CIccXformMonochrome::GetInvCurve(icSignature sig) const | |||
4936 | { | |||
4937 | CIccCurve *pCurve; | |||
4938 | CIccTagCurve *pInvCurve; | |||
4939 | ||||
4940 | if (!(pCurve = GetCurve(sig))) | |||
4941 | return NULL__null; | |||
4942 | ||||
4943 | pCurve->Begin(); | |||
4944 | ||||
4945 | pInvCurve = new CIccTagCurve(2048); | |||
4946 | ||||
4947 | int i; | |||
4948 | icFloatNumber x; | |||
4949 | icFloatNumber *Lut = &(*pInvCurve)[0]; | |||
4950 | ||||
4951 | for (i=0; i<2048; i++) { | |||
4952 | x=(icFloatNumber)i / 2047; | |||
4953 | ||||
4954 | Lut[i] = pCurve->Find(x); | |||
4955 | } | |||
4956 | ||||
4957 | return pInvCurve; | |||
4958 | } | |||
4959 | ||||
4960 | /** | |||
4961 | ************************************************************************** | |||
4962 | * Name: CIccXformMonochrome::ExtractInputCurves | |||
4963 | * | |||
4964 | * Purpose: | |||
4965 | * Gets the input curves. Should be called only after Begin() | |||
4966 | * has been called. Once the curves are extracted, they will | |||
4967 | * not be used by the Apply() function. | |||
4968 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
4969 | * | |||
4970 | * Return: | |||
4971 | * Pointer to the input curves. | |||
4972 | ************************************************************************** | |||
4973 | */ | |||
4974 | LPIccCurve* CIccXformMonochrome::ExtractInputCurves() | |||
4975 | { | |||
4976 | if (m_bInput) { | |||
4977 | if (m_Curve) { | |||
4978 | LPIccCurve* Curve = new LPIccCurve[1]; | |||
4979 | Curve[0] = (LPIccCurve)(m_Curve->NewCopy()); | |||
4980 | m_ApplyCurvePtr = NULL__null; | |||
4981 | return Curve; | |||
4982 | } | |||
4983 | } | |||
4984 | ||||
4985 | return NULL__null; | |||
4986 | } | |||
4987 | ||||
4988 | /** | |||
4989 | ************************************************************************** | |||
4990 | * Name: CIccXformMonochrome::ExtractOutputCurves | |||
4991 | * | |||
4992 | * Purpose: | |||
4993 | * Gets the output curves. Should be called only after Begin() | |||
4994 | * has been called. Once the curves are extracted, they will | |||
4995 | * not be used by the Apply() function. | |||
4996 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
4997 | * | |||
4998 | * Return: | |||
4999 | * Pointer to the output curves. | |||
5000 | ************************************************************************** | |||
5001 | */ | |||
5002 | LPIccCurve* CIccXformMonochrome::ExtractOutputCurves() | |||
5003 | { | |||
5004 | if (!m_bInput) { | |||
5005 | if (m_Curve) { | |||
5006 | LPIccCurve* Curve = new LPIccCurve[1]; | |||
5007 | Curve[0] = (LPIccCurve)(m_Curve->NewCopy()); | |||
5008 | m_ApplyCurvePtr = NULL__null; | |||
5009 | return Curve; | |||
5010 | } | |||
5011 | } | |||
5012 | ||||
5013 | return NULL__null; | |||
5014 | } | |||
5015 | ||||
5016 | /** | |||
5017 | ************************************************************************** | |||
5018 | * Name: CIccXformMatrixTRC::CIccXformMatrixTRC | |||
5019 | * | |||
5020 | * Purpose: | |||
5021 | * Constructor | |||
5022 | ************************************************************************** | |||
5023 | */ | |||
5024 | CIccXformMatrixTRC::CIccXformMatrixTRC() | |||
5025 | { | |||
5026 | m_Curve[0] = m_Curve[1] = m_Curve[2] = NULL__null; | |||
5027 | m_ApplyCurvePtr = NULL__null; | |||
5028 | m_bFreeCurve = false; | |||
5029 | } | |||
5030 | ||||
5031 | /** | |||
5032 | ************************************************************************** | |||
5033 | * Name: CIccXformMatrixTRC::~CIccXformMatrixTRC | |||
5034 | * | |||
5035 | * Purpose: | |||
5036 | * Destructor | |||
5037 | ************************************************************************** | |||
5038 | */ | |||
5039 | CIccXformMatrixTRC::~CIccXformMatrixTRC() | |||
5040 | { | |||
5041 | if (m_bFreeCurve) { | |||
5042 | if (m_Curve[0]) | |||
5043 | delete m_Curve[0]; | |||
5044 | if (m_Curve[1]) | |||
5045 | delete m_Curve[1]; | |||
5046 | if (m_Curve[2]) | |||
5047 | delete m_Curve[2]; | |||
5048 | } | |||
5049 | } | |||
5050 | ||||
5051 | /** | |||
5052 | ************************************************************************** | |||
5053 | * Name: CIccXformMatrixTRC::Begin | |||
5054 | * | |||
5055 | * Purpose: | |||
5056 | * Does the initialization of the Xform before Apply() is called. | |||
5057 | * Must be called before Apply(). | |||
5058 | * | |||
5059 | ************************************************************************** | |||
5060 | */ | |||
5061 | icStatusCMM CIccXformMatrixTRC::Begin() | |||
5062 | { | |||
5063 | icStatusCMM status; | |||
5064 | const CIccTagXYZ *pXYZ; | |||
5065 | ||||
5066 | status = CIccXform::Begin(); | |||
5067 | if (status != icCmmStatOk) | |||
5068 | return status; | |||
5069 | ||||
5070 | pXYZ = GetColumn(icSigRedMatrixColumnTag); | |||
5071 | if (!pXYZ) { | |||
5072 | return icCmmStatProfileMissingTag; | |||
5073 | } | |||
5074 | ||||
5075 | m_e[0] = icFtoD((*pXYZ)[0].X); | |||
5076 | m_e[3] = icFtoD((*pXYZ)[0].Y); | |||
5077 | m_e[6] = icFtoD((*pXYZ)[0].Z); | |||
5078 | ||||
5079 | pXYZ = GetColumn(icSigGreenMatrixColumnTag); | |||
5080 | if (!pXYZ) { | |||
5081 | return icCmmStatProfileMissingTag; | |||
5082 | } | |||
5083 | ||||
5084 | m_e[1] = icFtoD((*pXYZ)[0].X); | |||
5085 | m_e[4] = icFtoD((*pXYZ)[0].Y); | |||
5086 | m_e[7] = icFtoD((*pXYZ)[0].Z); | |||
5087 | ||||
5088 | pXYZ = GetColumn(icSigBlueMatrixColumnTag); | |||
5089 | if (!pXYZ) { | |||
5090 | return icCmmStatProfileMissingTag; | |||
5091 | } | |||
5092 | ||||
5093 | m_e[2] = icFtoD((*pXYZ)[0].X); | |||
5094 | m_e[5] = icFtoD((*pXYZ)[0].Y); | |||
5095 | m_e[8] = icFtoD((*pXYZ)[0].Z); | |||
5096 | ||||
5097 | m_ApplyCurvePtr = NULL__null; | |||
5098 | ||||
5099 | if (m_bInput) { | |||
5100 | m_Curve[0] = GetCurve(icSigRedTRCTag); | |||
5101 | m_Curve[1] = GetCurve(icSigGreenTRCTag); | |||
5102 | m_Curve[2] = GetCurve(icSigBlueTRCTag); | |||
5103 | ||||
5104 | if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) { | |||
5105 | return icCmmStatProfileMissingTag; | |||
5106 | } | |||
5107 | ||||
5108 | } | |||
5109 | else { | |||
5110 | if (m_pProfile->m_Header.pcs!=icSigXYZData) { | |||
5111 | return icCmmStatBadSpaceLink; | |||
5112 | } | |||
5113 | ||||
5114 | m_Curve[0] = GetInvCurve(icSigRedTRCTag); | |||
5115 | m_Curve[1] = GetInvCurve(icSigGreenTRCTag); | |||
5116 | m_Curve[2] = GetInvCurve(icSigBlueTRCTag); | |||
5117 | ||||
5118 | m_bFreeCurve = true; | |||
5119 | ||||
5120 | if (!m_Curve[0] || !m_Curve[1] || !m_Curve[2]) { | |||
5121 | return icCmmStatProfileMissingTag; | |||
5122 | } | |||
5123 | ||||
5124 | if (!icMatrixInvert3x3(m_e)) { | |||
5125 | return icCmmStatInvalidProfile; | |||
5126 | } | |||
5127 | } | |||
5128 | ||||
5129 | m_Curve[0]->Begin(); | |||
5130 | m_Curve[1]->Begin(); | |||
5131 | m_Curve[2]->Begin(); | |||
5132 | ||||
5133 | if (!m_Curve[0]->IsIdentity() || !m_Curve[1]->IsIdentity() || !m_Curve[2]->IsIdentity()) { | |||
5134 | m_ApplyCurvePtr = m_Curve; | |||
5135 | } | |||
5136 | ||||
5137 | return icCmmStatOk; | |||
5138 | } | |||
5139 | ||||
5140 | ||||
5141 | static icFloatNumber XYZScale(icFloatNumber v) | |||
5142 | { | |||
5143 | v = (icFloatNumber)(v * 32768.0 / 65535.0); | |||
5144 | return v; | |||
5145 | } | |||
5146 | ||||
5147 | static icFloatNumber XYZDescale(icFloatNumber v) | |||
5148 | { | |||
5149 | return (icFloatNumber)(v * 65535.0 / 32768.0); | |||
5150 | } | |||
5151 | ||||
5152 | static icFloatNumber RGBClip(icFloatNumber v, CIccCurve *pCurve) | |||
5153 | { | |||
5154 | if (v<=0) | |||
5155 | return(pCurve->Apply(0)); | |||
5156 | else if (v>=1.0) | |||
5157 | return (pCurve->Apply(1.0)); | |||
5158 | ||||
5159 | return pCurve->Apply(v); | |||
5160 | } | |||
5161 | ||||
5162 | /** | |||
5163 | ************************************************************************** | |||
5164 | * Name: CIccXformMatrixTRC::Apply | |||
5165 | * | |||
5166 | * Purpose: | |||
5167 | * Does the actual application of the Xform. | |||
5168 | * | |||
5169 | * Args: | |||
5170 | * pApply = ApplyXform object containging temporary storage used during Apply | |||
5171 | * DstPixel = Destination pixel where the result is stored, | |||
5172 | * SrcPixel = Source pixel which is to be applied. | |||
5173 | ************************************************************************** | |||
5174 | */ | |||
5175 | void CIccXformMatrixTRC::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
5176 | { | |||
5177 | icFloatNumber Pixel[3]; | |||
5178 | ||||
5179 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
5180 | Pixel[0] = SrcPixel[0]; | |||
5181 | Pixel[1] = SrcPixel[1]; | |||
5182 | Pixel[2] = SrcPixel[2]; | |||
5183 | ||||
5184 | if (m_bInput) { | |||
5185 | ||||
5186 | double LinR, LinG, LinB; | |||
5187 | if (m_ApplyCurvePtr) { | |||
5188 | LinR = m_ApplyCurvePtr[0]->Apply(Pixel[0]); | |||
5189 | LinG = m_ApplyCurvePtr[1]->Apply(Pixel[1]); | |||
5190 | LinB = m_ApplyCurvePtr[2]->Apply(Pixel[2]); | |||
5191 | } | |||
5192 | else { | |||
5193 | LinR = Pixel[0]; | |||
5194 | LinG = Pixel[1]; | |||
5195 | LinB = Pixel[2]; | |||
5196 | } | |||
5197 | ||||
5198 | DstPixel[0] = XYZScale((icFloatNumber)(m_e[0] * LinR + m_e[1] * LinG + m_e[2] * LinB)); | |||
5199 | DstPixel[1] = XYZScale((icFloatNumber)(m_e[3] * LinR + m_e[4] * LinG + m_e[5] * LinB)); | |||
5200 | DstPixel[2] = XYZScale((icFloatNumber)(m_e[6] * LinR + m_e[7] * LinG + m_e[8] * LinB)); | |||
5201 | } | |||
5202 | else { | |||
5203 | double X = XYZDescale(Pixel[0]); | |||
5204 | double Y = XYZDescale(Pixel[1]); | |||
5205 | double Z = XYZDescale(Pixel[2]); | |||
5206 | ||||
5207 | if (m_ApplyCurvePtr) { | |||
5208 | DstPixel[0] = RGBClip((icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z), m_ApplyCurvePtr[0]); | |||
5209 | DstPixel[1] = RGBClip((icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z), m_ApplyCurvePtr[1]); | |||
5210 | DstPixel[2] = RGBClip((icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z), m_ApplyCurvePtr[2]); | |||
5211 | } | |||
5212 | else { | |||
5213 | DstPixel[0] = (icFloatNumber)(m_e[0] * X + m_e[1] * Y + m_e[2] * Z); | |||
5214 | DstPixel[1] = (icFloatNumber)(m_e[3] * X + m_e[4] * Y + m_e[5] * Z); | |||
5215 | DstPixel[2] = (icFloatNumber)(m_e[6] * X + m_e[7] * Y + m_e[8] * Z); | |||
5216 | } | |||
5217 | } | |||
5218 | ||||
5219 | CheckDstAbs(DstPixel); | |||
5220 | } | |||
5221 | ||||
5222 | /** | |||
5223 | ************************************************************************** | |||
5224 | * Name: CIccXformMatrixTRC::GetCurve | |||
5225 | * | |||
5226 | * Purpose: | |||
5227 | * Gets the curve having the passed signature, from the profile. | |||
5228 | * | |||
5229 | * Args: | |||
5230 | * sig = signature of the curve to be found | |||
5231 | * | |||
5232 | * Return: | |||
5233 | * Pointer to the curve. | |||
5234 | ************************************************************************** | |||
5235 | */ | |||
5236 | CIccCurve *CIccXformMatrixTRC::GetCurve(icSignature sig) const | |||
5237 | { | |||
5238 | CIccTag *pTag = m_pProfile->FindTag(sig); | |||
5239 | ||||
5240 | if (pTag->GetType()==icSigCurveType || pTag->GetType()==icSigParametricCurveType) { | |||
5241 | return (CIccCurve*)pTag; | |||
5242 | } | |||
5243 | ||||
5244 | return NULL__null; | |||
5245 | } | |||
5246 | ||||
5247 | /** | |||
5248 | ************************************************************************** | |||
5249 | * Name: CIccXformMatrixTRC::GetColumn | |||
5250 | * | |||
5251 | * Purpose: | |||
5252 | * Gets the XYZ tag from the profile. | |||
5253 | * | |||
5254 | * Args: | |||
5255 | * sig = signature of the XYZ tag to be found. | |||
5256 | * | |||
5257 | * Return: | |||
5258 | * Pointer to the XYZ tag. | |||
5259 | ************************************************************************** | |||
5260 | */ | |||
5261 | CIccTagXYZ *CIccXformMatrixTRC::GetColumn(icSignature sig) const | |||
5262 | { | |||
5263 | CIccTag *pTag = m_pProfile->FindTag(sig); | |||
5264 | ||||
5265 | if (!pTag || pTag->GetType()!=icSigXYZType) { | |||
5266 | return NULL__null; | |||
5267 | } | |||
5268 | ||||
5269 | return (CIccTagXYZ*)pTag; | |||
5270 | } | |||
5271 | ||||
5272 | /** | |||
5273 | ************************************************************************** | |||
5274 | * Name: CIccXformMatrixTRC::GetInvCurve | |||
5275 | * | |||
5276 | * Purpose: | |||
5277 | * Gets the inverted curve having the passed signature, from the profile. | |||
5278 | * | |||
5279 | * Args: | |||
5280 | * sig = signature of the curve to be inverted | |||
5281 | * | |||
5282 | * Return: | |||
5283 | * Pointer to the inverted curve. | |||
5284 | ************************************************************************** | |||
5285 | */ | |||
5286 | CIccCurve *CIccXformMatrixTRC::GetInvCurve(icSignature sig) const | |||
5287 | { | |||
5288 | CIccCurve *pCurve; | |||
5289 | CIccTagCurve *pInvCurve; | |||
5290 | ||||
5291 | if (!(pCurve = GetCurve(sig))) | |||
5292 | return NULL__null; | |||
5293 | ||||
5294 | pCurve->Begin(); | |||
5295 | ||||
5296 | pInvCurve = new CIccTagCurve(2048); | |||
5297 | ||||
5298 | int i; | |||
5299 | icFloatNumber x; | |||
5300 | icFloatNumber *Lut = &(*pInvCurve)[0]; | |||
5301 | ||||
5302 | for (i=0; i<2048; i++) { | |||
5303 | x=(icFloatNumber)i / 2047; | |||
5304 | ||||
5305 | Lut[i] = pCurve->Find(x); | |||
5306 | } | |||
5307 | ||||
5308 | return pInvCurve; | |||
5309 | } | |||
5310 | ||||
5311 | /** | |||
5312 | ************************************************************************** | |||
5313 | * Name: CIccXformMatrixTRC::ExtractInputCurves | |||
5314 | * | |||
5315 | * Purpose: | |||
5316 | * Gets the input curves. Should be called only after Begin() | |||
5317 | * has been called. Once the curves are extracted, they will | |||
5318 | * not be used by the Apply() function. | |||
5319 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
5320 | * | |||
5321 | * Return: | |||
5322 | * Pointer to the input curves. | |||
5323 | ************************************************************************** | |||
5324 | */ | |||
5325 | LPIccCurve* CIccXformMatrixTRC::ExtractInputCurves() | |||
5326 | { | |||
5327 | if (m_bInput) { | |||
5328 | if (m_Curve[0]) { | |||
5329 | LPIccCurve* Curve = new LPIccCurve[3]; | |||
5330 | Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy()); | |||
5331 | Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy()); | |||
5332 | Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy()); | |||
5333 | m_ApplyCurvePtr = NULL__null; | |||
5334 | return Curve; | |||
5335 | } | |||
5336 | } | |||
5337 | ||||
5338 | return NULL__null; | |||
5339 | } | |||
5340 | ||||
5341 | /** | |||
5342 | ************************************************************************** | |||
5343 | * Name: CIccXformMatrixTRC::ExtractOutputCurves | |||
5344 | * | |||
5345 | * Purpose: | |||
5346 | * Gets the output curves. Should be called only after Begin() | |||
5347 | * has been called. Once the curves are extracted, they will | |||
5348 | * not be used by the Apply() function. | |||
5349 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
5350 | * | |||
5351 | * Return: | |||
5352 | * Pointer to the output curves. | |||
5353 | ************************************************************************** | |||
5354 | */ | |||
5355 | LPIccCurve* CIccXformMatrixTRC::ExtractOutputCurves() | |||
5356 | { | |||
5357 | if (!m_bInput) { | |||
5358 | if (m_Curve[0]) { | |||
5359 | LPIccCurve* Curve = new LPIccCurve[3]; | |||
5360 | Curve[0] = (LPIccCurve)(m_Curve[0]->NewCopy()); | |||
5361 | Curve[1] = (LPIccCurve)(m_Curve[1]->NewCopy()); | |||
5362 | Curve[2] = (LPIccCurve)(m_Curve[2]->NewCopy()); | |||
5363 | m_ApplyCurvePtr = NULL__null; | |||
5364 | return Curve; | |||
5365 | } | |||
5366 | } | |||
5367 | ||||
5368 | return NULL__null; | |||
5369 | } | |||
5370 | ||||
5371 | /** | |||
5372 | ************************************************************************** | |||
5373 | * Name: CIccXform3DLut::CIccXform3DLut | |||
5374 | * | |||
5375 | * Purpose: | |||
5376 | * Constructor | |||
5377 | * | |||
5378 | * Args: | |||
5379 | * pTag = Pointer to the tag of type CIccMBB | |||
5380 | ************************************************************************** | |||
5381 | */ | |||
5382 | CIccXform3DLut::CIccXform3DLut(CIccTag *pTag) | |||
5383 | { | |||
5384 | if (pTag && pTag->IsMBBType()) { | |||
5385 | m_pTag = (CIccMBB*)pTag; | |||
5386 | } | |||
5387 | else | |||
5388 | m_pTag = NULL__null; | |||
5389 | ||||
5390 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | |||
5391 | m_ApplyMatrixPtr = NULL__null; | |||
5392 | } | |||
5393 | ||||
5394 | /** | |||
5395 | ************************************************************************** | |||
5396 | * Name: CIccXform3DLut::~CIccXform3DLut | |||
5397 | * | |||
5398 | * Purpose: | |||
5399 | * Destructor | |||
5400 | ************************************************************************** | |||
5401 | */ | |||
5402 | CIccXform3DLut::~CIccXform3DLut() | |||
5403 | { | |||
5404 | } | |||
5405 | ||||
5406 | /** | |||
5407 | ************************************************************************** | |||
5408 | * Name: CIccXform3DLut::Begin | |||
5409 | * | |||
5410 | * Purpose: | |||
5411 | * Does the initialization of the Xform before Apply() is called. | |||
5412 | * Must be called before Apply(). | |||
5413 | * | |||
5414 | ************************************************************************** | |||
5415 | */ | |||
5416 | icStatusCMM CIccXform3DLut::Begin() | |||
5417 | { | |||
5418 | icStatusCMM status; | |||
5419 | CIccCurve **Curve; | |||
5420 | int i; | |||
5421 | ||||
5422 | status = CIccXform::Begin(); | |||
5423 | if (status != icCmmStatOk) | |||
5424 | return status; | |||
5425 | ||||
5426 | if (!m_pTag || | |||
5427 | m_pTag->InputChannels()!=3) { | |||
5428 | return icCmmStatInvalidLut; | |||
5429 | } | |||
5430 | ||||
5431 | m_ApplyCurvePtrA = NULL__null; | |||
5432 | m_ApplyCurvePtrB = NULL__null; | |||
5433 | m_ApplyCurvePtrM = NULL__null; | |||
5434 | ||||
5435 | if (m_pTag->m_bInputMatrix) { | |||
5436 | if (m_pTag->m_CurvesB) { | |||
5437 | Curve = m_pTag->m_CurvesB; | |||
5438 | ||||
5439 | Curve[0]->Begin(); | |||
5440 | Curve[1]->Begin(); | |||
5441 | Curve[2]->Begin(); | |||
5442 | ||||
5443 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { | |||
5444 | m_ApplyCurvePtrB = Curve; | |||
5445 | } | |||
5446 | } | |||
5447 | ||||
5448 | if (m_pTag->m_CurvesM) { | |||
5449 | Curve = m_pTag->m_CurvesM; | |||
5450 | ||||
5451 | Curve[0]->Begin(); | |||
5452 | Curve[1]->Begin(); | |||
5453 | Curve[2]->Begin(); | |||
5454 | ||||
5455 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { | |||
5456 | m_ApplyCurvePtrM = Curve; | |||
5457 | } | |||
5458 | } | |||
5459 | ||||
5460 | if (m_pTag->m_CLUT) { | |||
5461 | m_pTag->m_CLUT->Begin(); | |||
5462 | } | |||
5463 | ||||
5464 | if (m_pTag->m_CurvesA) { | |||
5465 | Curve = m_pTag->m_CurvesA; | |||
5466 | ||||
5467 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5468 | Curve[i]->Begin(); | |||
5469 | } | |||
5470 | ||||
5471 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5472 | if (!Curve[i]->IsIdentity()) { | |||
5473 | m_ApplyCurvePtrA = Curve; | |||
5474 | break; | |||
5475 | } | |||
5476 | } | |||
5477 | } | |||
5478 | ||||
5479 | } | |||
5480 | else { | |||
5481 | if (m_pTag->m_CurvesA) { | |||
5482 | Curve = m_pTag->m_CurvesA; | |||
5483 | ||||
5484 | Curve[0]->Begin(); | |||
5485 | Curve[1]->Begin(); | |||
5486 | Curve[2]->Begin(); | |||
5487 | ||||
5488 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || !Curve[2]->IsIdentity()) { | |||
5489 | m_ApplyCurvePtrA = Curve; | |||
5490 | } | |||
5491 | } | |||
5492 | ||||
5493 | if (m_pTag->m_CLUT) { | |||
5494 | m_pTag->m_CLUT->Begin(); | |||
5495 | } | |||
5496 | ||||
5497 | if (m_pTag->m_CurvesM) { | |||
5498 | Curve = m_pTag->m_CurvesM; | |||
5499 | ||||
5500 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5501 | Curve[i]->Begin(); | |||
5502 | } | |||
5503 | ||||
5504 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5505 | if (!Curve[i]->IsIdentity()) { | |||
5506 | m_ApplyCurvePtrM = Curve; | |||
5507 | break; | |||
5508 | } | |||
5509 | } | |||
5510 | } | |||
5511 | ||||
5512 | if (m_pTag->m_CurvesB) { | |||
5513 | Curve = m_pTag->m_CurvesB; | |||
5514 | ||||
5515 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5516 | Curve[i]->Begin(); | |||
5517 | } | |||
5518 | ||||
5519 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5520 | if (!Curve[i]->IsIdentity()) { | |||
5521 | m_ApplyCurvePtrB = Curve; | |||
5522 | break; | |||
5523 | } | |||
5524 | } | |||
5525 | } | |||
5526 | } | |||
5527 | ||||
5528 | m_ApplyMatrixPtr = NULL__null; | |||
5529 | if (m_pTag->m_Matrix) { | |||
5530 | if (m_pTag->m_bInputMatrix) { | |||
5531 | if (m_pTag->m_nInput!=3) { | |||
5532 | return icCmmStatInvalidProfile; | |||
5533 | } | |||
5534 | } | |||
5535 | else { | |||
5536 | if (m_pTag->m_nOutput!=3) { | |||
5537 | return icCmmStatInvalidProfile; | |||
5538 | } | |||
5539 | } | |||
5540 | ||||
5541 | if (!m_pTag->m_Matrix->IsIdentity()) { | |||
5542 | m_ApplyMatrixPtr = m_pTag->m_Matrix; | |||
5543 | } | |||
5544 | } | |||
5545 | ||||
5546 | return icCmmStatOk; | |||
5547 | } | |||
5548 | ||||
5549 | /** | |||
5550 | ************************************************************************** | |||
5551 | * Name: CIccXform3DLut::Apply | |||
5552 | * | |||
5553 | * Purpose: | |||
5554 | * Does the actual application of the Xform. | |||
5555 | * | |||
5556 | * Args: | |||
5557 | * pApply = ApplyXform object containing temporary storage used during Apply | |||
5558 | * DstPixel = Destination pixel where the result is stored, | |||
5559 | * SrcPixel = Source pixel which is to be applied. | |||
5560 | ************************************************************************** | |||
5561 | */ | |||
5562 | void CIccXform3DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
5563 | { | |||
5564 | icFloatNumber Pixel[16]; | |||
5565 | int i; | |||
5566 | ||||
5567 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
5568 | Pixel[0] = SrcPixel[0]; | |||
5569 | Pixel[1] = SrcPixel[1]; | |||
5570 | Pixel[2] = SrcPixel[2]; | |||
5571 | ||||
5572 | if (m_pTag->m_bInputMatrix) { | |||
5573 | if (m_ApplyCurvePtrB) { | |||
5574 | Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]); | |||
5575 | Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]); | |||
5576 | Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]); | |||
5577 | } | |||
5578 | ||||
5579 | if (m_ApplyMatrixPtr) { | |||
5580 | m_ApplyMatrixPtr->Apply(Pixel); | |||
5581 | } | |||
5582 | ||||
5583 | if (m_ApplyCurvePtrM) { | |||
5584 | Pixel[0] = m_ApplyCurvePtrM[0]->Apply(Pixel[0]); | |||
5585 | Pixel[1] = m_ApplyCurvePtrM[1]->Apply(Pixel[1]); | |||
5586 | Pixel[2] = m_ApplyCurvePtrM[2]->Apply(Pixel[2]); | |||
5587 | } | |||
5588 | ||||
5589 | if (m_pTag->m_CLUT) { | |||
5590 | if (m_nInterp==icInterpLinear) | |||
5591 | m_pTag->m_CLUT->Interp3d(Pixel, Pixel); | |||
5592 | else | |||
5593 | m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel); | |||
5594 | } | |||
5595 | ||||
5596 | if (m_ApplyCurvePtrA) { | |||
5597 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5598 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | |||
5599 | } | |||
5600 | } | |||
5601 | ||||
5602 | } | |||
5603 | else { | |||
5604 | if (m_ApplyCurvePtrA) { | |||
5605 | Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]); | |||
5606 | Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]); | |||
5607 | Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]); | |||
5608 | } | |||
5609 | ||||
5610 | if (m_pTag->m_CLUT) { | |||
5611 | if (m_nInterp==icInterpLinear) | |||
5612 | m_pTag->m_CLUT->Interp3d(Pixel, Pixel); | |||
5613 | else | |||
5614 | m_pTag->m_CLUT->Interp3dTetra(Pixel, Pixel); | |||
5615 | } | |||
5616 | ||||
5617 | if (m_ApplyCurvePtrM) { | |||
5618 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5619 | Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); | |||
5620 | } | |||
5621 | } | |||
5622 | ||||
5623 | if (m_ApplyMatrixPtr) { | |||
5624 | m_ApplyMatrixPtr->Apply(Pixel); | |||
5625 | } | |||
5626 | ||||
5627 | if (m_ApplyCurvePtrB) { | |||
5628 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5629 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | |||
5630 | } | |||
5631 | } | |||
5632 | } | |||
5633 | ||||
5634 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5635 | DstPixel[i] = Pixel[i]; | |||
5636 | } | |||
5637 | ||||
5638 | CheckDstAbs(DstPixel); | |||
5639 | } | |||
5640 | ||||
5641 | /** | |||
5642 | ************************************************************************** | |||
5643 | * Name: CIccXform3DLut::ExtractInputCurves | |||
5644 | * | |||
5645 | * Purpose: | |||
5646 | * Gets the input curves. Should be called only after Begin() | |||
5647 | * has been called. Once the curves are extracted, they will | |||
5648 | * not be used by the Apply() function. | |||
5649 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
5650 | * | |||
5651 | * Return: | |||
5652 | * Pointer to the input curves. | |||
5653 | ************************************************************************** | |||
5654 | */ | |||
5655 | LPIccCurve* CIccXform3DLut::ExtractInputCurves() | |||
5656 | { | |||
5657 | if (m_bInput) { | |||
5658 | if (m_pTag->m_bInputMatrix) { | |||
5659 | if (m_pTag->m_CurvesB) { | |||
5660 | LPIccCurve* Curve = new LPIccCurve[3]; | |||
5661 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy()); | |||
5662 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy()); | |||
5663 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy()); | |||
5664 | m_ApplyCurvePtrB = NULL__null; | |||
5665 | return Curve; | |||
5666 | } | |||
5667 | } | |||
5668 | else { | |||
5669 | if (m_pTag->m_CurvesA) { | |||
5670 | LPIccCurve* Curve = new LPIccCurve[3]; | |||
5671 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy()); | |||
5672 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy()); | |||
5673 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy()); | |||
5674 | m_ApplyCurvePtrA = NULL__null; | |||
5675 | return Curve; | |||
5676 | } | |||
5677 | } | |||
5678 | } | |||
5679 | ||||
5680 | return NULL__null; | |||
5681 | } | |||
5682 | ||||
5683 | /** | |||
5684 | ************************************************************************** | |||
5685 | * Name: CIccXform3DLut::ExtractOutputCurves | |||
5686 | * | |||
5687 | * Purpose: | |||
5688 | * Gets the output curves. Should be called only after Begin() | |||
5689 | * has been called. Once the curves are extracted, they will | |||
5690 | * not be used by the Apply() function. | |||
5691 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
5692 | * | |||
5693 | * Return: | |||
5694 | * Pointer to the output curves. | |||
5695 | ************************************************************************** | |||
5696 | */ | |||
5697 | LPIccCurve* CIccXform3DLut::ExtractOutputCurves() | |||
5698 | { | |||
5699 | if (!m_bInput) { | |||
5700 | if (m_pTag->m_bInputMatrix) { | |||
5701 | if (m_pTag->m_CurvesA) { | |||
5702 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | |||
5703 | for (int i=0; i<m_pTag->m_nOutput; i++) { | |||
5704 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | |||
5705 | } | |||
5706 | m_ApplyCurvePtrA = NULL__null; | |||
5707 | return Curve; | |||
5708 | } | |||
5709 | } | |||
5710 | else { | |||
5711 | if (m_pTag->m_CurvesB) { | |||
5712 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | |||
5713 | for (int i=0; i<m_pTag->m_nOutput; i++) { | |||
5714 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | |||
5715 | } | |||
5716 | m_ApplyCurvePtrB = NULL__null; | |||
5717 | return Curve; | |||
5718 | } | |||
5719 | } | |||
5720 | } | |||
5721 | ||||
5722 | return NULL__null; | |||
5723 | } | |||
5724 | ||||
5725 | /** | |||
5726 | ************************************************************************** | |||
5727 | * Name: CIccXform4DLut::CIccXform4DLut | |||
5728 | * | |||
5729 | * Purpose: | |||
5730 | * Constructor | |||
5731 | * | |||
5732 | * Args: | |||
5733 | * pTag = Pointer to the tag of type CIccMBB | |||
5734 | ************************************************************************** | |||
5735 | */ | |||
5736 | CIccXform4DLut::CIccXform4DLut(CIccTag *pTag) | |||
5737 | { | |||
5738 | if (pTag && pTag->IsMBBType()) { | |||
5739 | m_pTag = (CIccMBB*)pTag; | |||
5740 | } | |||
5741 | else | |||
5742 | m_pTag = NULL__null; | |||
5743 | ||||
5744 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | |||
5745 | m_ApplyMatrixPtr = NULL__null; | |||
5746 | } | |||
5747 | ||||
5748 | ||||
5749 | /** | |||
5750 | ************************************************************************** | |||
5751 | * Name: CIccXform4DLut::~CIccXform4DLut | |||
5752 | * | |||
5753 | * Purpose: | |||
5754 | * Destructor | |||
5755 | ************************************************************************** | |||
5756 | */ | |||
5757 | CIccXform4DLut::~CIccXform4DLut() | |||
5758 | { | |||
5759 | } | |||
5760 | ||||
5761 | ||||
5762 | /** | |||
5763 | ************************************************************************** | |||
5764 | * Name: CIccXform4DLut::Begin | |||
5765 | * | |||
5766 | * Purpose: | |||
5767 | * Does the initialization of the Xform before Apply() is called. | |||
5768 | * Must be called before Apply(). | |||
5769 | * | |||
5770 | ************************************************************************** | |||
5771 | */ | |||
5772 | icStatusCMM CIccXform4DLut::Begin() | |||
5773 | { | |||
5774 | icStatusCMM status; | |||
5775 | CIccCurve **Curve; | |||
5776 | int i; | |||
5777 | ||||
5778 | status = CIccXform::Begin(); | |||
5779 | if (status != icCmmStatOk) { | |||
5780 | return status; | |||
5781 | } | |||
5782 | ||||
5783 | if (!m_pTag || | |||
5784 | m_pTag->InputChannels()!=4) { | |||
5785 | return icCmmStatInvalidLut; | |||
5786 | } | |||
5787 | ||||
5788 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | |||
5789 | ||||
5790 | if (m_pTag->m_bInputMatrix) { | |||
5791 | if (m_pTag->m_CurvesB) { | |||
5792 | Curve = m_pTag->m_CurvesB; | |||
5793 | ||||
5794 | Curve[0]->Begin(); | |||
5795 | Curve[1]->Begin(); | |||
5796 | Curve[2]->Begin(); | |||
5797 | Curve[3]->Begin(); | |||
5798 | ||||
5799 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || | |||
5800 | !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity()) | |||
5801 | { | |||
5802 | m_ApplyCurvePtrB = Curve; | |||
5803 | } | |||
5804 | } | |||
5805 | ||||
5806 | if (m_pTag->m_CLUT) { | |||
5807 | m_pTag->m_CLUT->Begin(); | |||
5808 | } | |||
5809 | ||||
5810 | if (m_pTag->m_CurvesA) { | |||
5811 | Curve = m_pTag->m_CurvesA; | |||
5812 | ||||
5813 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5814 | Curve[i]->Begin(); | |||
5815 | } | |||
5816 | ||||
5817 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5818 | if (!Curve[i]->IsIdentity()) { | |||
5819 | m_ApplyCurvePtrA = Curve; | |||
5820 | break; | |||
5821 | } | |||
5822 | } | |||
5823 | } | |||
5824 | ||||
5825 | } | |||
5826 | else { | |||
5827 | if (m_pTag->m_CurvesA) { | |||
5828 | Curve = m_pTag->m_CurvesA; | |||
5829 | ||||
5830 | Curve[0]->Begin(); | |||
5831 | Curve[1]->Begin(); | |||
5832 | Curve[2]->Begin(); | |||
5833 | Curve[3]->Begin(); | |||
5834 | ||||
5835 | if (!Curve[0]->IsIdentity() || !Curve[1]->IsIdentity() || | |||
5836 | !Curve[2]->IsIdentity() || !Curve[3]->IsIdentity()) | |||
5837 | { | |||
5838 | m_ApplyCurvePtrA = Curve; | |||
5839 | } | |||
5840 | } | |||
5841 | ||||
5842 | if (m_pTag->m_CLUT) { | |||
5843 | m_pTag->m_CLUT->Begin(); | |||
5844 | } | |||
5845 | ||||
5846 | if (m_pTag->m_CurvesM) { | |||
5847 | Curve = m_pTag->m_CurvesM; | |||
5848 | ||||
5849 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5850 | Curve[i]->Begin(); | |||
5851 | } | |||
5852 | ||||
5853 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5854 | if (!Curve[i]->IsIdentity()) { | |||
5855 | m_ApplyCurvePtrM = Curve; | |||
5856 | break; | |||
5857 | } | |||
5858 | } | |||
5859 | } | |||
5860 | ||||
5861 | if (m_pTag->m_CurvesB) { | |||
5862 | Curve = m_pTag->m_CurvesB; | |||
5863 | ||||
5864 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5865 | Curve[i]->Begin(); | |||
5866 | } | |||
5867 | ||||
5868 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5869 | if (!Curve[i]->IsIdentity()) { | |||
5870 | m_ApplyCurvePtrB = Curve; | |||
5871 | break; | |||
5872 | } | |||
5873 | } | |||
5874 | } | |||
5875 | } | |||
5876 | ||||
5877 | m_ApplyMatrixPtr = NULL__null; | |||
5878 | if (m_pTag->m_Matrix) { | |||
5879 | if (m_pTag->m_bInputMatrix) { | |||
5880 | return icCmmStatInvalidProfile; | |||
5881 | } | |||
5882 | else { | |||
5883 | if (m_pTag->m_nOutput!=3) { | |||
5884 | return icCmmStatInvalidProfile; | |||
5885 | } | |||
5886 | } | |||
5887 | ||||
5888 | if (!m_pTag->m_Matrix->IsIdentity()) { | |||
5889 | m_ApplyMatrixPtr = m_pTag->m_Matrix; | |||
5890 | } | |||
5891 | } | |||
5892 | ||||
5893 | return icCmmStatOk; | |||
5894 | } | |||
5895 | ||||
5896 | ||||
5897 | /** | |||
5898 | ************************************************************************** | |||
5899 | * Name: CIccXform4DLut::Apply | |||
5900 | * | |||
5901 | * Purpose: | |||
5902 | * Does the actual application of the Xform. | |||
5903 | * | |||
5904 | * Args: | |||
5905 | * pApply = ApplyXform object containging temporary storage used during Apply | |||
5906 | * DstPixel = Destination pixel where the result is stored, | |||
5907 | * SrcPixel = Source pixel which is to be applied. | |||
5908 | ************************************************************************** | |||
5909 | */ | |||
5910 | void CIccXform4DLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
5911 | { | |||
5912 | icFloatNumber Pixel[16]; | |||
5913 | int i; | |||
5914 | ||||
5915 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
5916 | Pixel[0] = SrcPixel[0]; | |||
5917 | Pixel[1] = SrcPixel[1]; | |||
5918 | Pixel[2] = SrcPixel[2]; | |||
5919 | Pixel[3] = SrcPixel[3]; | |||
5920 | ||||
5921 | if (m_pTag->m_bInputMatrix) { | |||
5922 | if (m_ApplyCurvePtrB) { | |||
5923 | Pixel[0] = m_ApplyCurvePtrB[0]->Apply(Pixel[0]); | |||
5924 | Pixel[1] = m_ApplyCurvePtrB[1]->Apply(Pixel[1]); | |||
5925 | Pixel[2] = m_ApplyCurvePtrB[2]->Apply(Pixel[2]); | |||
5926 | Pixel[3] = m_ApplyCurvePtrB[3]->Apply(Pixel[3]); | |||
5927 | } | |||
5928 | ||||
5929 | if (m_pTag->m_CLUT) { | |||
5930 | m_pTag->m_CLUT->Interp4d(Pixel, Pixel); | |||
5931 | } | |||
5932 | ||||
5933 | if (m_ApplyCurvePtrA) { | |||
5934 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5935 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | |||
5936 | } | |||
5937 | } | |||
5938 | ||||
5939 | } | |||
5940 | else { | |||
5941 | if (m_ApplyCurvePtrA) { | |||
5942 | Pixel[0] = m_ApplyCurvePtrA[0]->Apply(Pixel[0]); | |||
5943 | Pixel[1] = m_ApplyCurvePtrA[1]->Apply(Pixel[1]); | |||
5944 | Pixel[2] = m_ApplyCurvePtrA[2]->Apply(Pixel[2]); | |||
5945 | Pixel[3] = m_ApplyCurvePtrA[3]->Apply(Pixel[3]); | |||
5946 | } | |||
5947 | ||||
5948 | if (m_pTag->m_CLUT) { | |||
5949 | m_pTag->m_CLUT->Interp4d(Pixel, Pixel); | |||
5950 | } | |||
5951 | ||||
5952 | if (m_ApplyCurvePtrM) { | |||
5953 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5954 | Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); | |||
5955 | } | |||
5956 | } | |||
5957 | ||||
5958 | if (m_ApplyMatrixPtr) { | |||
5959 | m_ApplyMatrixPtr->Apply(Pixel); | |||
5960 | } | |||
5961 | ||||
5962 | if (m_ApplyCurvePtrB) { | |||
5963 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5964 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | |||
5965 | } | |||
5966 | } | |||
5967 | } | |||
5968 | ||||
5969 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
5970 | DstPixel[i] = Pixel[i]; | |||
5971 | } | |||
5972 | ||||
5973 | CheckDstAbs(DstPixel); | |||
5974 | } | |||
5975 | ||||
5976 | /** | |||
5977 | ************************************************************************** | |||
5978 | * Name: CIccXform4DLut::ExtractInputCurves | |||
5979 | * | |||
5980 | * Purpose: | |||
5981 | * Gets the input curves. Should be called only after Begin() | |||
5982 | * has been called. Once the curves are extracted, they will | |||
5983 | * not be used by the Apply() function. | |||
5984 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
5985 | * | |||
5986 | * Return: | |||
5987 | * Pointer to the input curves. | |||
5988 | ************************************************************************** | |||
5989 | */ | |||
5990 | LPIccCurve* CIccXform4DLut::ExtractInputCurves() | |||
5991 | { | |||
5992 | if (m_bInput) { | |||
5993 | if (m_pTag->m_bInputMatrix) { | |||
5994 | if (m_pTag->m_CurvesB) { | |||
5995 | LPIccCurve* Curve = new LPIccCurve[4]; | |||
5996 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesB[0]->NewCopy()); | |||
5997 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesB[1]->NewCopy()); | |||
5998 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesB[2]->NewCopy()); | |||
5999 | Curve[3] = (LPIccCurve)(m_pTag->m_CurvesB[3]->NewCopy()); | |||
6000 | m_ApplyCurvePtrB = NULL__null; | |||
6001 | return Curve; | |||
6002 | } | |||
6003 | } | |||
6004 | else { | |||
6005 | if (m_pTag->m_CurvesA) { | |||
6006 | LPIccCurve* Curve = new LPIccCurve[4]; | |||
6007 | Curve[0] = (LPIccCurve)(m_pTag->m_CurvesA[0]->NewCopy()); | |||
6008 | Curve[1] = (LPIccCurve)(m_pTag->m_CurvesA[1]->NewCopy()); | |||
6009 | Curve[2] = (LPIccCurve)(m_pTag->m_CurvesA[2]->NewCopy()); | |||
6010 | Curve[3] = (LPIccCurve)(m_pTag->m_CurvesA[3]->NewCopy()); | |||
6011 | m_ApplyCurvePtrA = NULL__null; | |||
6012 | return Curve; | |||
6013 | } | |||
6014 | } | |||
6015 | } | |||
6016 | ||||
6017 | return NULL__null; | |||
6018 | } | |||
6019 | ||||
6020 | /** | |||
6021 | ************************************************************************** | |||
6022 | * Name: CIccXform4DLut::ExtractOutputCurves | |||
6023 | * | |||
6024 | * Purpose: | |||
6025 | * Gets the output curves. Should be called only after Begin() | |||
6026 | * has been called. Once the curves are extracted, they will | |||
6027 | * not be used by the Apply() function. | |||
6028 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
6029 | * | |||
6030 | * Return: | |||
6031 | * Pointer to the output curves. | |||
6032 | ************************************************************************** | |||
6033 | */ | |||
6034 | LPIccCurve* CIccXform4DLut::ExtractOutputCurves() | |||
6035 | { | |||
6036 | if (!m_bInput) { | |||
6037 | if (m_pTag->m_bInputMatrix) { | |||
6038 | if (m_pTag->m_CurvesA) { | |||
6039 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | |||
6040 | for (int i=0; i<m_pTag->m_nOutput; i++) { | |||
6041 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | |||
6042 | } | |||
6043 | m_ApplyCurvePtrA = NULL__null; | |||
6044 | return Curve; | |||
6045 | } | |||
6046 | } | |||
6047 | else { | |||
6048 | if (m_pTag->m_CurvesB) { | |||
6049 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | |||
6050 | for (int i=0; i<m_pTag->m_nOutput; i++) { | |||
6051 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | |||
6052 | } | |||
6053 | m_ApplyCurvePtrB = NULL__null; | |||
6054 | return Curve; | |||
6055 | } | |||
6056 | } | |||
6057 | } | |||
6058 | ||||
6059 | return NULL__null; | |||
6060 | } | |||
6061 | ||||
6062 | ||||
6063 | /** | |||
6064 | ************************************************************************** | |||
6065 | * Name: CIccXformNDLut::CIccXformNDLut | |||
6066 | * | |||
6067 | * Purpose: | |||
6068 | * Constructor | |||
6069 | * | |||
6070 | * Args: | |||
6071 | * pTag = Pointer to the tag of type CIccMBB | |||
6072 | ************************************************************************** | |||
6073 | */ | |||
6074 | CIccXformNDLut::CIccXformNDLut(CIccTag *pTag) | |||
6075 | { | |||
6076 | if (pTag && pTag->IsMBBType()) { | |||
6077 | m_pTag = (CIccMBB*)pTag; | |||
6078 | } | |||
6079 | else | |||
6080 | m_pTag = NULL__null; | |||
6081 | ||||
6082 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | |||
6083 | m_ApplyMatrixPtr = NULL__null; | |||
6084 | } | |||
6085 | ||||
6086 | ||||
6087 | /** | |||
6088 | ************************************************************************** | |||
6089 | * Name: CIccXformNDLut::~CIccXformNDLut | |||
6090 | * | |||
6091 | * Purpose: | |||
6092 | * Destructor | |||
6093 | ************************************************************************** | |||
6094 | */ | |||
6095 | CIccXformNDLut::~CIccXformNDLut() | |||
6096 | { | |||
6097 | } | |||
6098 | ||||
6099 | ||||
6100 | /** | |||
6101 | ************************************************************************** | |||
6102 | * Name: CIccXformNDLut::Begin | |||
6103 | * | |||
6104 | * Purpose: | |||
6105 | * Does the initialization of the Xform before Apply() is called. | |||
6106 | * Must be called before Apply(). | |||
6107 | * | |||
6108 | ************************************************************************** | |||
6109 | */ | |||
6110 | icStatusCMM CIccXformNDLut::Begin() | |||
6111 | { | |||
6112 | icStatusCMM status; | |||
6113 | CIccCurve **Curve; | |||
6114 | int i; | |||
6115 | ||||
6116 | status = CIccXform::Begin(); | |||
6117 | if (status != icCmmStatOk) { | |||
6118 | return status; | |||
6119 | } | |||
6120 | ||||
6121 | if (!m_pTag || (m_pTag->InputChannels()>2 && m_pTag->InputChannels()<5)) { | |||
6122 | return icCmmStatInvalidLut; | |||
6123 | } | |||
6124 | ||||
6125 | m_nNumInput = m_pTag->m_nInput; | |||
6126 | ||||
6127 | m_ApplyCurvePtrA = m_ApplyCurvePtrB = m_ApplyCurvePtrM = NULL__null; | |||
6128 | ||||
6129 | if (m_pTag->m_bInputMatrix) { | |||
6130 | if (m_pTag->m_CurvesB) { | |||
6131 | Curve = m_pTag->m_CurvesB; | |||
6132 | ||||
6133 | for (i=0; i<m_nNumInput; i++) | |||
6134 | Curve[i]->Begin(); | |||
6135 | ||||
6136 | for (i=0; i<m_nNumInput; i++) { | |||
6137 | if (!Curve[i]->IsIdentity()) { | |||
6138 | m_ApplyCurvePtrB = Curve; | |||
6139 | break; | |||
6140 | } | |||
6141 | } | |||
6142 | } | |||
6143 | ||||
6144 | if (m_pTag->m_CLUT) { | |||
6145 | m_pTag->m_CLUT->Begin(); | |||
6146 | } | |||
6147 | ||||
6148 | if (m_pTag->m_CurvesA) { | |||
6149 | Curve = m_pTag->m_CurvesA; | |||
6150 | ||||
6151 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6152 | Curve[i]->Begin(); | |||
6153 | } | |||
6154 | ||||
6155 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6156 | if (!Curve[i]->IsIdentity()) { | |||
6157 | m_ApplyCurvePtrA = Curve; | |||
6158 | break; | |||
6159 | } | |||
6160 | } | |||
6161 | } | |||
6162 | ||||
6163 | } | |||
6164 | else { | |||
6165 | if (m_pTag->m_CurvesA) { | |||
6166 | Curve = m_pTag->m_CurvesA; | |||
6167 | ||||
6168 | for (i=0; i<m_nNumInput; i++) | |||
6169 | Curve[i]->Begin(); | |||
6170 | ||||
6171 | for (i=0; i<m_nNumInput; i++) { | |||
6172 | if (!Curve[i]->IsIdentity()) { | |||
6173 | m_ApplyCurvePtrA = Curve; | |||
6174 | break; | |||
6175 | } | |||
6176 | } | |||
6177 | } | |||
6178 | ||||
6179 | if (m_pTag->m_CLUT) { | |||
6180 | m_pTag->m_CLUT->Begin(); | |||
6181 | } | |||
6182 | ||||
6183 | if (m_pTag->m_CurvesM) { | |||
6184 | Curve = m_pTag->m_CurvesM; | |||
6185 | ||||
6186 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6187 | Curve[i]->Begin(); | |||
6188 | } | |||
6189 | ||||
6190 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6191 | if (!Curve[i]->IsIdentity()) { | |||
6192 | m_ApplyCurvePtrM = Curve; | |||
6193 | break; | |||
6194 | } | |||
6195 | } | |||
6196 | } | |||
6197 | ||||
6198 | if (m_pTag->m_CurvesB) { | |||
6199 | Curve = m_pTag->m_CurvesB; | |||
6200 | ||||
6201 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6202 | Curve[i]->Begin(); | |||
6203 | } | |||
6204 | ||||
6205 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6206 | if (!Curve[i]->IsIdentity()) { | |||
6207 | m_ApplyCurvePtrB = Curve; | |||
6208 | break; | |||
6209 | } | |||
6210 | } | |||
6211 | } | |||
6212 | } | |||
6213 | ||||
6214 | m_ApplyMatrixPtr = NULL__null; | |||
6215 | if (m_pTag->m_Matrix) { | |||
6216 | if (m_pTag->m_bInputMatrix) { | |||
6217 | return icCmmStatInvalidProfile; | |||
6218 | } | |||
6219 | else { | |||
6220 | if (m_pTag->m_nOutput!=3) { | |||
6221 | return icCmmStatInvalidProfile; | |||
6222 | } | |||
6223 | } | |||
6224 | ||||
6225 | if (!m_pTag->m_Matrix->IsIdentity()) { | |||
6226 | m_ApplyMatrixPtr = m_pTag->m_Matrix; | |||
6227 | } | |||
6228 | } | |||
6229 | ||||
6230 | return icCmmStatOk; | |||
6231 | } | |||
6232 | ||||
6233 | ||||
6234 | /** | |||
6235 | ************************************************************************** | |||
6236 | * Name: CIccXformNDLut::Apply | |||
6237 | * | |||
6238 | * Purpose: | |||
6239 | * Does the actual application of the Xform. | |||
6240 | * | |||
6241 | * Args: | |||
6242 | * pApply = ApplyXform object containging temporary storage used during Apply | |||
6243 | * DstPixel = Destination pixel where the result is stored, | |||
6244 | * SrcPixel = Source pixel which is to be applied. | |||
6245 | ************************************************************************** | |||
6246 | */ | |||
6247 | void CIccXformNDLut::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
6248 | { | |||
6249 | icFloatNumber Pixel[16]; | |||
6250 | int i; | |||
6251 | ||||
6252 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
6253 | for (i=0; i<m_nNumInput; i++) | |||
| ||||
6254 | Pixel[i] = SrcPixel[i]; | |||
6255 | ||||
6256 | if (m_pTag->m_bInputMatrix) { | |||
6257 | if (m_ApplyCurvePtrB) { | |||
6258 | for (i=0; i<m_nNumInput; i++) | |||
6259 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | |||
6260 | } | |||
6261 | ||||
6262 | if (m_pTag->m_CLUT) { | |||
6263 | switch(m_nNumInput) { | |||
6264 | case 5: | |||
6265 | m_pTag->m_CLUT->Interp5d(Pixel, Pixel); | |||
6266 | break; | |||
6267 | case 6: | |||
6268 | m_pTag->m_CLUT->Interp6d(Pixel, Pixel); | |||
6269 | break; | |||
6270 | default: | |||
6271 | m_pTag->m_CLUT->InterpND(Pixel, Pixel); | |||
6272 | break; | |||
6273 | } | |||
6274 | } | |||
6275 | ||||
6276 | if (m_ApplyCurvePtrA) { | |||
6277 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6278 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | |||
6279 | } | |||
6280 | } | |||
6281 | ||||
6282 | } | |||
6283 | else { | |||
6284 | if (m_ApplyCurvePtrA) { | |||
6285 | for (i=0; i<m_nNumInput; i++) | |||
6286 | Pixel[i] = m_ApplyCurvePtrA[i]->Apply(Pixel[i]); | |||
6287 | } | |||
6288 | ||||
6289 | if (m_pTag->m_CLUT) { | |||
6290 | switch(m_nNumInput) { | |||
6291 | case 5: | |||
6292 | m_pTag->m_CLUT->Interp5d(Pixel, Pixel); | |||
6293 | break; | |||
6294 | case 6: | |||
6295 | m_pTag->m_CLUT->Interp6d(Pixel, Pixel); | |||
6296 | break; | |||
6297 | default: | |||
6298 | m_pTag->m_CLUT->InterpND(Pixel, Pixel); | |||
6299 | break; | |||
6300 | } | |||
6301 | } | |||
6302 | ||||
6303 | if (m_ApplyCurvePtrM) { | |||
6304 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6305 | Pixel[i] = m_ApplyCurvePtrM[i]->Apply(Pixel[i]); | |||
6306 | } | |||
6307 | } | |||
6308 | ||||
6309 | if (m_ApplyMatrixPtr) { | |||
6310 | m_ApplyMatrixPtr->Apply(Pixel); | |||
6311 | } | |||
6312 | ||||
6313 | if (m_ApplyCurvePtrB) { | |||
6314 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6315 | Pixel[i] = m_ApplyCurvePtrB[i]->Apply(Pixel[i]); | |||
6316 | } | |||
6317 | } | |||
6318 | } | |||
6319 | ||||
6320 | for (i=0; i<m_pTag->m_nOutput; i++) { | |||
6321 | DstPixel[i] = Pixel[i]; | |||
| ||||
6322 | } | |||
6323 | ||||
6324 | CheckDstAbs(DstPixel); | |||
6325 | } | |||
6326 | ||||
6327 | /** | |||
6328 | ************************************************************************** | |||
6329 | * Name: CIccXformNDLut::ExtractInputCurves | |||
6330 | * | |||
6331 | * Purpose: | |||
6332 | * Gets the input curves. Should be called only after Begin() | |||
6333 | * has been called. Once the curves are extracted, they will | |||
6334 | * not be used by the Apply() function. | |||
6335 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
6336 | * | |||
6337 | * Return: | |||
6338 | * Pointer to the input curves. | |||
6339 | ************************************************************************** | |||
6340 | */ | |||
6341 | LPIccCurve* CIccXformNDLut::ExtractInputCurves() | |||
6342 | { | |||
6343 | if (m_bInput) { | |||
6344 | if (m_pTag->m_bInputMatrix) { | |||
6345 | if (m_pTag->m_CurvesB) { | |||
6346 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput]; | |||
6347 | for (int i=0; i<m_pTag->m_nInput; i++) { | |||
6348 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | |||
6349 | } | |||
6350 | m_ApplyCurvePtrB = NULL__null; | |||
6351 | return Curve; | |||
6352 | } | |||
6353 | } | |||
6354 | else { | |||
6355 | if (m_pTag->m_CurvesA) { | |||
6356 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nInput]; | |||
6357 | for (int i=0; i<m_pTag->m_nInput; i++) { | |||
6358 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | |||
6359 | } | |||
6360 | m_ApplyCurvePtrA = NULL__null; | |||
6361 | return Curve; | |||
6362 | } | |||
6363 | } | |||
6364 | } | |||
6365 | ||||
6366 | return NULL__null; | |||
6367 | } | |||
6368 | ||||
6369 | /** | |||
6370 | ************************************************************************** | |||
6371 | * Name: CIccXformNDLut::ExtractOutputCurves | |||
6372 | * | |||
6373 | * Purpose: | |||
6374 | * Gets the output curves. Should be called only after Begin() | |||
6375 | * has been called. Once the curves are extracted, they will | |||
6376 | * not be used by the Apply() function. | |||
6377 | * WARNING: caller owns the curves and must be deleted by the caller. | |||
6378 | * | |||
6379 | * Return: | |||
6380 | * Pointer to the output curves. | |||
6381 | ************************************************************************** | |||
6382 | */ | |||
6383 | LPIccCurve* CIccXformNDLut::ExtractOutputCurves() | |||
6384 | { | |||
6385 | if (!m_bInput) { | |||
6386 | if (m_pTag->m_bInputMatrix) { | |||
6387 | if (m_pTag->m_CurvesA) { | |||
6388 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | |||
6389 | for (int i=0; i<m_pTag->m_nOutput; i++) { | |||
6390 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesA[i]->NewCopy()); | |||
6391 | } | |||
6392 | m_ApplyCurvePtrA = NULL__null; | |||
6393 | return Curve; | |||
6394 | } | |||
6395 | } | |||
6396 | else { | |||
6397 | if (m_pTag->m_CurvesB) { | |||
6398 | LPIccCurve* Curve = new LPIccCurve[m_pTag->m_nOutput]; | |||
6399 | for (int i=0; i<m_pTag->m_nOutput; i++) { | |||
6400 | Curve[i] = (LPIccCurve)(m_pTag->m_CurvesB[i]->NewCopy()); | |||
6401 | } | |||
6402 | m_ApplyCurvePtrB = NULL__null; | |||
6403 | return Curve; | |||
6404 | } | |||
6405 | } | |||
6406 | } | |||
6407 | ||||
6408 | return NULL__null; | |||
6409 | } | |||
6410 | ||||
6411 | /** | |||
6412 | ************************************************************************** | |||
6413 | * Name: CIccXformNamedColor::CIccXformNamedColor | |||
6414 | * | |||
6415 | * Purpose: | |||
6416 | * Constructor | |||
6417 | * | |||
6418 | * Args: | |||
6419 | * pTag = Pointer to the tag of type CIccTagNamedColor2, | |||
6420 | * csPCS = PCS color space, | |||
6421 | * csDevice = Device color space | |||
6422 | ************************************************************************** | |||
6423 | */ | |||
6424 | CIccXformNamedColor::CIccXformNamedColor(CIccTag *pTag, icColorSpaceSignature csPcs, icColorSpaceSignature csDevice, | |||
6425 | icSpectralColorSignature csSpectralPcs/* =icSigNoSpectralData */, | |||
6426 | const icSpectralRange *pSpectralRange /* = NULL */, | |||
6427 | const icSpectralRange *pBiSpectralRange /* = NULL */) | |||
6428 | { | |||
6429 | if (pTag) { | |||
6430 | if (pTag->GetType()==icSigNamedColor2Type) { | |||
6431 | m_pTag = (CIccTagNamedColor2*)pTag; | |||
6432 | m_pArray = NULL__null; | |||
6433 | ||||
6434 | m_pTag->SetColorSpaces(csPcs, csDevice); | |||
6435 | } | |||
6436 | else if (pTag->GetTagArrayType()==icSigNamedColorArray) { | |||
6437 | CIccTagArray *pArray = (CIccTagArray*)pTag; | |||
6438 | CIccArrayNamedColor *pNamed = (CIccArrayNamedColor*)pArray->GetArrayHandler(); | |||
6439 | ||||
6440 | if (pNamed) { | |||
6441 | m_pTag = NULL__null; | |||
6442 | m_pArray = pNamed; | |||
6443 | pNamed->SetColorSpaces(csPcs, csDevice, csSpectralPcs, pSpectralRange, pBiSpectralRange); | |||
6444 | } | |||
6445 | } | |||
6446 | } | |||
6447 | ||||
6448 | m_nSrcSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | |||
6449 | m_nDestSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | |||
6450 | } | |||
6451 | ||||
6452 | ||||
6453 | /** | |||
6454 | ************************************************************************** | |||
6455 | * Name: CIccXformNamedColor::CIccXformNamedColor | |||
6456 | * | |||
6457 | * Purpose: | |||
6458 | * Destructor | |||
6459 | ************************************************************************** | |||
6460 | */ | |||
6461 | CIccXformNamedColor::~CIccXformNamedColor() | |||
6462 | { | |||
6463 | } | |||
6464 | ||||
6465 | /** | |||
6466 | ************************************************************************** | |||
6467 | * Name: CIccXformNamedColor::Begin | |||
6468 | * | |||
6469 | * Purpose: | |||
6470 | * Does the initialization of the Xform before Apply() is called. | |||
6471 | * Must be called before Apply(). | |||
6472 | * | |||
6473 | ************************************************************************** | |||
6474 | */ | |||
6475 | icStatusCMM CIccXformNamedColor::Begin() | |||
6476 | { | |||
6477 | icStatusCMM status; | |||
6478 | ||||
6479 | status = CIccXform::Begin(); | |||
6480 | if (status != icCmmStatOk) | |||
6481 | return status; | |||
6482 | ||||
6483 | if (m_pTag==NULL__null && m_pArray==NULL__null) { | |||
6484 | return icCmmStatProfileMissingTag; | |||
6485 | } | |||
6486 | ||||
6487 | if (m_nSrcSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f) || | |||
6488 | m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
6489 | return icCmmStatIncorrectApply; | |||
6490 | } | |||
6491 | ||||
6492 | if (m_nSrcSpace != icSigNamedData) { | |||
6493 | if (m_nDestSpace != icSigNamedData) { | |||
6494 | m_nApplyInterface = icApplyPixel2Pixel; | |||
6495 | } | |||
6496 | else { | |||
6497 | m_nApplyInterface = icApplyPixel2Named; | |||
6498 | } | |||
6499 | } | |||
6500 | else { | |||
6501 | if (m_nDestSpace != icSigNamedData) { | |||
6502 | m_nApplyInterface = icApplyNamed2Pixel; | |||
6503 | } | |||
6504 | else { | |||
6505 | return icCmmStatIncorrectApply; | |||
6506 | } | |||
6507 | } | |||
6508 | ||||
6509 | if (m_pTag && !m_pTag->InitFindCachedPCSColor()) | |||
6510 | return icCmmStatAllocErr; | |||