File: | IccProfLib/IccCmm.cpp |
Warning: | line 6278, column 20 1st function call argument is an uninitialized value |
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; | |||
6511 | else if (m_pArray && !m_pArray->Begin()) | |||
6512 | return icCmmStatAllocErr; | |||
6513 | ||||
6514 | return icCmmStatOk; | |||
6515 | } | |||
6516 | ||||
6517 | ||||
6518 | ||||
6519 | /** | |||
6520 | ************************************************************************** | |||
6521 | * Name: CIccXformNamedColor::Apply | |||
6522 | * | |||
6523 | * Purpose: | |||
6524 | * Does the actual application of the Xform. | |||
6525 | * | |||
6526 | * Args: | |||
6527 | * pApply = ApplyXform object containging temporary storage used during Apply | |||
6528 | * DstColorName = Destination string where the color name result is stored, | |||
6529 | * SrcPixel = Source pixel which is to be applied. | |||
6530 | ************************************************************************** | |||
6531 | */ | |||
6532 | icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icChar *DstColorName, const icFloatNumber *SrcPixel) const | |||
6533 | { | |||
6534 | ||||
6535 | if (m_pArray) { | |||
6536 | const CIccArrayNamedColor *pArray = m_pArray; | |||
6537 | CIccStructNamedColor *pColor; | |||
6538 | ||||
6539 | std::string NamedColor; | |||
6540 | ||||
6541 | if (IsSrcPCS()) { | |||
6542 | if (IsSpaceSpectralPCS(m_nSrcSpace)) { | |||
6543 | pColor = pArray->FindSpectralColor(SrcPixel); | |||
6544 | if (pColor) | |||
6545 | NamedColor = pColor->getName(); | |||
6546 | else | |||
6547 | return icCmmStatColorNotFound; | |||
6548 | } | |||
6549 | else { | |||
6550 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
6551 | icFloatNumber pix[3]; | |||
6552 | memcpy(pix, SrcPixel, 3*sizeof(icFloatNumber)); | |||
6553 | ||||
6554 | if (m_nSrcSpace == icSigLabPcsDataicSigLabData) | |||
6555 | icLabFromPcs(pix); | |||
6556 | else { | |||
6557 | icXyzFromPcs(pix); | |||
6558 | icXYZtoLab(pix, pix); | |||
6559 | } | |||
6560 | ||||
6561 | pColor = pArray->FindPcsColor(pix); | |||
6562 | if (pColor) | |||
6563 | NamedColor = pColor->getName(); | |||
6564 | else | |||
6565 | return icCmmStatColorNotFound; | |||
6566 | } | |||
6567 | } | |||
6568 | else { | |||
6569 | pColor = pArray->FindDeviceColor(SrcPixel); | |||
6570 | if (pColor) | |||
6571 | NamedColor = pColor->getName(); | |||
6572 | else | |||
6573 | return icCmmStatColorNotFound; | |||
6574 | } | |||
6575 | ||||
6576 | sprintf(DstColorName, "%s", NamedColor.c_str()); | |||
6577 | } | |||
6578 | else if (m_pTag) { | |||
6579 | const CIccTagNamedColor2 *pTag = m_pTag; | |||
6580 | ||||
6581 | icFloatNumber DevicePix[16], PCSPix[3]; | |||
6582 | std::string NamedColor; | |||
6583 | icUInt32Number i, j; | |||
6584 | ||||
6585 | if (IsSrcPCS()) { | |||
6586 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
6587 | for(i=0; i<3; i++) | |||
6588 | PCSPix[i] = SrcPixel[i]; | |||
6589 | ||||
6590 | j = pTag->FindCachedPCSColor(PCSPix); | |||
6591 | pTag->GetColorName(NamedColor, j); | |||
6592 | } | |||
6593 | else { | |||
6594 | for(i=0; i<m_pTag->GetDeviceCoords(); i++) | |||
6595 | DevicePix[i] = SrcPixel[i]; | |||
6596 | ||||
6597 | j = pTag->FindDeviceColor(DevicePix); | |||
6598 | pTag->GetColorName(NamedColor, j); | |||
6599 | } | |||
6600 | ||||
6601 | sprintf(DstColorName, "%s", NamedColor.c_str()); | |||
6602 | } | |||
6603 | else | |||
6604 | return icCmmStatBadXform; | |||
6605 | ||||
6606 | return icCmmStatOk; | |||
6607 | } | |||
6608 | ||||
6609 | ||||
6610 | /** | |||
6611 | ************************************************************************** | |||
6612 | * Name: CIccXformNamedColor::Apply | |||
6613 | * | |||
6614 | * Purpose: | |||
6615 | * Does the actual application of the Xform. | |||
6616 | * | |||
6617 | * Args: | |||
6618 | * pApply = ApplyXform object containing temporary storage used during Apply | |||
6619 | * DstPixel = Destination pixel where the result is stored, | |||
6620 | * SrcColorName = Source color name which is to be applied. | |||
6621 | ************************************************************************** | |||
6622 | */ | |||
6623 | icStatusCMM CIccXformNamedColor::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint) const | |||
6624 | { | |||
6625 | ||||
6626 | if (m_pArray) { | |||
6627 | const CIccArrayNamedColor *pArray = m_pArray; | |||
6628 | ||||
6629 | CIccStructNamedColor *pColor; | |||
6630 | ||||
6631 | if (m_nSrcSpace != icSigNamedData) | |||
6632 | return icCmmStatBadSpaceLink; | |||
6633 | ||||
6634 | pColor = pArray->FindColor(SrcColorName); | |||
6635 | if (!pColor) | |||
6636 | return icCmmStatColorNotFound; | |||
6637 | ||||
6638 | if (IsDestPCS()) { | |||
6639 | if (IsSpaceSpectralPCS(m_nDestSpace)) { | |||
6640 | if (!pArray->GetSpectralTint(DstPixel, pColor, tint)) | |||
6641 | return icCmmStatBadTintXform; | |||
6642 | } | |||
6643 | else { | |||
6644 | if (!pArray->GetPcsTint(DstPixel, pColor, tint)) | |||
6645 | return icCmmStatBadTintXform; | |||
6646 | ||||
6647 | if (m_nDestSpace == icSigLabData) { | |||
6648 | icLabToPcs(DstPixel); | |||
6649 | } | |||
6650 | else { | |||
6651 | icXyzToPcs(DstPixel); | |||
6652 | } | |||
6653 | CheckDstAbs(DstPixel); | |||
6654 | } | |||
6655 | } | |||
6656 | else { | |||
6657 | if (!pArray->GetDeviceTint(DstPixel, pColor, tint)) | |||
6658 | return icCmmStatBadTintXform; | |||
6659 | } | |||
6660 | } | |||
6661 | else if (m_pTag) { | |||
6662 | const CIccTagNamedColor2 *pTag = m_pTag; | |||
6663 | ||||
6664 | icInt32Number j; | |||
6665 | ||||
6666 | if (m_nSrcSpace != icSigNamedData) | |||
6667 | return icCmmStatBadSpaceLink; | |||
6668 | ||||
6669 | if (IsDestPCS()) { | |||
6670 | ||||
6671 | j = pTag->FindColor(SrcColorName); | |||
6672 | if (j<0) | |||
6673 | return icCmmStatColorNotFound; | |||
6674 | ||||
6675 | if (m_nDestSpace == icSigLabData) { | |||
6676 | memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber)); | |||
6677 | } | |||
6678 | else { | |||
6679 | memcpy(DstPixel, pTag->GetEntry(j)->pcsCoords, 3*sizeof(icFloatNumber)); | |||
6680 | } | |||
6681 | CheckDstAbs(DstPixel); | |||
6682 | } | |||
6683 | else { | |||
6684 | j = pTag->FindColor(SrcColorName); | |||
6685 | if (j<0) | |||
6686 | return icCmmStatColorNotFound; | |||
6687 | memcpy(DstPixel, pTag->GetEntry(j)->deviceCoords, pTag->GetDeviceCoords()*sizeof(icFloatNumber)); | |||
6688 | } | |||
6689 | } | |||
6690 | ||||
6691 | return icCmmStatOk; | |||
6692 | } | |||
6693 | ||||
6694 | /** | |||
6695 | ************************************************************************** | |||
6696 | * Name: CIccXformNamedColor::SetSrcSpace | |||
6697 | * | |||
6698 | * Purpose: | |||
6699 | * Sets the source space of the Xform | |||
6700 | * | |||
6701 | * Args: | |||
6702 | * nSrcSpace = signature of the color space to be set | |||
6703 | ************************************************************************** | |||
6704 | */ | |||
6705 | icStatusCMM CIccXformNamedColor::SetSrcSpace(icColorSpaceSignature nSrcSpace) | |||
6706 | { | |||
6707 | if (m_pArray) { | |||
6708 | ||||
6709 | } | |||
6710 | else if (m_pTag) { | |||
6711 | CIccTagNamedColor2 *pTag = m_pTag; | |||
6712 | ||||
6713 | if (nSrcSpace!=pTag->GetPCS()) | |||
6714 | if (nSrcSpace!=pTag->GetDeviceSpace()) | |||
6715 | if (nSrcSpace!=icSigNamedData) | |||
6716 | return icCmmStatBadSpaceLink; | |||
6717 | } | |||
6718 | ||||
6719 | m_nSrcSpace = nSrcSpace; | |||
6720 | ||||
6721 | return icCmmStatOk; | |||
6722 | } | |||
6723 | ||||
6724 | /** | |||
6725 | ************************************************************************** | |||
6726 | * Name: CIccXformNamedColor::SetDestSpace | |||
6727 | * | |||
6728 | * Purpose: | |||
6729 | * Sets the destination space of the Xform | |||
6730 | * | |||
6731 | * Args: | |||
6732 | * nDestSpace = signature of the color space to be set | |||
6733 | ************************************************************************** | |||
6734 | */ | |||
6735 | icStatusCMM CIccXformNamedColor::SetDestSpace(icColorSpaceSignature nDestSpace) | |||
6736 | { | |||
6737 | if (m_nSrcSpace == nDestSpace) | |||
6738 | return icCmmStatBadSpaceLink; | |||
6739 | ||||
6740 | if (m_pArray) { | |||
6741 | ||||
6742 | } | |||
6743 | else if (m_pTag) { | |||
6744 | CIccTagNamedColor2 *pTag = (CIccTagNamedColor2*)m_pTag; | |||
6745 | ||||
6746 | if (nDestSpace!=pTag->GetPCS()) | |||
6747 | if (nDestSpace!=pTag->GetDeviceSpace()) | |||
6748 | if (nDestSpace!=icSigNamedData) | |||
6749 | return icCmmStatBadSpaceLink; | |||
6750 | } | |||
6751 | ||||
6752 | m_nDestSpace = nDestSpace; | |||
6753 | ||||
6754 | return icCmmStatOk; | |||
6755 | } | |||
6756 | ||||
6757 | /** | |||
6758 | ************************************************************************** | |||
6759 | * Name: CIccXformNamedColor::IsSrcPCS | |||
6760 | * | |||
6761 | * Purpose: | |||
6762 | * Sets the source space is a PCS space | |||
6763 | ************************************************************************** | |||
6764 | */ | |||
6765 | bool CIccXformNamedColor::IsSrcPCS() const | |||
6766 | { | |||
6767 | if (m_pTag) { | |||
6768 | return m_nSrcSpace == m_pTag->GetPCS(); | |||
6769 | } | |||
6770 | else if (m_pArray) { | |||
6771 | return IsSpacePCS(m_nSrcSpace)(((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace)); | |||
6772 | } | |||
6773 | else | |||
6774 | return false; | |||
6775 | } | |||
6776 | ||||
6777 | ||||
6778 | /** | |||
6779 | ************************************************************************** | |||
6780 | * Name: CIccXformNamedColor::IsDestPCS | |||
6781 | * | |||
6782 | * Purpose: | |||
6783 | * Sets the destination space is a PCS space | |||
6784 | ************************************************************************** | |||
6785 | */ | |||
6786 | bool CIccXformNamedColor::IsDestPCS() const | |||
6787 | { | |||
6788 | if (m_pTag) { | |||
6789 | return m_nDestSpace == m_pTag->GetPCS(); | |||
6790 | } | |||
6791 | else if (m_pArray) { | |||
6792 | return IsSpacePCS(m_nDestSpace)(((m_nDestSpace)==icSigXYZData || (m_nDestSpace)==icSigLabData ) || IsSpaceSpectralPCS(m_nDestSpace)); | |||
6793 | } | |||
6794 | else | |||
6795 | return false; | |||
6796 | } | |||
6797 | ||||
6798 | ||||
6799 | /** | |||
6800 | ************************************************************************** | |||
6801 | * Name: CIccXformMPE::CIccXformMPE | |||
6802 | * | |||
6803 | * Purpose: | |||
6804 | * Constructor | |||
6805 | ************************************************************************** | |||
6806 | */ | |||
6807 | CIccXformMpe::CIccXformMpe(CIccTag *pTag) | |||
6808 | { | |||
6809 | if (pTag && pTag->GetType()==icSigMultiProcessElementType) | |||
6810 | m_pTag = (CIccTagMultiProcessElement*)pTag; | |||
6811 | else | |||
6812 | m_pTag = NULL__null; | |||
6813 | ||||
6814 | m_bUsingAcs = false; | |||
6815 | m_pAppliedPCC = NULL__null; | |||
6816 | m_bDeleteAppliedPCC = false; | |||
6817 | } | |||
6818 | ||||
6819 | /** | |||
6820 | ************************************************************************** | |||
6821 | * Name: CIccXformMPE::~CIccXformMPE | |||
6822 | * | |||
6823 | * Purpose: | |||
6824 | * Destructor | |||
6825 | ************************************************************************** | |||
6826 | */ | |||
6827 | CIccXformMpe::~CIccXformMpe() | |||
6828 | { | |||
6829 | if (m_pAppliedPCC && m_bDeleteAppliedPCC) | |||
6830 | delete m_pAppliedPCC; | |||
6831 | } | |||
6832 | ||||
6833 | /** | |||
6834 | ************************************************************************** | |||
6835 | * Name: CIccXformMPE::Create | |||
6836 | * | |||
6837 | * Purpose: | |||
6838 | * This is a static Creation function that creates derived CIccXform objects and | |||
6839 | * initializes them. | |||
6840 | * | |||
6841 | * Args: | |||
6842 | * pProfile = pointer to a CIccProfile object that will be owned by the transform. This object will | |||
6843 | * be destroyed when the returned CIccXform object is destroyed. The means that the CIccProfile | |||
6844 | * object needs to be allocated on the heap. | |||
6845 | * bInput = flag to indicate whether to use the input or output side of the profile, | |||
6846 | * nIntent = the rendering intent to apply to the profile, | |||
6847 | * nInterp = the interpolation algorithm to use for N-D luts. | |||
6848 | * nLutType = selection of which transform lut to use | |||
6849 | * pHintManager = hints for creating the xform | |||
6850 | * | |||
6851 | * Return: | |||
6852 | * A suitable pXform object | |||
6853 | ************************************************************************** | |||
6854 | */ | |||
6855 | CIccXform *CIccXformMpe::Create(CIccProfile *pProfile, bool bInput/* =true */, icRenderingIntent nIntent/* =icUnknownIntent */, | |||
6856 | icXformInterp nInterp/* =icInterpLinear */, icXformLutType nLutType/* =icXformLutColor */, | |||
6857 | CIccCreateXformHintManager *pHintManager/* =NULL */) | |||
6858 | { | |||
6859 | CIccXform *rv = NULL__null; | |||
6860 | icRenderingIntent nTagIntent = nIntent; | |||
6861 | bool bUseSpectralPCS = false; | |||
6862 | bool bAbsToRel = false; | |||
6863 | icXformLutType nUseLutType = nLutType; | |||
6864 | bool bUseColorimeticTags = true; | |||
6865 | bool bUseDToB = true; | |||
6866 | ||||
6867 | if (nLutType == icXformLutSpectral) { | |||
6868 | nUseLutType = icXformLutColor; | |||
6869 | bUseColorimeticTags = false; | |||
6870 | } | |||
6871 | else if (nLutType == icXformLutColorimetric) { | |||
6872 | nUseLutType = icXformLutColor; | |||
6873 | bUseDToB = false; | |||
6874 | } | |||
6875 | ||||
6876 | if (nTagIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | |||
6877 | nTagIntent = icPerceptual; | |||
6878 | ||||
6879 | switch (nUseLutType) { | |||
6880 | case icXformLutColor: | |||
6881 | if (bInput) { | |||
6882 | CIccTag *pTag = NULL__null; | |||
6883 | if (bUseDToB) { | |||
6884 | pTag = pProfile->FindTag(icSigDToB0Tag + nTagIntent); | |||
6885 | ||||
6886 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
6887 | pTag = pProfile->FindTag(icSigDToB1Tag); | |||
6888 | if (pTag) | |||
6889 | nTagIntent = icRelativeColorimetric; | |||
6890 | } | |||
6891 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | |||
6892 | pTag = pProfile->FindTag(icSigDToB3Tag); | |||
6893 | if (pTag) { | |||
6894 | nTagIntent = icAbsoluteColorimetric; | |||
6895 | bAbsToRel = true; | |||
6896 | } | |||
6897 | } | |||
6898 | ||||
6899 | if (!pTag) { | |||
6900 | pTag = pProfile->FindTag(icSigDToB0Tag); | |||
6901 | } | |||
6902 | } | |||
6903 | ||||
6904 | //Unsupported elements cause fall back behavior | |||
6905 | if (pTag && !pTag->IsSupported()) | |||
6906 | pTag = NULL__null; | |||
6907 | ||||
6908 | if (pTag && pProfile->m_Header.spectralPCS) { | |||
6909 | bUseSpectralPCS = true; | |||
6910 | } | |||
6911 | ||||
6912 | if (bUseColorimeticTags) { | |||
6913 | if (!pTag) { | |||
6914 | if (nTagIntent == icAbsoluteColorimetric) | |||
6915 | nTagIntent = icRelativeColorimetric; | |||
6916 | pTag = pProfile->FindTag(icSigAToB0Tag + nTagIntent); | |||
6917 | } | |||
6918 | ||||
6919 | if (!pTag) { | |||
6920 | pTag = pProfile->FindTag(icSigAToB0Tag); | |||
6921 | } | |||
6922 | } | |||
6923 | ||||
6924 | if (!pTag) { | |||
6925 | if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version < icVersionNumberV50x05000000) { | |||
6926 | rv = new CIccXformMatrixTRC(); | |||
6927 | } | |||
6928 | else | |||
6929 | return NULL__null; | |||
6930 | } | |||
6931 | else if (pTag->GetType()==icSigMultiProcessElementType) { | |||
6932 | rv = new CIccXformMpe(pTag); | |||
6933 | } | |||
6934 | else { | |||
6935 | switch(pProfile->m_Header.colorSpace) { | |||
6936 | case icSigXYZData: | |||
6937 | case icSigLabData: | |||
6938 | case icSigLuvData: | |||
6939 | case icSigYCbCrData: | |||
6940 | case icSigYxyData: | |||
6941 | case icSigRgbData: | |||
6942 | case icSigHsvData: | |||
6943 | case icSigHlsData: | |||
6944 | case icSigCmyData: | |||
6945 | case icSig3colorData: | |||
6946 | rv = new CIccXform3DLut(pTag); | |||
6947 | break; | |||
6948 | ||||
6949 | case icSigCmykData: | |||
6950 | case icSig4colorData: | |||
6951 | rv = new CIccXform4DLut(pTag); | |||
6952 | break; | |||
6953 | ||||
6954 | default: | |||
6955 | rv = new CIccXformNDLut(pTag); | |||
6956 | break; | |||
6957 | } | |||
6958 | } | |||
6959 | } | |||
6960 | else { | |||
6961 | CIccTag *pTag = NULL__null; | |||
6962 | ||||
6963 | if (bUseDToB) { | |||
6964 | pTag = pProfile->FindTag(icSigBToD0Tag + nTagIntent); | |||
6965 | ||||
6966 | if (!pTag && nTagIntent == icAbsoluteColorimetric) { | |||
6967 | pTag = pProfile->FindTag(icSigBToD1Tag); | |||
6968 | if (pTag) | |||
6969 | nTagIntent = icRelativeColorimetric; | |||
6970 | } | |||
6971 | else if (!pTag && nTagIntent != icAbsoluteColorimetric) { | |||
6972 | pTag = pProfile->FindTag(icSigBToD3Tag); | |||
6973 | if (pTag) { | |||
6974 | nTagIntent = icAbsoluteColorimetric; | |||
6975 | bAbsToRel = true; | |||
6976 | } | |||
6977 | } | |||
6978 | ||||
6979 | if (!pTag) { | |||
6980 | pTag = pProfile->FindTag(icSigBToD0Tag); | |||
6981 | } | |||
6982 | } | |||
6983 | ||||
6984 | //Unsupported elements cause fall back behavior | |||
6985 | if (pTag && !pTag->IsSupported()) | |||
6986 | pTag = NULL__null; | |||
6987 | ||||
6988 | if (bUseColorimeticTags) { | |||
6989 | if (!pTag) { | |||
6990 | if (nTagIntent == icAbsoluteColorimetric) | |||
6991 | nTagIntent = icRelativeColorimetric; | |||
6992 | pTag = pProfile->FindTag(icSigBToA0Tag + nTagIntent); | |||
6993 | } | |||
6994 | ||||
6995 | if (!pTag) { | |||
6996 | pTag = pProfile->FindTag(icSigBToA0Tag); | |||
6997 | } | |||
6998 | } | |||
6999 | ||||
7000 | if (!pTag) { | |||
7001 | if (bUseColorimeticTags && pProfile->m_Header.colorSpace == icSigRgbData && pProfile->m_Header.version<icVersionNumberV50x05000000) { | |||
7002 | rv = new CIccXformMatrixTRC(); | |||
7003 | } | |||
7004 | else | |||
7005 | return NULL__null; | |||
7006 | } | |||
7007 | ||||
7008 | if (pTag->GetType()==icSigMultiProcessElementType) { | |||
7009 | rv = new CIccXformMpe(pTag); | |||
7010 | } | |||
7011 | else { | |||
7012 | switch(pProfile->m_Header.pcs) { | |||
7013 | case icSigXYZData: | |||
7014 | case icSigLabData: | |||
7015 | rv = new CIccXform3DLut(pTag); | |||
7016 | ||||
7017 | default: | |||
7018 | break; | |||
7019 | } | |||
7020 | } | |||
7021 | } | |||
7022 | break; | |||
7023 | ||||
7024 | case icXformLutNamedColor: | |||
7025 | { | |||
7026 | CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); | |||
7027 | if (!pTag) | |||
7028 | return NULL__null; | |||
7029 | ||||
7030 | rv = new CIccXformNamedColor(pTag, pProfile->m_Header.pcs, pProfile->m_Header.colorSpace, | |||
7031 | pProfile->m_Header.spectralPCS, | |||
7032 | &pProfile->m_Header.spectralRange, | |||
7033 | &pProfile->m_Header.biSpectralRange); | |||
7034 | } | |||
7035 | break; | |||
7036 | ||||
7037 | case icXformLutPreview: | |||
7038 | { | |||
7039 | bInput = false; | |||
7040 | CIccTag *pTag = pProfile->FindTag(icSigPreview0Tag + nTagIntent); | |||
7041 | if (!pTag) { | |||
7042 | pTag = pProfile->FindTag(icSigPreview0Tag); | |||
7043 | } | |||
7044 | if (!pTag) { | |||
7045 | return NULL__null; | |||
7046 | } | |||
7047 | else { | |||
7048 | switch(pProfile->m_Header.pcs) { | |||
7049 | case icSigXYZData: | |||
7050 | case icSigLabData: | |||
7051 | rv = new CIccXform3DLut(pTag); | |||
7052 | ||||
7053 | default: | |||
7054 | break; | |||
7055 | } | |||
7056 | } | |||
7057 | } | |||
7058 | break; | |||
7059 | ||||
7060 | case icXformLutGamut: | |||
7061 | { | |||
7062 | bInput = false; | |||
7063 | CIccTag *pTag = pProfile->FindTag(icSigGamutTag); | |||
7064 | if (!pTag) { | |||
7065 | return NULL__null; | |||
7066 | } | |||
7067 | else { | |||
7068 | switch(pProfile->m_Header.pcs) { | |||
7069 | case icSigXYZData: | |||
7070 | case icSigLabData: | |||
7071 | rv = new CIccXform3DLut(pTag); | |||
7072 | ||||
7073 | default: | |||
7074 | break; | |||
7075 | } | |||
7076 | } | |||
7077 | } | |||
7078 | break; | |||
7079 | } | |||
7080 | ||||
7081 | if (rv) { | |||
7082 | rv->SetParams(pProfile, bInput, nIntent, nTagIntent, bUseSpectralPCS, nInterp, pHintManager, bAbsToRel); | |||
7083 | } | |||
7084 | ||||
7085 | return rv; | |||
7086 | } | |||
7087 | ||||
7088 | /** | |||
7089 | ************************************************************************** | |||
7090 | * Name: CIccXformMPE::IsLateBinding | |||
7091 | * | |||
7092 | * Purpose: | |||
7093 | * Determines if any processing elements are late binding with connection | |||
7094 | * conditions | |||
7095 | ************************************************************************** | |||
7096 | */ | |||
7097 | bool CIccXformMpe::IsLateBinding() const | |||
7098 | { | |||
7099 | if (m_pTag) | |||
7100 | return m_pTag->IsLateBinding(); | |||
7101 | ||||
7102 | return false; | |||
7103 | } | |||
7104 | ||||
7105 | /** | |||
7106 | ************************************************************************** | |||
7107 | * Name: CIccXformMPE::IsLateBindingReflectance | |||
7108 | * | |||
7109 | * Purpose: | |||
7110 | * Determines if any processing elements are late binding with connection | |||
7111 | * conditions | |||
7112 | ************************************************************************** | |||
7113 | */ | |||
7114 | bool CIccXformMpe::IsLateBindingReflectance() const | |||
7115 | { | |||
7116 | if (m_pTag) | |||
7117 | return m_pTag->IsLateBindingReflectance(); | |||
7118 | ||||
7119 | return false; | |||
7120 | } | |||
7121 | ||||
7122 | /** | |||
7123 | ************************************************************************** | |||
7124 | * Name: CIccXformMPE::GetConnectionConditions | |||
7125 | * | |||
7126 | * Purpose: | |||
7127 | * Gets appropriate connection conditions | |||
7128 | ************************************************************************** | |||
7129 | */ | |||
7130 | IIccProfileConnectionConditions *CIccXformMpe::GetConnectionConditions() const | |||
7131 | { | |||
7132 | if (m_pAppliedPCC) | |||
7133 | return m_pAppliedPCC; | |||
7134 | ||||
7135 | return m_pConnectionConditions; | |||
7136 | } | |||
7137 | ||||
7138 | /** | |||
7139 | ************************************************************************** | |||
7140 | * Name: CIccXformMPE::SetAppliedCC | |||
7141 | * | |||
7142 | * Purpose: | |||
7143 | * This creates combined connection conditions based on profile, | |||
7144 | * alternate connection conditions and whether reflectance is used | |||
7145 | * by any late binding processing elements. | |||
7146 | ************************************************************************** | |||
7147 | */ | |||
7148 | void CIccXformMpe::SetAppliedCC(IIccProfileConnectionConditions *pPCC) | |||
7149 | { | |||
7150 | if (!pPCC) { | |||
7151 | if (m_pAppliedPCC && m_bDeleteAppliedPCC) { | |||
7152 | delete m_pAppliedPCC; | |||
7153 | } | |||
7154 | m_pAppliedPCC = NULL__null; | |||
7155 | m_bDeleteAppliedPCC = false; | |||
7156 | return; | |||
7157 | } | |||
7158 | ||||
7159 | if (m_pTag) { | |||
7160 | bool bReflectance = m_pTag->IsLateBindingReflectance(); | |||
7161 | ||||
7162 | if (pPCC != (IIccProfileConnectionConditions *)m_pProfile) { | |||
7163 | if (!bReflectance) { | |||
7164 | const CIccTagSpectralViewingConditions *pViewPCC = pPCC ? pPCC->getPccViewingConditions() : NULL__null; | |||
7165 | const CIccTagSpectralViewingConditions *pViewProfile = m_pProfile ? m_pProfile->getPccViewingConditions() : NULL__null; | |||
7166 | ||||
7167 | if (pViewPCC && pViewProfile && | |||
7168 | pViewPCC->getStdIllumiant() == pViewProfile->getStdIllumiant() && | |||
7169 | pViewPCC->getIlluminantCCT() == pViewProfile->getIlluminantCCT() && | |||
7170 | pViewPCC->getStdIllumiant() != icIlluminantUnknown) { | |||
7171 | m_pAppliedPCC = pPCC; | |||
7172 | m_bDeleteAppliedPCC = false; | |||
7173 | } | |||
7174 | else { | |||
7175 | m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance); | |||
7176 | m_bDeleteAppliedPCC = true; | |||
7177 | } | |||
7178 | } | |||
7179 | else { | |||
7180 | m_pAppliedPCC = new CIccCombinedConnectionConditions(m_pProfile, pPCC, bReflectance); | |||
7181 | m_bDeleteAppliedPCC = true; | |||
7182 | } | |||
7183 | } | |||
7184 | else { | |||
7185 | m_pAppliedPCC = NULL__null; | |||
7186 | } | |||
7187 | } | |||
7188 | else { | |||
7189 | m_pAppliedPCC = pPCC; | |||
7190 | m_bDeleteAppliedPCC = false; | |||
7191 | } | |||
7192 | } | |||
7193 | ||||
7194 | ||||
7195 | /** | |||
7196 | ************************************************************************** | |||
7197 | * Name: CIccXformMPE::Begin | |||
7198 | * | |||
7199 | * Purpose: | |||
7200 | * This function will be called before the xform is applied. Derived objects | |||
7201 | * should also call the base class function to initialize for Absolute Colorimetric | |||
7202 | * Intent handling which is performed through the use of the CheckSrcAbs and | |||
7203 | * CheckDstAbs functions. | |||
7204 | ************************************************************************** | |||
7205 | */ | |||
7206 | icStatusCMM CIccXformMpe::Begin() | |||
7207 | { | |||
7208 | icStatusCMM status; | |||
7209 | status = CIccXform::Begin(); | |||
7210 | ||||
7211 | if (status != icCmmStatOk) | |||
7212 | return status; | |||
7213 | ||||
7214 | if (!m_pTag) { | |||
7215 | return icCmmStatInvalidLut; | |||
7216 | } | |||
7217 | ||||
7218 | if (!m_pTag->Begin(icElemInterpLinear, GetProfileCC(), GetConnectionConditions(), GetCmmEnvVarLookup())) { | |||
7219 | return icCmmStatInvalidProfile; | |||
7220 | } | |||
7221 | ||||
7222 | return icCmmStatOk; | |||
7223 | } | |||
7224 | ||||
7225 | ||||
7226 | /** | |||
7227 | ************************************************************************** | |||
7228 | * Name: CIccXformMpe::GetNewApply | |||
7229 | * | |||
7230 | * Purpose: | |||
7231 | * This Factory function allocates data specific for the application of the xform. | |||
7232 | * This allows multiple threads to simultaneously use the same xform. | |||
7233 | ************************************************************************** | |||
7234 | */ | |||
7235 | CIccApplyXform *CIccXformMpe::GetNewApply(icStatusCMM &status) | |||
7236 | { | |||
7237 | if (!m_pTag) | |||
7238 | return NULL__null; | |||
7239 | ||||
7240 | CIccApplyXformMpe *rv= new CIccApplyXformMpe(this); | |||
7241 | ||||
7242 | if (!rv) { | |||
7243 | status = icCmmStatAllocErr; | |||
7244 | return NULL__null; | |||
7245 | } | |||
7246 | ||||
7247 | rv->m_pApply = m_pTag->GetNewApply(); | |||
7248 | if (!rv->m_pApply) { | |||
7249 | status = icCmmStatAllocErr; | |||
7250 | delete rv; | |||
7251 | return NULL__null; | |||
7252 | } | |||
7253 | ||||
7254 | status = icCmmStatOk; | |||
7255 | return rv; | |||
7256 | } | |||
7257 | ||||
7258 | ||||
7259 | /** | |||
7260 | ************************************************************************** | |||
7261 | * Name: CIccXformMPE::Apply | |||
7262 | * | |||
7263 | * Purpose: | |||
7264 | * Does the actual application of the Xform. | |||
7265 | * | |||
7266 | * Args: | |||
7267 | * pApply = ApplyXform object containging temporary storage used during Apply | |||
7268 | * DstPixel = Destination pixel where the result is stored, | |||
7269 | * SrcPixel = Source pixel which is to be applied. | |||
7270 | ************************************************************************** | |||
7271 | */ | |||
7272 | void CIccXformMpe::Apply(CIccApplyXform* pApply, icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) const | |||
7273 | { | |||
7274 | const CIccTagMultiProcessElement *pTag = m_pTag; | |||
7275 | ||||
7276 | if (!m_bInput) { //PCS comming in? | |||
7277 | if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //B2D3 tags don't need abs conversion | |||
7278 | SrcPixel = CheckSrcAbs(pApply, SrcPixel); | |||
7279 | } | |||
7280 | ||||
7281 | //Since MPE tags use "real" values for PCS we need to convert from | |||
7282 | //internal encoding used by IccProfLib | |||
7283 | icFloatNumber temp[3]; | |||
7284 | switch (GetSrcSpace()) { | |||
7285 | case icSigXYZData: | |||
7286 | memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber)); | |||
7287 | icXyzFromPcs(temp); | |||
7288 | SrcPixel = &temp[0]; | |||
7289 | break; | |||
7290 | ||||
7291 | case icSigLabData: | |||
7292 | memcpy(&temp[0], SrcPixel, 3*sizeof(icFloatNumber)); | |||
7293 | icLabFromPcs(temp); | |||
7294 | SrcPixel = &temp[0]; | |||
7295 | break; | |||
7296 | ||||
7297 | default: | |||
7298 | break; | |||
7299 | } | |||
7300 | } | |||
7301 | ||||
7302 | //Note: pApply should be a CIccApplyXformMpe type here | |||
7303 | CIccApplyXformMpe *pApplyMpe = (CIccApplyXformMpe *)pApply; | |||
7304 | ||||
7305 | pTag->Apply(pApplyMpe->m_pApply, DstPixel, SrcPixel); | |||
7306 | ||||
7307 | if (m_bInput) { //PCS going out? | |||
7308 | //Since MPE tags use "real" values for PCS we need to convert to | |||
7309 | //internal encoding used by IccProfLib | |||
7310 | switch(GetDstSpace()) { | |||
7311 | case icSigXYZData: | |||
7312 | icXyzToPcs(DstPixel); | |||
7313 | break; | |||
7314 | ||||
7315 | case icSigLabData: | |||
7316 | icLabToPcs(DstPixel); | |||
7317 | break; | |||
7318 | ||||
7319 | default: | |||
7320 | break; | |||
7321 | } | |||
7322 | ||||
7323 | if (m_nIntent != icAbsoluteColorimetric || m_nIntent != m_nTagIntent) { //D2B3 tags don't need abs conversion | |||
7324 | CheckDstAbs(DstPixel); | |||
7325 | } | |||
7326 | } | |||
7327 | } | |||
7328 | ||||
7329 | /** | |||
7330 | ************************************************************************** | |||
7331 | * Name: CIccApplyXformMpe::CIccApplyXformMpe | |||
7332 | * | |||
7333 | * Purpose: | |||
7334 | * Constructor | |||
7335 | ************************************************************************** | |||
7336 | */ | |||
7337 | CIccApplyXformMpe::CIccApplyXformMpe(CIccXformMpe *pXform) : CIccApplyXform(pXform) | |||
7338 | { | |||
7339 | } | |||
7340 | ||||
7341 | /** | |||
7342 | ************************************************************************** | |||
7343 | * Name: CIccApplyXformMpe::~CIccApplyXformMpe | |||
7344 | * | |||
7345 | * Purpose: | |||
7346 | * Destructor | |||
7347 | ************************************************************************** | |||
7348 | */ | |||
7349 | CIccApplyXformMpe::~CIccApplyXformMpe() | |||
7350 | { | |||
7351 | } | |||
7352 | ||||
7353 | ||||
7354 | /** | |||
7355 | ************************************************************************** | |||
7356 | * Name: CIccApplyCmm::CIccApplyCmm | |||
7357 | * | |||
7358 | * Purpose: | |||
7359 | * Constructor | |||
7360 | * | |||
7361 | * Args: | |||
7362 | * pCmm = ptr to CMM to apply against | |||
7363 | ************************************************************************** | |||
7364 | */ | |||
7365 | CIccApplyCmm::CIccApplyCmm(CIccCmm *pCmm) | |||
7366 | { | |||
7367 | m_pCmm = pCmm; | |||
7368 | m_pPCS = m_pCmm->GetPCS(); | |||
7369 | ||||
7370 | m_Xforms = new CIccApplyXformList; | |||
7371 | m_Xforms->clear(); | |||
7372 | ||||
7373 | m_Pixel = NULL__null; | |||
7374 | m_Pixel2 = NULL__null; | |||
7375 | } | |||
7376 | ||||
7377 | /** | |||
7378 | ************************************************************************** | |||
7379 | * Name: CIccApplyCmm::~CIccApplyCmm | |||
7380 | * | |||
7381 | * Purpose: | |||
7382 | * Destructor | |||
7383 | ************************************************************************** | |||
7384 | */ | |||
7385 | CIccApplyCmm::~CIccApplyCmm() | |||
7386 | { | |||
7387 | if (m_Xforms) { | |||
7388 | CIccApplyXformList::iterator i; | |||
7389 | ||||
7390 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
7391 | if (i->ptr) | |||
7392 | delete i->ptr; | |||
7393 | } | |||
7394 | ||||
7395 | delete m_Xforms; | |||
7396 | } | |||
7397 | ||||
7398 | if (m_pPCS) | |||
7399 | delete m_pPCS; | |||
7400 | ||||
7401 | if (m_Pixel) | |||
7402 | free(m_Pixel); | |||
7403 | if (m_Pixel2) | |||
7404 | free(m_Pixel2); | |||
7405 | } | |||
7406 | ||||
7407 | bool CIccApplyCmm::InitPixel() | |||
7408 | { | |||
7409 | if (m_Pixel && m_Pixel2) | |||
7410 | return true; | |||
7411 | ||||
7412 | icUInt16Number nSamples = 16; | |||
7413 | CIccApplyXformList::iterator i; | |||
7414 | ||||
7415 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
7416 | if (i->ptr->GetXform()) { | |||
7417 | icUInt16Number nXformSamples = i->ptr->GetXform()->GetNumDstSamples(); | |||
7418 | if (nXformSamples>nSamples) | |||
7419 | nSamples=nXformSamples; | |||
7420 | } | |||
7421 | } | |||
7422 | m_Pixel = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber)); | |||
7423 | m_Pixel2 = (icFloatNumber*)malloc(nSamples*sizeof(icFloatNumber)); | |||
7424 | ||||
7425 | if (!m_Pixel || !m_Pixel2) | |||
7426 | return false; | |||
7427 | ||||
7428 | return true; | |||
7429 | } | |||
7430 | ||||
7431 | ||||
7432 | /** | |||
7433 | ************************************************************************** | |||
7434 | * Name: CIccApplyCmm::Apply | |||
7435 | * | |||
7436 | * Purpose: | |||
7437 | * Does the actual application of the Xforms in the list. | |||
7438 | * | |||
7439 | * Args: | |||
7440 | * DstPixel = Destination pixel where the result is stored, | |||
7441 | * SrcPixel = Source pixel which is to be applied. | |||
7442 | ************************************************************************** | |||
7443 | */ | |||
7444 | icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | |||
7445 | { | |||
7446 | icFloatNumber *pDst, *pTmp; | |||
7447 | const icFloatNumber *pSrc; | |||
7448 | CIccApplyXformList::iterator i; | |||
7449 | const CIccXform *pLastXform; | |||
7450 | int j, n = (int)m_Xforms->size(); | |||
7451 | bool bNoClip; | |||
7452 | ||||
7453 | if (!n) | |||
7454 | return icCmmStatBadXform; | |||
7455 | ||||
7456 | if (!m_Pixel && !InitPixel()) { | |||
7457 | return icCmmStatAllocErr; | |||
7458 | } | |||
7459 | ||||
7460 | m_pPCS->Reset(m_pCmm->m_nSrcSpace); | |||
7461 | ||||
7462 | pSrc = SrcPixel; | |||
7463 | pDst = m_Pixel; | |||
7464 | ||||
7465 | if (n>1) { | |||
7466 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | |||
7467 | ||||
7468 | i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform())); | |||
7469 | pTmp = (icFloatNumber*)pSrc; | |||
7470 | pSrc = pDst; | |||
7471 | if (pTmp == SrcPixel) | |||
7472 | pDst = m_Pixel2; | |||
7473 | else | |||
7474 | pDst = pTmp; | |||
7475 | } | |||
7476 | ||||
7477 | pLastXform = i->ptr->GetXform(); | |||
7478 | i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, pLastXform)); | |||
7479 | bNoClip = pLastXform->NoClipPCS(); | |||
7480 | } | |||
7481 | else if (n==1) { | |||
7482 | i = m_Xforms->begin(); | |||
7483 | ||||
7484 | pLastXform = i->ptr->GetXform(); | |||
7485 | i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, pLastXform)); | |||
7486 | bNoClip = pLastXform->NoClipPCS(); | |||
7487 | } | |||
7488 | else { | |||
7489 | bNoClip = true; | |||
7490 | } | |||
7491 | ||||
7492 | m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace, bNoClip); | |||
7493 | ||||
7494 | return icCmmStatOk; | |||
7495 | } | |||
7496 | ||||
7497 | /** | |||
7498 | ************************************************************************** | |||
7499 | * Name: CIccApplyCmm::Apply | |||
7500 | * | |||
7501 | * Purpose: | |||
7502 | * Does the actual application of the Xforms in the list. | |||
7503 | * | |||
7504 | * Args: | |||
7505 | * DstPixel = Destination pixel where the result is stored, | |||
7506 | * SrcPixel = Source pixel which is to be applied. | |||
7507 | ************************************************************************** | |||
7508 | */ | |||
7509 | icStatusCMM CIccApplyCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | |||
7510 | { | |||
7511 | icFloatNumber *pDst, *pTmp; | |||
7512 | const icFloatNumber *pSrc; | |||
7513 | CIccApplyXformList::iterator i; | |||
7514 | int j, n = (int)m_Xforms->size(); | |||
7515 | icUInt32Number k; | |||
7516 | ||||
7517 | if (!n) | |||
7518 | return icCmmStatBadXform; | |||
7519 | ||||
7520 | if (!m_Pixel && !InitPixel()) { | |||
7521 | return icCmmStatAllocErr; | |||
7522 | } | |||
7523 | ||||
7524 | for (k=0; k<nPixels; k++) { | |||
7525 | m_pPCS->Reset(m_pCmm->m_nSrcSpace); | |||
7526 | ||||
7527 | pSrc = SrcPixel; | |||
7528 | pDst = m_Pixel; | |||
7529 | ||||
7530 | if (n>1) { | |||
7531 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | |||
7532 | ||||
7533 | i->ptr->Apply(pDst, m_pPCS->Check(pSrc, i->ptr->GetXform())); | |||
7534 | pTmp = (icFloatNumber*)pSrc; | |||
7535 | pSrc = pDst; | |||
7536 | if (pTmp==SrcPixel) | |||
7537 | pDst = m_Pixel2; | |||
7538 | else | |||
7539 | pDst = pTmp; | |||
7540 | } | |||
7541 | ||||
7542 | i->ptr->Apply(DstPixel, m_pPCS->Check(pSrc, i->ptr->GetXform())); | |||
7543 | } | |||
7544 | else if (n==1) { | |||
7545 | i = m_Xforms->begin(); | |||
7546 | i->ptr->Apply(DstPixel, m_pPCS->Check(SrcPixel, i->ptr->GetXform())); | |||
7547 | } | |||
7548 | ||||
7549 | m_pPCS->CheckLast(DstPixel, m_pCmm->m_nDestSpace); | |||
7550 | ||||
7551 | DstPixel += m_pCmm->GetDestSamples(); | |||
7552 | SrcPixel += m_pCmm->GetSourceSamples(); | |||
7553 | } | |||
7554 | ||||
7555 | return icCmmStatOk; | |||
7556 | } | |||
7557 | ||||
7558 | void CIccApplyCmm::AppendApplyXform(CIccApplyXform *pApplyXform) | |||
7559 | { | |||
7560 | CIccApplyXformPtr ptr; | |||
7561 | ptr.ptr = pApplyXform; | |||
7562 | ||||
7563 | m_Xforms->push_back(ptr); | |||
7564 | } | |||
7565 | ||||
7566 | /** | |||
7567 | ************************************************************************** | |||
7568 | * Name: CIccCmm::CIccCmm | |||
7569 | * | |||
7570 | * Purpose: | |||
7571 | * Constructor | |||
7572 | * | |||
7573 | * Args: | |||
7574 | * nSrcSpace = signature of the source color space, | |||
7575 | * nDestSpace = signature of the destination color space, | |||
7576 | * bFirstInput = true if the first profile added is an input profile | |||
7577 | ************************************************************************** | |||
7578 | */ | |||
7579 | CIccCmm::CIccCmm(icColorSpaceSignature nSrcSpace /*=icSigUnknownData*/, | |||
7580 | icColorSpaceSignature nDestSpace /*=icSigUnknownData*/, | |||
7581 | bool bFirstInput /*=true*/) | |||
7582 | { | |||
7583 | m_bValid = false; | |||
7584 | ||||
7585 | m_bLastInput = !bFirstInput; | |||
7586 | m_nSrcSpace = nSrcSpace; | |||
7587 | m_nDestSpace = nDestSpace; | |||
7588 | ||||
7589 | m_nLastSpace = nSrcSpace; | |||
7590 | m_nLastIntent = icUnknownIntent((icRenderingIntent) 0x3f3f3f3f); | |||
7591 | ||||
7592 | m_Xforms = new CIccXformList; | |||
7593 | m_Xforms->clear(); | |||
7594 | ||||
7595 | m_pApply = NULL__null; | |||
7596 | } | |||
7597 | ||||
7598 | /** | |||
7599 | ************************************************************************** | |||
7600 | * Name: CIccCmm::~CIccCmm | |||
7601 | * | |||
7602 | * Purpose: | |||
7603 | * Destructor | |||
7604 | ************************************************************************** | |||
7605 | */ | |||
7606 | CIccCmm::~CIccCmm() | |||
7607 | { | |||
7608 | if (m_Xforms) { | |||
7609 | CIccXformList::iterator i; | |||
7610 | ||||
7611 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
7612 | if (i->ptr) | |||
7613 | delete i->ptr; | |||
7614 | } | |||
7615 | ||||
7616 | delete m_Xforms; | |||
7617 | } | |||
7618 | ||||
7619 | if (m_pApply) | |||
7620 | delete m_pApply; | |||
7621 | } | |||
7622 | ||||
7623 | const icChar* CIccCmm::GetStatusText(icStatusCMM stat) | |||
7624 | { | |||
7625 | switch (stat) { | |||
7626 | case icCmmStatBad: | |||
7627 | return "Bad CMM"; | |||
7628 | case icCmmStatOk: | |||
7629 | return "OK"; | |||
7630 | case icCmmStatCantOpenProfile: | |||
7631 | return "Cannot open profile"; | |||
7632 | case icCmmStatBadSpaceLink: | |||
7633 | return "Invalid space link"; | |||
7634 | case icCmmStatInvalidProfile: | |||
7635 | return "Invalid profile"; | |||
7636 | case icCmmStatBadXform: | |||
7637 | return "Invalid profile transform"; | |||
7638 | case icCmmStatInvalidLut: | |||
7639 | return "Invalid Look-Up Table"; | |||
7640 | case icCmmStatProfileMissingTag: | |||
7641 | return "Missing tag in profile"; | |||
7642 | case icCmmStatColorNotFound: | |||
7643 | return "Color not found"; | |||
7644 | case icCmmStatIncorrectApply: | |||
7645 | return "Incorrect Apply object"; | |||
7646 | case icCmmStatBadColorEncoding: | |||
7647 | return "Invalid color encoding used"; | |||
7648 | case icCmmStatAllocErr: | |||
7649 | return "Memory allocation error"; | |||
7650 | case icCmmStatBadLutType: | |||
7651 | return "Invalid Look-Up Table type"; | |||
7652 | case icCmmStatIdentityXform: | |||
7653 | return "Identity transform used"; | |||
7654 | case icCmmStatUnsupportedPcsLink: | |||
7655 | return "Unsupported PCS Link used"; | |||
7656 | case icCmmStatBadConnection: | |||
7657 | return "Invalid profile connection"; | |||
7658 | case icCmmStatBadTintXform: | |||
7659 | return "Invalid tint transform"; | |||
7660 | case icCmmStatTooManySamples: | |||
7661 | return "Too many samples used"; | |||
7662 | case icCmmStatBadMCSLink: | |||
7663 | return "Invalid MCS link connection"; | |||
7664 | default: | |||
7665 | return "Unknown CMM Status value"; | |||
7666 | ||||
7667 | } | |||
7668 | } | |||
7669 | ||||
7670 | /** | |||
7671 | ************************************************************************** | |||
7672 | * Name: CIccCmm::AddXform | |||
7673 | * | |||
7674 | * Purpose: | |||
7675 | * Adds a profile at the end of the Xform list | |||
7676 | * | |||
7677 | * Args: | |||
7678 | * szProfilePath = file name of the profile to be added, | |||
7679 | * nIntent = rendering intent to be used with the profile, | |||
7680 | * nInterp = type of interpolation to be used with the profile, | |||
7681 | * nLutType = selection of which transform lut to use | |||
7682 | * pHintManager = hints for creating the xform | |||
7683 | * | |||
7684 | * Return: | |||
7685 | * icCmmStatOk, if the profile was added to the list succesfully | |||
7686 | ************************************************************************** | |||
7687 | */ | |||
7688 | icStatusCMM CIccCmm::AddXform(const icChar *szProfilePath, | |||
7689 | icRenderingIntent nIntent /*=icUnknownIntent*/, | |||
7690 | icXformInterp nInterp /*icXformInterp*/, | |||
7691 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
7692 | icXformLutType nLutType /*=icXformLutColor*/, | |||
7693 | bool bUseD2BxB2DxTags /*=true*/, | |||
7694 | CIccCreateXformHintManager *pHintManager /*=NULL*/, | |||
7695 | bool bUseSubProfile /*=false*/) | |||
7696 | { | |||
7697 | CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile); | |||
7698 | ||||
7699 | if (!pProfile) | |||
7700 | return icCmmStatCantOpenProfile; | |||
7701 | ||||
7702 | icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | |||
7703 | ||||
7704 | if (rv != icCmmStatOk) | |||
7705 | delete pProfile; | |||
7706 | ||||
7707 | return rv; | |||
7708 | } | |||
7709 | ||||
7710 | ||||
7711 | /** | |||
7712 | ************************************************************************** | |||
7713 | * Name: CIccCmm::AddXform | |||
7714 | * | |||
7715 | * Purpose: | |||
7716 | * Adds a profile at the end of the Xform list | |||
7717 | * | |||
7718 | * Args: | |||
7719 | * pProfileMem = ptr to profile loaded into memory. Note: this memory | |||
7720 | * needs to be available until after the Begin() function is called. | |||
7721 | * nProfileLen = size in bytes of profile loaded into memory | |||
7722 | * nIntent = rendering intent to be used with the profile, | |||
7723 | * nInterp = type of interpolation to be used with the profile, | |||
7724 | * nLutType = selection of which transform lut to use | |||
7725 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | |||
7726 | * pHintManager = hints for creating the xform | |||
7727 | * | |||
7728 | * Return: | |||
7729 | * icCmmStatOk, if the profile was added to the list succesfully | |||
7730 | ************************************************************************** | |||
7731 | */ | |||
7732 | icStatusCMM CIccCmm::AddXform(icUInt8Number *pProfileMem, | |||
7733 | icUInt32Number nProfileLen, | |||
7734 | icRenderingIntent nIntent /*=icUnknownIntent*/, | |||
7735 | icXformInterp nInterp /*icXformInterp*/, | |||
7736 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
7737 | icXformLutType nLutType /*=icXformLutColor*/, | |||
7738 | bool bUseD2BxB2DxTags /*=true*/, | |||
7739 | CIccCreateXformHintManager *pHintManager /*=NULL*/, | |||
7740 | bool bUseSubProfile /*=false*/) | |||
7741 | { | |||
7742 | CIccMemIO *pFile = new CIccMemIO; | |||
7743 | ||||
7744 | if (!pFile || !pFile->Attach(pProfileMem, nProfileLen, bUseSubProfile)) | |||
7745 | return icCmmStatCantOpenProfile; | |||
7746 | ||||
7747 | CIccProfile *pProfile = new CIccProfile; | |||
7748 | ||||
7749 | if (!pProfile) | |||
7750 | return icCmmStatCantOpenProfile; | |||
7751 | ||||
7752 | if (!pProfile->Attach(pFile)) { | |||
7753 | delete pFile; | |||
7754 | delete pProfile; | |||
7755 | return icCmmStatCantOpenProfile; | |||
7756 | } | |||
7757 | ||||
7758 | icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | |||
7759 | ||||
7760 | if (rv != icCmmStatOk) | |||
7761 | delete pProfile; | |||
7762 | ||||
7763 | return rv; | |||
7764 | } | |||
7765 | ||||
7766 | ||||
7767 | /** | |||
7768 | ************************************************************************** | |||
7769 | * Name: CIccCmm::AddXform | |||
7770 | * | |||
7771 | * Purpose: | |||
7772 | * Adds a profile at the end of the Xform list | |||
7773 | * | |||
7774 | * Args: | |||
7775 | * pProfile = pointer to the CIccProfile object to be added, | |||
7776 | * nIntent = rendering intent to be used with the profile, | |||
7777 | * nInterp = type of interpolation to be used with the profile, | |||
7778 | * nLutType = selection of which transform lut to use | |||
7779 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | |||
7780 | * pHintManager = hints for creating the xform | |||
7781 | * | |||
7782 | * Return: | |||
7783 | * icCmmStatOk, if the profile was added to the list succesfully | |||
7784 | ************************************************************************** | |||
7785 | */ | |||
7786 | icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile, | |||
7787 | icRenderingIntent nIntent /*=icUnknownIntent*/, | |||
7788 | icXformInterp nInterp /*=icInterpLinear*/, | |||
7789 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
7790 | icXformLutType nLutType /*=icXformLutColor*/, | |||
7791 | bool bUseD2BxB2DxTags /*=true*/, | |||
7792 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | |||
7793 | { | |||
7794 | icColorSpaceSignature nSrcSpace, nDstSpace; | |||
7795 | bool bInput = !m_bLastInput; | |||
7796 | ||||
7797 | if (!pProfile) | |||
7798 | return icCmmStatInvalidProfile; | |||
7799 | ||||
7800 | switch(pProfile->m_Header.deviceClass) { | |||
7801 | case icSigMaterialIdentificationClass: | |||
7802 | case icSigMaterialVisualizationClass: | |||
7803 | case icSigMaterialLinkClass: | |||
7804 | nIntent = icPerceptual; | |||
7805 | nLutType = icXformLutMCS; | |||
7806 | ||||
7807 | default: | |||
7808 | break; | |||
7809 | } | |||
7810 | ||||
7811 | switch (nLutType) { | |||
7812 | case icXformLutColor: | |||
7813 | case icXformLutColorimetric: | |||
7814 | case icXformLutSpectral: | |||
7815 | { | |||
7816 | //Check pProfile if nIntent and input can be found. | |||
7817 | if (bInput) { | |||
7818 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
7819 | ||||
7820 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) | |||
7821 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
7822 | else | |||
7823 | nDstSpace = pProfile->m_Header.pcs; | |||
7824 | } | |||
7825 | else { | |||
7826 | if (pProfile->m_Header.deviceClass == icSigLinkClass) { | |||
7827 | return icCmmStatBadSpaceLink; | |||
7828 | } | |||
7829 | if (pProfile->m_Header.deviceClass == icSigAbstractClass) { | |||
7830 | bInput = true; | |||
7831 | nIntent = icPerceptual; // Note: icPerceptualIntent = 0 | |||
7832 | } | |||
7833 | ||||
7834 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) | |||
7835 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
7836 | else | |||
7837 | nSrcSpace = pProfile->m_Header.pcs; | |||
7838 | ||||
7839 | nDstSpace = pProfile->m_Header.colorSpace; | |||
7840 | } | |||
7841 | } | |||
7842 | break; | |||
7843 | ||||
7844 | case icXformLutPreview: | |||
7845 | nSrcSpace = pProfile->m_Header.pcs; | |||
7846 | nDstSpace = pProfile->m_Header.pcs; | |||
7847 | bInput = false; | |||
7848 | break; | |||
7849 | ||||
7850 | case icXformLutGamut: | |||
7851 | nSrcSpace = pProfile->m_Header.pcs; | |||
7852 | nDstSpace = icSigGamutData((icColorSpaceSignature) 0x67616D74); | |||
7853 | bInput = true; | |||
7854 | break; | |||
7855 | ||||
7856 | case icXformLutBRDFParam: | |||
7857 | if (!bInput) | |||
7858 | return icCmmStatBadSpaceLink; | |||
7859 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
7860 | nDstSpace = icSigBRDFParameters((icColorSpaceSignature) 0x62700000); | |||
7861 | bInput = true; | |||
7862 | break; | |||
7863 | ||||
7864 | case icXformLutBRDFDirect: | |||
7865 | if (!bInput) | |||
7866 | return icCmmStatBadSpaceLink; | |||
7867 | nSrcSpace = icSigBRDFDirect((icColorSpaceSignature) 0x62640000); | |||
7868 | nDstSpace = pProfile->m_Header.pcs; | |||
7869 | bInput = true; | |||
7870 | break; | |||
7871 | ||||
7872 | case icXformLutBRDFMcsParam: | |||
7873 | if (!bInput) | |||
7874 | return icCmmStatBadSpaceLink; | |||
7875 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | |||
7876 | nDstSpace = icSigBRDFParameters((icColorSpaceSignature) 0x62700000); | |||
7877 | break; | |||
7878 | ||||
7879 | case icXformLutMCS: | |||
7880 | if (bInput) { | |||
7881 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
7882 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | |||
7883 | } | |||
7884 | else { | |||
7885 | if (m_Xforms->size()) { | |||
7886 | CIccXformList::iterator prev = --(m_Xforms->end()); | |||
7887 | ||||
7888 | //Make sure previous profile connects with an icXformLutMCS | |||
7889 | if (prev->ptr->GetXformType()!=icXformLutMCS) { | |||
7890 | //check to see if we can convert previous xform to connect via an MCS | |||
7891 | if (!prev->ptr->GetProfile()->m_Header.mcs) { | |||
7892 | return icCmmStatBadMCSLink; | |||
7893 | } | |||
7894 | ||||
7895 | CIccXform *pPrev = prev->ptr; | |||
7896 | CIccXform *pNew = CIccXform::Create(pPrev->GetProfilePtr(), pPrev->IsInput(), pPrev->GetIntent(), pPrev->GetInterp(), | |||
7897 | pPrev->GetConnectionConditions(), icXformLutMCS, bUseD2BxB2DxTags, pHintManager); | |||
7898 | ||||
7899 | if (pNew) { | |||
7900 | pPrev->DetachAll(); | |||
7901 | delete pPrev; | |||
7902 | } | |||
7903 | ||||
7904 | prev->ptr = pNew; | |||
7905 | ||||
7906 | } | |||
7907 | } | |||
7908 | else { | |||
7909 | return icCmmStatBadMCSLink; | |||
7910 | } | |||
7911 | ||||
7912 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | |||
7913 | if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) { | |||
7914 | if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) { | |||
7915 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
7916 | } | |||
7917 | else { | |||
7918 | nDstSpace = pProfile->m_Header.pcs; | |||
7919 | } | |||
7920 | } | |||
7921 | else if (pProfile->m_Header.deviceClass==icSigMaterialLinkClass) { | |||
7922 | nDstSpace = pProfile->m_Header.colorSpace; | |||
7923 | } | |||
7924 | else { | |||
7925 | return icCmmStatBadSpaceLink; | |||
7926 | } | |||
7927 | } | |||
7928 | break; | |||
7929 | ||||
7930 | default: | |||
7931 | return icCmmStatBadLutType; | |||
7932 | } | |||
7933 | ||||
7934 | //Make sure colorspaces match with previous xforms | |||
7935 | if (!m_Xforms->size()) { | |||
7936 | if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
7937 | m_nLastSpace = nSrcSpace; | |||
7938 | m_nSrcSpace = nSrcSpace; | |||
7939 | } | |||
7940 | else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | |||
7941 | return icCmmStatBadSpaceLink; | |||
7942 | } | |||
7943 | } | |||
7944 | else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData || (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | |||
7945 | return icCmmStatBadSpaceLink; | |||
7946 | } | |||
7947 | ||||
7948 | if (nSrcSpace==icSigNamedData) | |||
7949 | return icCmmStatBadSpaceLink; | |||
7950 | ||||
7951 | //Automatic creation of intent from header/last profile | |||
7952 | if (nIntent==icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) { | |||
7953 | if (bInput) { | |||
7954 | nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; | |||
7955 | } | |||
7956 | else { | |||
7957 | nIntent = m_nLastIntent; | |||
7958 | } | |||
7959 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | |||
7960 | nIntent = icPerceptual; | |||
7961 | } | |||
7962 | ||||
7963 | CIccXformPtr Xform; | |||
7964 | ||||
7965 | Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | |||
7966 | ||||
7967 | if (!Xform.ptr) { | |||
7968 | return icCmmStatBadXform; | |||
7969 | } | |||
7970 | ||||
7971 | if (pProfile->m_Header.deviceClass==icSigMaterialVisualizationClass) { | |||
7972 | bInput = true; | |||
7973 | } | |||
7974 | ||||
7975 | m_nLastSpace = nDstSpace; | |||
7976 | m_nLastIntent = nIntent; | |||
7977 | m_bLastInput = bInput; | |||
7978 | ||||
7979 | m_Xforms->push_back(Xform); | |||
7980 | ||||
7981 | return icCmmStatOk; | |||
7982 | } | |||
7983 | ||||
7984 | /** | |||
7985 | ************************************************************************** | |||
7986 | * Name: CIccCmm::AddXform | |||
7987 | * | |||
7988 | * Purpose: | |||
7989 | * Adds a profile at the end of the Xform list | |||
7990 | * | |||
7991 | * Args: | |||
7992 | * pProfile = pointer to the CIccProfile object to be added, | |||
7993 | * nIntent = rendering intent to be used with the profile, | |||
7994 | * nInterp = type of interpolation to be used with the profile, | |||
7995 | * nLutType = selection of which transform lut to use | |||
7996 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | |||
7997 | * pHintManager = hints for creating the xform | |||
7998 | * | |||
7999 | * Return: | |||
8000 | * icCmmStatOk, if the profile was added to the list succesfully | |||
8001 | ************************************************************************** | |||
8002 | */ | |||
8003 | icStatusCMM CIccCmm::AddXform(CIccProfile *pProfile, | |||
8004 | CIccTag *pXformTag, | |||
8005 | icRenderingIntent nIntent/*= icUnknownIntent*/, | |||
8006 | icXformInterp nInterp /*=icInterpLinear*/, | |||
8007 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
8008 | bool bUseSpectralPCS /*=false*/, | |||
8009 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | |||
8010 | { | |||
8011 | icColorSpaceSignature nSrcSpace, nDstSpace; | |||
8012 | bool bInput = !m_bLastInput; | |||
8013 | ||||
8014 | if (!pProfile) | |||
8015 | return icCmmStatInvalidProfile; | |||
8016 | ||||
8017 | switch (pProfile->m_Header.deviceClass) { | |||
8018 | case icSigMaterialIdentificationClass: | |||
8019 | case icSigMaterialVisualizationClass: | |||
8020 | case icSigMaterialLinkClass: | |||
8021 | return icCmmStatBadLutType; | |||
8022 | ||||
8023 | default: | |||
8024 | break; | |||
8025 | } | |||
8026 | ||||
8027 | //Check pProfile if nIntent and input can be found. | |||
8028 | if (bInput) { | |||
8029 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
8030 | ||||
8031 | if (bUseSpectralPCS && pProfile->m_Header.spectralPCS) | |||
8032 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
8033 | else { | |||
8034 | nDstSpace = pProfile->m_Header.pcs; | |||
8035 | bUseSpectralPCS = false; | |||
8036 | } | |||
8037 | } | |||
8038 | else { | |||
8039 | if (pProfile->m_Header.deviceClass == icSigLinkClass) { | |||
8040 | return icCmmStatBadSpaceLink; | |||
8041 | } | |||
8042 | if (pProfile->m_Header.deviceClass == icSigAbstractClass) { | |||
8043 | bInput = true; | |||
8044 | nIntent = icPerceptual; // Note: icPerceptualIntent = 0 | |||
8045 | } | |||
8046 | ||||
8047 | if (bUseSpectralPCS && pProfile->m_Header.spectralPCS) | |||
8048 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
8049 | else { | |||
8050 | nSrcSpace = pProfile->m_Header.pcs; | |||
8051 | bUseSpectralPCS = false; | |||
8052 | } | |||
8053 | ||||
8054 | nDstSpace = pProfile->m_Header.colorSpace; | |||
8055 | } | |||
8056 | ||||
8057 | //Make sure colorspaces match with previous xforms | |||
8058 | if (!m_Xforms->size()) { | |||
8059 | if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
8060 | m_nLastSpace = nSrcSpace; | |||
8061 | m_nSrcSpace = nSrcSpace; | |||
8062 | } | |||
8063 | else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | |||
8064 | return icCmmStatBadSpaceLink; | |||
8065 | } | |||
8066 | } | |||
8067 | else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData || (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) )) { | |||
8068 | return icCmmStatBadSpaceLink; | |||
8069 | } | |||
8070 | ||||
8071 | if (nSrcSpace == icSigNamedData) | |||
8072 | return icCmmStatBadSpaceLink; | |||
8073 | ||||
8074 | //Automatic creation of intent from header/last profile | |||
8075 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) { | |||
8076 | if (bInput) { | |||
8077 | nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; | |||
8078 | } | |||
8079 | else { | |||
8080 | nIntent = m_nLastIntent; | |||
8081 | } | |||
8082 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | |||
8083 | nIntent = icPerceptual; | |||
8084 | } | |||
8085 | ||||
8086 | CIccXformPtr Xform; | |||
8087 | ||||
8088 | Xform.ptr = CIccXform::Create(pProfile, pXformTag, bInput, nIntent, nInterp, pPcc, bUseSpectralPCS, pHintManager); | |||
8089 | ||||
8090 | if (!Xform.ptr) { | |||
8091 | return icCmmStatBadXform; | |||
8092 | } | |||
8093 | ||||
8094 | m_nLastSpace = nDstSpace; | |||
8095 | m_nLastIntent = nIntent; | |||
8096 | m_bLastInput = bInput; | |||
8097 | ||||
8098 | m_Xforms->push_back(Xform); | |||
8099 | ||||
8100 | return icCmmStatOk; | |||
8101 | } | |||
8102 | ||||
8103 | /** | |||
8104 | ************************************************************************** | |||
8105 | * Name: CIccCmm::AddXform | |||
8106 | * | |||
8107 | * Purpose: | |||
8108 | * Adds a profile at the end of the Xform list | |||
8109 | * | |||
8110 | * Args: | |||
8111 | * Profile = reference a CIccProfile object that will be copies and added, | |||
8112 | * nIntent = rendering intent to be used with the profile, | |||
8113 | * nInterp = type of interpolation to be used with the profile, | |||
8114 | * nLutType = selection of which transform lut to use | |||
8115 | * bUseD2BxB2DxTags = flag to indicate the use MPE flags if available | |||
8116 | * pHintManager = hints for creating the xform | |||
8117 | * | |||
8118 | * Return: | |||
8119 | * icCmmStatOk, if the profile was added to the list succesfully | |||
8120 | ************************************************************************** | |||
8121 | */ | |||
8122 | icStatusCMM CIccCmm::AddXform(CIccProfile &Profile, | |||
8123 | icRenderingIntent nIntent /*=icUnknownIntent*/, | |||
8124 | icXformInterp nInterp /*=icInterpLinear*/, | |||
8125 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
8126 | icXformLutType nLutType /*=icXformLutColor*/, | |||
8127 | bool bUseD2BxB2DxTags /*=true*/, | |||
8128 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | |||
8129 | { | |||
8130 | CIccProfile *pProfile = new CIccProfile(Profile); | |||
8131 | ||||
8132 | if (!pProfile) | |||
8133 | return icCmmStatAllocErr; | |||
8134 | ||||
8135 | icStatusCMM stat = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | |||
8136 | ||||
8137 | if (stat != icCmmStatOk) | |||
8138 | delete pProfile; | |||
8139 | ||||
8140 | return stat; | |||
8141 | } | |||
8142 | ||||
8143 | icStatusCMM CIccCmm::CheckPCSConnections(bool bUsePCSConversions/*=false*/) | |||
8144 | { | |||
8145 | icStatusCMM rv = icCmmStatOk; | |||
8146 | ||||
8147 | CIccXformList::iterator last, next; | |||
8148 | CIccXformList xforms; | |||
8149 | CIccXformPtr ptr; | |||
8150 | bool bUsesPcsXforms = false; | |||
8151 | ||||
8152 | next=m_Xforms->begin(); | |||
8153 | ||||
8154 | if (next!=m_Xforms->end()) { | |||
8155 | last = next; | |||
8156 | next++; | |||
8157 | ||||
8158 | xforms.push_back(*last); | |||
8159 | ||||
8160 | for (;next!=m_Xforms->end(); last=next, next++) { | |||
8161 | if ((last->ptr->IsInput() && last->ptr->IsMCS() && next->ptr->IsMCS()) || | |||
8162 | (IsSpaceSpectralPCS(last->ptr->GetDstSpace()) || IsSpaceSpectralPCS(next->ptr->GetSrcSpace())) || | |||
8163 | (!bUsePCSConversions && | |||
8164 | (IsSpaceColorimetricPCS(last->ptr->GetDstSpace())((last->ptr->GetDstSpace())==icSigXYZData || (last-> ptr->GetDstSpace())==icSigLabData) || IsSpaceColorimetricPCS(next->ptr->GetSrcSpace())((next->ptr->GetSrcSpace())==icSigXYZData || (next-> ptr->GetSrcSpace())==icSigLabData)))) { | |||
8165 | last->ptr->SetDstPCSConversion(false); | |||
8166 | next->ptr->SetSrcPCSConversion(false); | |||
8167 | CIccPcsXform *pPcs = new CIccPcsXform(); | |||
8168 | ||||
8169 | if (!pPcs) { | |||
8170 | return icCmmStatAllocErr; | |||
8171 | } | |||
8172 | ||||
8173 | rv = pPcs->Connect(last->ptr, next->ptr); | |||
8174 | ||||
8175 | if (rv!=icCmmStatOk && rv!=icCmmStatIdentityXform) | |||
8176 | return rv; | |||
8177 | ||||
8178 | if (rv!=icCmmStatIdentityXform) { | |||
8179 | ptr.ptr = pPcs; | |||
8180 | xforms.push_back(ptr); | |||
8181 | } | |||
8182 | else { | |||
8183 | delete pPcs; | |||
8184 | } | |||
8185 | ||||
8186 | bUsesPcsXforms = true; | |||
8187 | } | |||
8188 | xforms.push_back(*next); | |||
8189 | } | |||
8190 | } | |||
8191 | ||||
8192 | if (bUsesPcsXforms) { | |||
8193 | *m_Xforms = xforms; | |||
8194 | } | |||
8195 | ||||
8196 | return rv; | |||
8197 | } | |||
8198 | ||||
8199 | /** | |||
8200 | ************************************************************************** | |||
8201 | * Name: CIccCmm::SetLateBindingCC | |||
8202 | * | |||
8203 | * Purpose: | |||
8204 | * Initializes the LateBinding Connection Conditions used by | |||
8205 | * colorimetric based transforms | |||
8206 | * | |||
8207 | ************************************************************************** | |||
8208 | */ | |||
8209 | void CIccCmm::SetLateBindingCC() | |||
8210 | { | |||
8211 | CIccXformList::iterator i; | |||
8212 | CIccXform *pLastXform = NULL__null; | |||
8213 | ||||
8214 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
8215 | if (i->ptr->IsInput()) { | |||
8216 | if (i->ptr->IsLateBinding()) { | |||
8217 | CIccXformList::iterator j=i; | |||
8218 | j++; | |||
8219 | if (j!=m_Xforms->end()) { | |||
8220 | if (j->ptr->IsLateBinding()) { | |||
8221 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | |||
8222 | j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | |||
8223 | pLastXform = i->ptr; | |||
8224 | } | |||
8225 | else { | |||
8226 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | |||
8227 | j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions()); | |||
8228 | pLastXform = NULL__null; | |||
8229 | } | |||
8230 | } | |||
8231 | else { | |||
8232 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | |||
8233 | pLastXform = NULL__null; | |||
8234 | } | |||
8235 | } | |||
8236 | else if (IsSpaceSpectralPCS(i->ptr->GetDstSpace())) { | |||
8237 | CIccXformList::iterator j=i; | |||
8238 | j++; | |||
8239 | if (j!=m_Xforms->end()) { | |||
8240 | if (j->ptr->IsLateBinding()) { | |||
8241 | j->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | |||
8242 | pLastXform = i->ptr; | |||
8243 | } | |||
8244 | else if (!j->ptr->IsAbstract()){ | |||
8245 | j->ptr->SetAppliedCC(j->ptr->GetConnectionConditions()); | |||
8246 | pLastXform = NULL__null; | |||
8247 | } | |||
8248 | } | |||
8249 | } | |||
8250 | else { | |||
8251 | pLastXform = NULL__null; | |||
8252 | } | |||
8253 | } | |||
8254 | else { | |||
8255 | if (!pLastXform) | |||
8256 | i->ptr->SetAppliedCC(i->ptr->GetConnectionConditions()); | |||
8257 | else | |||
8258 | pLastXform = NULL__null; | |||
8259 | } | |||
8260 | } | |||
8261 | } | |||
8262 | ||||
8263 | ||||
8264 | /** | |||
8265 | ************************************************************************** | |||
8266 | * Name: CIccCmm::Begin | |||
8267 | * | |||
8268 | * Purpose: | |||
8269 | * Does the initialization of the Xforms before Apply() is called. | |||
8270 | * Must be called before Apply(). | |||
8271 | * | |||
8272 | ************************************************************************** | |||
8273 | */ | |||
8274 | icStatusCMM CIccCmm::Begin(bool bAllocApplyCmm/*=true*/, bool bUsePCSConversions/*=false*/) | |||
8275 | { | |||
8276 | if (m_pApply) | |||
8277 | return icCmmStatOk; | |||
8278 | ||||
8279 | if (m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
8280 | m_nDestSpace = m_nLastSpace; | |||
8281 | } | |||
8282 | else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)((m_nDestSpace)==(m_nLastSpace) || ((((m_nDestSpace)==icSigXYZData || (m_nDestSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nDestSpace )) && (((m_nLastSpace)==icSigXYZData || (m_nLastSpace )==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace))) || ((( (icColorSpaceSignature)(((icUInt32Number)m_nDestSpace)&0xffff0000 ))==icSigSrcMCSChannelData) && (((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData )) )) { | |||
8283 | return icCmmStatBadSpaceLink; | |||
8284 | } | |||
8285 | ||||
8286 | if (m_nSrcSpace==icSigNamedData || m_nDestSpace==icSigNamedData) { | |||
8287 | return icCmmStatBadSpaceLink; | |||
8288 | } | |||
8289 | ||||
8290 | SetLateBindingCC(); | |||
8291 | ||||
8292 | icStatusCMM rv; | |||
8293 | CIccXformList::iterator i; | |||
8294 | ||||
8295 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
8296 | ||||
8297 | rv = i->ptr->Begin(); | |||
8298 | ||||
8299 | if (rv!= icCmmStatOk) | |||
8300 | return rv; | |||
8301 | } | |||
8302 | ||||
8303 | rv = CheckPCSConnections(bUsePCSConversions); | |||
8304 | if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform) | |||
8305 | return rv; | |||
8306 | ||||
8307 | if (bAllocApplyCmm) { | |||
8308 | m_pApply = GetNewApplyCmm(rv); | |||
8309 | } | |||
8310 | else | |||
8311 | rv = icCmmStatOk; | |||
8312 | ||||
8313 | return rv; | |||
8314 | } | |||
8315 | ||||
8316 | ||||
8317 | /** | |||
8318 | ************************************************************************** | |||
8319 | * Name: CIccCmm::GetNewApplyCmm | |||
8320 | * | |||
8321 | * Purpose: | |||
8322 | * Allocates an CIccApplyCmm object that does the initialization of the Xforms | |||
8323 | * that provides an Apply() function. | |||
8324 | * Multiple CIccApplyCmm objects can be allocated and used in separate threads. | |||
8325 | * | |||
8326 | ************************************************************************** | |||
8327 | */ | |||
8328 | CIccApplyCmm *CIccCmm::GetNewApplyCmm(icStatusCMM &status) | |||
8329 | { | |||
8330 | CIccApplyCmm *pApply = new CIccApplyCmm(this); | |||
8331 | ||||
8332 | if (!pApply) { | |||
8333 | status = icCmmStatAllocErr; | |||
8334 | return NULL__null; | |||
8335 | } | |||
8336 | ||||
8337 | CIccXformList::iterator i; | |||
8338 | CIccApplyXform *pXform; | |||
8339 | ||||
8340 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
8341 | pXform = i->ptr->GetNewApply(status); | |||
8342 | if (!pXform || status != icCmmStatOk) { | |||
8343 | delete pApply; | |||
8344 | return NULL__null; | |||
8345 | } | |||
8346 | pApply->AppendApplyXform(pXform); | |||
8347 | } | |||
8348 | ||||
8349 | m_bValid = true; | |||
8350 | ||||
8351 | status = icCmmStatOk; | |||
8352 | ||||
8353 | return pApply; | |||
8354 | } | |||
8355 | ||||
8356 | ||||
8357 | /** | |||
8358 | ************************************************************************** | |||
8359 | * Name: CIccCmm::Apply | |||
8360 | * | |||
8361 | * Purpose: | |||
8362 | * Uses the m_pApply object allocated during Begin to Apply the transformations | |||
8363 | * associated with the CMM. | |||
8364 | * | |||
8365 | ************************************************************************** | |||
8366 | */ | |||
8367 | icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | |||
8368 | { | |||
8369 | return m_pApply->Apply(DstPixel, SrcPixel); | |||
8370 | } | |||
8371 | ||||
8372 | ||||
8373 | /** | |||
8374 | ************************************************************************** | |||
8375 | * Name: CIccCmm::Apply | |||
8376 | * | |||
8377 | * Purpose: | |||
8378 | * Uses the m_pApply object allocated during Begin to Apply the transformations | |||
8379 | * associated with the CMM. | |||
8380 | * | |||
8381 | ************************************************************************** | |||
8382 | */ | |||
8383 | icStatusCMM CIccCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | |||
8384 | { | |||
8385 | return m_pApply->Apply(DstPixel, SrcPixel, nPixels); | |||
8386 | } | |||
8387 | ||||
8388 | ||||
8389 | /** | |||
8390 | ************************************************************************** | |||
8391 | * Name: CIccCmm::RemoveAllIO() | |||
8392 | * | |||
8393 | * Purpose: | |||
8394 | * Remove any attachments to CIccIO objects associated with the profiles | |||
8395 | * related to the transforms attached to the CMM. | |||
8396 | * Must be called after Begin(). | |||
8397 | * | |||
8398 | * Return: | |||
8399 | * icCmmStatOK - All IO objects removed | |||
8400 | * icCmmStatBadXform - Begin() has not been performed. | |||
8401 | ************************************************************************** | |||
8402 | */ | |||
8403 | icStatusCMM CIccCmm::RemoveAllIO() | |||
8404 | { | |||
8405 | if (!Valid()) | |||
8406 | return icCmmStatBadXform; | |||
8407 | ||||
8408 | CIccXformList::iterator i; | |||
8409 | ||||
8410 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
8411 | i->ptr->RemoveIO(); | |||
8412 | } | |||
8413 | ||||
8414 | return icCmmStatOk; | |||
8415 | } | |||
8416 | ||||
8417 | /** | |||
8418 | ************************************************************************* | |||
8419 | ** Name: CIccCmm::IsInGamut | |||
8420 | ** | |||
8421 | ** Purpose: | |||
8422 | ** Function to check if internal representation of gamut is in gamut. Note | |||
8423 | ** since gamut table is 8 bit and a color is considered to be in out of gamut | |||
8424 | ** if the value is not zero. Then we need to check where the 8 bit representation | |||
8425 | ** of the internal value is not zero. | |||
8426 | ** | |||
8427 | ** Args: | |||
8428 | ** pInternal = internal pixel representation of gamut value | |||
8429 | ** | |||
8430 | ** Return: | |||
8431 | ** true if in gamut, false if out of gamut | |||
8432 | **************************************************************************/ | |||
8433 | bool CIccCmm::IsInGamut(icFloatNumber *pInternal) | |||
8434 | { | |||
8435 | if (!((unsigned int)((*pInternal)*255.0))) | |||
8436 | return true; | |||
8437 | return false; | |||
8438 | } | |||
8439 | ||||
8440 | ||||
8441 | /** | |||
8442 | ************************************************************************** | |||
8443 | * Name: CIccCmm::ToInternalEncoding | |||
8444 | * | |||
8445 | * Purpose: | |||
8446 | * Functions for converting to Internal representation of pixel colors. | |||
8447 | * | |||
8448 | * Args: | |||
8449 | * nSpace = color space signature of the data, | |||
8450 | * nEncode = icFloatColorEncoding type of the data, | |||
8451 | * pInternal = converted data is stored here, | |||
8452 | * pData = the data to be converted | |||
8453 | * bClip = flag to clip to internal range | |||
8454 | ************************************************************************** | |||
8455 | */ | |||
8456 | icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode, | |||
8457 | icFloatNumber *pInternal, const icFloatNumber *pData, | |||
8458 | bool bClip) | |||
8459 | { | |||
8460 | int nSamples = icGetSpaceSamples(nSpace); | |||
8461 | if (!nSamples) | |||
8462 | return icCmmStatBadColorEncoding; | |||
8463 | ||||
8464 | ||||
8465 | icUInt16Number i; | |||
8466 | CIccPixelBuf pInput(nSamples); | |||
8467 | ||||
8468 | if (!pInput.get()) | |||
8469 | return icCmmStatAllocErr; | |||
8470 | ||||
8471 | memcpy(pInput, pData, nSamples*sizeof(icFloatNumber)); | |||
8472 | bool bCLRspace = icIsSpaceCLR(nSpace); | |||
8473 | ||||
8474 | switch(icGetColorSpaceType(nSpace)((icColorSpaceSignature)(((icUInt32Number)nSpace)&0xffff0000 ))) | |||
8475 | { | |||
8476 | case icSigReflectanceSpectralPcsData((icColorSpaceSignature)icSigReflectanceSpectralData): | |||
8477 | case icSigTransmissionSpectralPcsData((icColorSpaceSignature)icSigTransmisionSpectralData): | |||
8478 | case icSigBiDirReflectanceSpectralPcsData((icColorSpaceSignature)icSigBiSpectralReflectanceData): | |||
8479 | case icSigSparseMatrixSpectralPcsData((icColorSpaceSignature)icSigSparseMatrixReflectanceData): | |||
8480 | bCLRspace = true; | |||
8481 | break; | |||
8482 | } | |||
8483 | ||||
8484 | switch(nSpace) { | |||
8485 | ||||
8486 | case icSigLabData: | |||
8487 | { | |||
8488 | switch(nEncode) { | |||
8489 | case icEncodeValue: | |||
8490 | { | |||
8491 | icLabToPcs(pInput); | |||
8492 | break; | |||
8493 | } | |||
8494 | case icEncodeFloat: | |||
8495 | { | |||
8496 | break; | |||
8497 | } | |||
8498 | case icEncode8Bit: | |||
8499 | { | |||
8500 | pInput[0] = icU8toF((icUInt8Number)pInput[0])*100.0f; | |||
8501 | pInput[1] = icU8toAB((icUInt8Number)pInput[1]); | |||
8502 | pInput[2] = icU8toAB((icUInt8Number)pInput[2]); | |||
8503 | ||||
8504 | icLabToPcs(pInput); | |||
8505 | break; | |||
8506 | } | |||
8507 | case icEncode16Bit: | |||
8508 | { | |||
8509 | pInput[0] = icU16toF((icUInt16Number)pInput[0]); | |||
8510 | pInput[1] = icU16toF((icUInt16Number)pInput[1]); | |||
8511 | pInput[2] = icU16toF((icUInt16Number)pInput[2]); | |||
8512 | break; | |||
8513 | } | |||
8514 | case icEncode16BitV2: | |||
8515 | { | |||
8516 | pInput[0] = icU16toF((icUInt16Number)pInput[0]); | |||
8517 | pInput[1] = icU16toF((icUInt16Number)pInput[1]); | |||
8518 | pInput[2] = icU16toF((icUInt16Number)pInput[2]); | |||
8519 | ||||
8520 | CIccPCS::Lab2ToLab4(pInput, pInput); | |||
8521 | break; | |||
8522 | } | |||
8523 | default: | |||
8524 | return icCmmStatBadColorEncoding; | |||
8525 | break; | |||
8526 | } | |||
8527 | break; | |||
8528 | } | |||
8529 | ||||
8530 | case icSigXYZData: | |||
8531 | { | |||
8532 | switch(nEncode) { | |||
8533 | case icEncodeValue: | |||
8534 | { | |||
8535 | pInput[0] = (icFloatNumber)pInput[0]; | |||
8536 | pInput[1] = (icFloatNumber)pInput[1]; | |||
8537 | pInput[2] = (icFloatNumber)pInput[2]; | |||
8538 | icXyzToPcs(pInput); | |||
8539 | break; | |||
8540 | } | |||
8541 | case icEncodePercent: | |||
8542 | { | |||
8543 | pInput[0] = (icFloatNumber)(pInput[0] / 100.0); | |||
8544 | pInput[1] = (icFloatNumber)(pInput[1] / 100.0); | |||
8545 | pInput[2] = (icFloatNumber)(pInput[2] / 100.0); | |||
8546 | icXyzToPcs(pInput); | |||
8547 | break; | |||
8548 | } | |||
8549 | case icEncodeFloat: | |||
8550 | { | |||
8551 | icXyzToPcs(pInput); | |||
8552 | break; | |||
8553 | } | |||
8554 | ||||
8555 | case icEncode16Bit: | |||
8556 | case icEncode16BitV2: | |||
8557 | { | |||
8558 | pInput[0] = icUSFtoD((icU1Fixed15Number)pInput[0]); | |||
8559 | pInput[1] = icUSFtoD((icU1Fixed15Number)pInput[1]); | |||
8560 | pInput[2] = icUSFtoD((icU1Fixed15Number)pInput[2]); | |||
8561 | break; | |||
8562 | } | |||
8563 | ||||
8564 | default: | |||
8565 | return icCmmStatBadColorEncoding; | |||
8566 | break; | |||
8567 | } | |||
8568 | break; | |||
8569 | } | |||
8570 | ||||
8571 | case icSigNamedData: | |||
8572 | return icCmmStatBadColorEncoding; | |||
8573 | ||||
8574 | default: | |||
8575 | { | |||
8576 | switch(nEncode) { | |||
8577 | case icEncodeValue: | |||
8578 | { | |||
8579 | if (!bCLRspace || nSamples<3) { | |||
8580 | return icCmmStatBadColorEncoding; | |||
8581 | } | |||
8582 | if (nSamples==3) | |||
8583 | icLabToPcs(pInput); | |||
8584 | break; | |||
8585 | } | |||
8586 | ||||
8587 | case icEncodePercent: | |||
8588 | { | |||
8589 | if (bClip) { | |||
8590 | for(i=0; i<nSamples; i++) { | |||
8591 | pInput[i] = (icFloatNumber)(pInput[i]/100.0); | |||
8592 | if (pInput[i] < 0.0) pInput[i] = 0.0; | |||
8593 | if (pInput[i] > 1.0) pInput[i] = 1.0; | |||
8594 | } | |||
8595 | } | |||
8596 | else { | |||
8597 | for(i=0; i<nSamples; i++) { | |||
8598 | pInput[i] = (icFloatNumber)(pInput[i]/100.0); | |||
8599 | } | |||
8600 | } | |||
8601 | break; | |||
8602 | } | |||
8603 | ||||
8604 | case icEncodeFloat: | |||
8605 | { | |||
8606 | if (bClip) { | |||
8607 | for(i=0; i<nSamples; i++) { | |||
8608 | if (pInput[i] < 0.0) pInput[i] = 0.0; | |||
8609 | if (pInput[i] > 1.0) pInput[i] = 1.0; | |||
8610 | } | |||
8611 | } | |||
8612 | break; | |||
8613 | } | |||
8614 | ||||
8615 | case icEncode8Bit: | |||
8616 | { | |||
8617 | for(i=0; i<nSamples; i++) { | |||
8618 | pInput[i] = icU8toF((icUInt8Number)pInput[i]); | |||
8619 | } | |||
8620 | break; | |||
8621 | } | |||
8622 | ||||
8623 | case icEncode16Bit: | |||
8624 | case icEncode16BitV2: | |||
8625 | { | |||
8626 | for(i=0; i<nSamples; i++) { | |||
8627 | pInput[i] = icU16toF((icUInt16Number)pInput[i]); | |||
8628 | } | |||
8629 | break; | |||
8630 | } | |||
8631 | ||||
8632 | default: | |||
8633 | return icCmmStatBadColorEncoding; | |||
8634 | break; | |||
8635 | } | |||
8636 | break; | |||
8637 | } | |||
8638 | } | |||
8639 | ||||
8640 | memcpy(pInternal, pInput, nSamples*sizeof(icFloatNumber)); | |||
8641 | return icCmmStatOk; | |||
8642 | } | |||
8643 | ||||
8644 | ||||
8645 | /** | |||
8646 | ************************************************************************** | |||
8647 | * Name: CIccCmm::ToInternalEncoding | |||
8648 | * | |||
8649 | * Purpose: | |||
8650 | * Functions for converting to Internal representation of 8 bit pixel colors. | |||
8651 | * | |||
8652 | * Args: | |||
8653 | * nSpace = color space signature of the data, | |||
8654 | * nEncode = icFloatColorEncoding type of the data, | |||
8655 | * pInternal = converted data is stored here, | |||
8656 | * pData = the data to be converted | |||
8657 | * bClip = flag to clip to internal range | |||
8658 | ************************************************************************** | |||
8659 | */ | |||
8660 | icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal, | |||
8661 | const icUInt8Number *pData) | |||
8662 | { | |||
8663 | switch(nSpace) { | |||
8664 | case icSigRgbData: | |||
8665 | { | |||
8666 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0); | |||
8667 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0); | |||
8668 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0); | |||
8669 | ||||
8670 | return icCmmStatOk; | |||
8671 | } | |||
8672 | case icSigCmykData: | |||
8673 | { | |||
8674 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 255.0); | |||
8675 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 255.0); | |||
8676 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 255.0); | |||
8677 | pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 255.0); | |||
8678 | return icCmmStatOk; | |||
8679 | } | |||
8680 | default: | |||
8681 | { | |||
8682 | icUInt32Number i; | |||
8683 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | |||
8684 | CIccPixelBuf FloatPixel(nSamples); | |||
8685 | if (!FloatPixel.get()) | |||
8686 | return icCmmStatAllocErr; | |||
8687 | ||||
8688 | for(i=0; i<nSamples; i++) { | |||
8689 | FloatPixel[i] = (icFloatNumber)pData[i]; | |||
8690 | } | |||
8691 | return ToInternalEncoding(nSpace, icEncode8Bit, pInternal, FloatPixel); | |||
8692 | } | |||
8693 | } | |||
8694 | ||||
8695 | } | |||
8696 | ||||
8697 | ||||
8698 | /** | |||
8699 | ************************************************************************** | |||
8700 | * Name: CIccCmm::ToInternalEncoding | |||
8701 | * | |||
8702 | * Purpose: | |||
8703 | * Functions for converting to Internal representation of 16 bit pixel colors. | |||
8704 | * | |||
8705 | * Args: | |||
8706 | * nSpace = color space signature of the data, | |||
8707 | * nEncode = icFloatColorEncoding type of the data, | |||
8708 | * pInternal = converted data is stored here, | |||
8709 | * pData = the data to be converted | |||
8710 | * bClip = flag to clip to internal range | |||
8711 | ************************************************************************** | |||
8712 | */ | |||
8713 | icStatusCMM CIccCmm::ToInternalEncoding(icColorSpaceSignature nSpace, icFloatNumber *pInternal, | |||
8714 | const icUInt16Number *pData) | |||
8715 | { | |||
8716 | switch(nSpace) { | |||
8717 | case icSigRgbData: | |||
8718 | { | |||
8719 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0); | |||
8720 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0); | |||
8721 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0); | |||
8722 | ||||
8723 | return icCmmStatOk; | |||
8724 | } | |||
8725 | case icSigCmykData: | |||
8726 | { | |||
8727 | pInternal[0] = (icFloatNumber)((icFloatNumber)pData[0] / 65535.0); | |||
8728 | pInternal[1] = (icFloatNumber)((icFloatNumber)pData[1] / 65535.0); | |||
8729 | pInternal[2] = (icFloatNumber)((icFloatNumber)pData[2] / 65535.0); | |||
8730 | pInternal[3] = (icFloatNumber)((icFloatNumber)pData[3] / 65535.0); | |||
8731 | return icCmmStatOk; | |||
8732 | } | |||
8733 | default: | |||
8734 | { | |||
8735 | icUInt32Number i; | |||
8736 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | |||
8737 | CIccPixelBuf pFloatPixel(nSamples); | |||
8738 | if (!pFloatPixel.get()) | |||
8739 | return icCmmStatAllocErr; | |||
8740 | ||||
8741 | for(i=0; i<nSamples; i++) { | |||
8742 | pFloatPixel[i] = (icFloatNumber)pData[i]; | |||
8743 | } | |||
8744 | return ToInternalEncoding(nSpace, icEncode16Bit, pInternal, pFloatPixel); | |||
8745 | } | |||
8746 | } | |||
8747 | } | |||
8748 | ||||
8749 | ||||
8750 | /** | |||
8751 | ************************************************************************** | |||
8752 | * Name: CIccCmm::FromInternalEncoding | |||
8753 | * | |||
8754 | * Purpose: | |||
8755 | * Functions for converting from Internal representation of pixel colors. | |||
8756 | * | |||
8757 | * Args: | |||
8758 | * nSpace = color space signature of the data, | |||
8759 | * nEncode = icFloatColorEncoding type of the data, | |||
8760 | * pData = converted data is stored here, | |||
8761 | * pInternal = the data to be converted | |||
8762 | * bClip = flag to clip data to internal range | |||
8763 | ************************************************************************** | |||
8764 | */ | |||
8765 | icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icFloatColorEncoding nEncode, | |||
8766 | icFloatNumber *pData, const icFloatNumber *pInternal, bool bClip) | |||
8767 | { | |||
8768 | int nSamples = icGetSpaceSamples(nSpace); | |||
8769 | if (!nSamples) | |||
8770 | return icCmmStatBadColorEncoding; | |||
8771 | ||||
8772 | icUInt16Number i; | |||
8773 | CIccPixelBuf pInput(nSamples); | |||
8774 | ||||
8775 | if (!pInput.get()) | |||
8776 | return icCmmStatAllocErr; | |||
8777 | ||||
8778 | memcpy(pInput, pInternal, nSamples*sizeof(icFloatNumber)); | |||
8779 | bool bCLRspace = (icIsSpaceCLR(nSpace) || (nSpace == icSigDevLabData((icColorSpaceSignature) 0x644C6162)) || (nSpace==icSigDevXYZData((icColorSpaceSignature) 0x6458595A))); | |||
8780 | ||||
8781 | switch(nSpace) { | |||
8782 | ||||
8783 | case icSigLabData: | |||
8784 | { | |||
8785 | switch(nEncode) { | |||
8786 | case icEncodeValue: | |||
8787 | { | |||
8788 | icLabFromPcs(pInput); | |||
8789 | break; | |||
8790 | } | |||
8791 | case icEncodeUnitFloat: | |||
8792 | case icEncodeFloat: | |||
8793 | { | |||
8794 | break; | |||
8795 | } | |||
8796 | case icEncode8Bit: | |||
8797 | { | |||
8798 | icLabFromPcs(pInput); | |||
8799 | ||||
8800 | pInput[0] = (icUInt8Number)(pInput[0]/100.0 * 255.0 + 0.5); | |||
8801 | pInput[1] = icABtoU8(pInput[1]); | |||
8802 | pInput[2] = icABtoU8(pInput[2]); | |||
8803 | break; | |||
8804 | } | |||
8805 | case icEncode16Bit: | |||
8806 | { | |||
8807 | pInput[0] = icFtoU16(pInput[0]); | |||
8808 | pInput[1] = icFtoU16(pInput[1]); | |||
8809 | pInput[2] = icFtoU16(pInput[2]); | |||
8810 | break; | |||
8811 | } | |||
8812 | case icEncode16BitV2: | |||
8813 | { | |||
8814 | CIccPCS::Lab4ToLab2(pInput, pInput); | |||
8815 | ||||
8816 | pInput[0] = icFtoU16(pInput[0]); | |||
8817 | pInput[1] = icFtoU16(pInput[1]); | |||
8818 | pInput[2] = icFtoU16(pInput[2]); | |||
8819 | break; | |||
8820 | } | |||
8821 | default: | |||
8822 | return icCmmStatBadColorEncoding; | |||
8823 | break; | |||
8824 | } | |||
8825 | break; | |||
8826 | } | |||
8827 | ||||
8828 | case icSigXYZData: | |||
8829 | { | |||
8830 | switch(nEncode) { | |||
8831 | case icEncodeValue: | |||
8832 | { | |||
8833 | icXyzFromPcs(pInput); | |||
8834 | break; | |||
8835 | } | |||
8836 | case icEncodePercent: | |||
8837 | { | |||
8838 | icXyzFromPcs(pInput); | |||
8839 | pInput[0] = (icFloatNumber)(pInput[0] * 100.0); | |||
8840 | pInput[1] = (icFloatNumber)(pInput[1] * 100.0); | |||
8841 | pInput[2] = (icFloatNumber)(pInput[2] * 100.0); | |||
8842 | break; | |||
8843 | } | |||
8844 | case icEncodeFloat: | |||
8845 | case icEncodeUnitFloat: | |||
8846 | { | |||
8847 | icXyzFromPcs(pInput); | |||
8848 | break; | |||
8849 | } | |||
8850 | ||||
8851 | case icEncode16Bit: | |||
8852 | case icEncode16BitV2: | |||
8853 | { | |||
8854 | icXyzFromPcs(pInput); | |||
8855 | pInput[0] = icDtoUSF(pInput[0]); | |||
8856 | pInput[1] = icDtoUSF(pInput[1]); | |||
8857 | pInput[2] = icDtoUSF(pInput[2]); | |||
8858 | break; | |||
8859 | } | |||
8860 | ||||
8861 | default: | |||
8862 | return icCmmStatBadColorEncoding; | |||
8863 | break; | |||
8864 | } | |||
8865 | break; | |||
8866 | } | |||
8867 | ||||
8868 | case icSigNamedData: | |||
8869 | return icCmmStatBadColorEncoding; | |||
8870 | ||||
8871 | default: | |||
8872 | { | |||
8873 | switch(nEncode) { | |||
8874 | case icEncodeValue: | |||
8875 | { | |||
8876 | if (nSpace == icSigDevXYZData((icColorSpaceSignature) 0x6458595A)) { | |||
8877 | icXyzFromPcs(pInput); | |||
8878 | } | |||
8879 | else if (bCLRspace && nSamples >=3) { | |||
8880 | icLabFromPcs(pInput); | |||
8881 | } | |||
8882 | break; | |||
8883 | } | |||
8884 | case icEncodePercent: | |||
8885 | { | |||
8886 | if (bClip) { | |||
8887 | for(i=0; i<nSamples; i++) { | |||
8888 | if (pInput[i] < 0.0) pInput[i] = 0.0; | |||
8889 | if (pInput[i] > 1.0) pInput[i] = 1.0; | |||
8890 | pInput[i] = (icFloatNumber)(pInput[i]*100.0); | |||
8891 | } | |||
8892 | } | |||
8893 | else { | |||
8894 | for(i=0; i<nSamples; i++) { | |||
8895 | pInput[i] = (icFloatNumber)(pInput[i]*100.0); | |||
8896 | } | |||
8897 | } | |||
8898 | break; | |||
8899 | } | |||
8900 | ||||
8901 | case icEncodeFloat: | |||
8902 | break; | |||
8903 | ||||
8904 | case icEncodeUnitFloat: | |||
8905 | { | |||
8906 | if (bClip) { | |||
8907 | for(i=0; i<nSamples; i++) { | |||
8908 | if (pInput[i] < 0.0) pInput[i] = 0.0; | |||
8909 | if (pInput[i] > 1.0) pInput[i] = 1.0; | |||
8910 | } | |||
8911 | } | |||
8912 | break; | |||
8913 | } | |||
8914 | ||||
8915 | case icEncode8Bit: | |||
8916 | { | |||
8917 | for(i=0; i<nSamples; i++) { | |||
8918 | pInput[i] = icFtoU8(pInput[i]); | |||
8919 | } | |||
8920 | break; | |||
8921 | } | |||
8922 | ||||
8923 | case icEncode16Bit: | |||
8924 | case icEncode16BitV2: | |||
8925 | { | |||
8926 | for(i=0; i<nSamples; i++) { | |||
8927 | pInput[i] = icFtoU16(pInput[i]); | |||
8928 | } | |||
8929 | break; | |||
8930 | } | |||
8931 | ||||
8932 | default: | |||
8933 | return icCmmStatBadColorEncoding; | |||
8934 | break; | |||
8935 | } | |||
8936 | break; | |||
8937 | } | |||
8938 | } | |||
8939 | ||||
8940 | memcpy(pData, pInput, nSamples*sizeof(icFloatNumber)); | |||
8941 | return icCmmStatOk; | |||
8942 | } | |||
8943 | ||||
8944 | ||||
8945 | /** | |||
8946 | ************************************************************************** | |||
8947 | * Name: CIccCmm::FromInternalEncoding | |||
8948 | * | |||
8949 | * Purpose: | |||
8950 | * Functions for converting from Internal representation of 8 bit pixel colors. | |||
8951 | * | |||
8952 | * Args: | |||
8953 | * nSpace = color space signature of the data, | |||
8954 | * nEncode = icFloatColorEncoding type of the data, | |||
8955 | * pData = converted data is stored here, | |||
8956 | * pInternal = the data to be converted | |||
8957 | * bClip = flag to clip data to internal range | |||
8958 | ************************************************************************** | |||
8959 | */ | |||
8960 | icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt8Number *pData, | |||
8961 | const icFloatNumber *pInternal) | |||
8962 | { | |||
8963 | switch(nSpace) { | |||
8964 | case icSigRgbData: | |||
8965 | { | |||
8966 | pData[0] = icFtoU8(pInternal[0]); | |||
8967 | pData[1] = icFtoU8(pInternal[1]); | |||
8968 | pData[2] = icFtoU8(pInternal[2]); | |||
8969 | ||||
8970 | return icCmmStatOk; | |||
8971 | } | |||
8972 | case icSigCmykData: | |||
8973 | { | |||
8974 | pData[0] = icFtoU8(pInternal[0]); | |||
8975 | pData[1] = icFtoU8(pInternal[1]); | |||
8976 | pData[2] = icFtoU8(pInternal[2]); | |||
8977 | pData[3] = icFtoU8(pInternal[3]); | |||
8978 | ||||
8979 | return icCmmStatOk; | |||
8980 | } | |||
8981 | default: | |||
8982 | { | |||
8983 | icUInt32Number i; | |||
8984 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | |||
8985 | ||||
8986 | CIccPixelBuf pFloatPixel(nSamples); | |||
8987 | icStatusCMM convertStat; | |||
8988 | ||||
8989 | if (!pFloatPixel.get()) | |||
8990 | return icCmmStatAllocErr; | |||
8991 | ||||
8992 | convertStat = FromInternalEncoding(nSpace, icEncode8Bit, pFloatPixel, pInternal); | |||
8993 | if (convertStat) | |||
8994 | return convertStat; | |||
8995 | for(i=0; i<nSamples; i++) { | |||
8996 | pData[i] = (icUInt8Number)(pFloatPixel[i] + 0.5); | |||
8997 | } | |||
8998 | ||||
8999 | return icCmmStatOk; | |||
9000 | } | |||
9001 | } | |||
9002 | } | |||
9003 | ||||
9004 | ||||
9005 | /** | |||
9006 | ************************************************************************** | |||
9007 | * Name: CIccCmm::FromInternalEncoding | |||
9008 | * | |||
9009 | * Purpose: | |||
9010 | * Functions for converting from Internal representation of 16 bit pixel colors. | |||
9011 | * | |||
9012 | * Args: | |||
9013 | * nSpace = color space signature of the data, | |||
9014 | * nEncode = icFloatColorEncoding type of the data, | |||
9015 | * pData = converted data is stored here, | |||
9016 | * pInternal = the data to be converted | |||
9017 | * bClip = flag to clip data to internal range | |||
9018 | ************************************************************************** | |||
9019 | */ | |||
9020 | icStatusCMM CIccCmm::FromInternalEncoding(icColorSpaceSignature nSpace, icUInt16Number *pData, | |||
9021 | const icFloatNumber *pInternal) | |||
9022 | { | |||
9023 | switch(nSpace) { | |||
9024 | case icSigRgbData: | |||
9025 | { | |||
9026 | pData[0] = icFtoU16(pInternal[0]); | |||
9027 | pData[1] = icFtoU16(pInternal[1]); | |||
9028 | pData[2] = icFtoU16(pInternal[2]); | |||
9029 | ||||
9030 | return icCmmStatOk; | |||
9031 | } | |||
9032 | case icSigCmykData: | |||
9033 | { | |||
9034 | pData[0] = icFtoU16(pInternal[0]); | |||
9035 | pData[1] = icFtoU16(pInternal[1]); | |||
9036 | pData[2] = icFtoU16(pInternal[2]); | |||
9037 | pData[3] = icFtoU16(pInternal[3]); | |||
9038 | ||||
9039 | return icCmmStatOk; | |||
9040 | } | |||
9041 | default: | |||
9042 | { | |||
9043 | icUInt32Number i; | |||
9044 | icUInt32Number nSamples = icGetSpaceSamples(nSpace); | |||
9045 | CIccPixelBuf pFloatPixel(nSamples); | |||
9046 | icStatusCMM convertStat; | |||
9047 | ||||
9048 | if (!pFloatPixel.get()) | |||
9049 | return icCmmStatAllocErr; | |||
9050 | ||||
9051 | convertStat = FromInternalEncoding(nSpace, icEncode16Bit, pFloatPixel, pInternal); | |||
9052 | if (convertStat) | |||
9053 | return convertStat; | |||
9054 | for(i=0; i<nSamples; i++) { | |||
9055 | pData[i] = (icUInt16Number)(pFloatPixel[i] + 0.5); | |||
9056 | } | |||
9057 | ||||
9058 | return icCmmStatOk; | |||
9059 | } | |||
9060 | } | |||
9061 | } | |||
9062 | ||||
9063 | ||||
9064 | /** | |||
9065 | ************************************************************************** | |||
9066 | * Name: CIccCmm::GetFloatColorEncoding | |||
9067 | * | |||
9068 | * Purpose: | |||
9069 | * Converts the encoding type to characters for printing | |||
9070 | * | |||
9071 | * Args: | |||
9072 | * val = encoding type | |||
9073 | * | |||
9074 | * Return: | |||
9075 | * characters for printing | |||
9076 | ************************************************************************** | |||
9077 | */ | |||
9078 | const icChar* CIccCmm::GetFloatColorEncoding(icFloatColorEncoding val) | |||
9079 | { | |||
9080 | switch(val) { | |||
9081 | ||||
9082 | case icEncodeValue: | |||
9083 | return "icEncodeValue"; | |||
9084 | ||||
9085 | case icEncodeFloat: | |||
9086 | return "icEncodeFloat"; | |||
9087 | ||||
9088 | case icEncodeUnitFloat: | |||
9089 | return "icEncodeUnitFloat"; | |||
9090 | ||||
9091 | case icEncodePercent: | |||
9092 | return "icEncodePercent"; | |||
9093 | ||||
9094 | case icEncode8Bit: | |||
9095 | return "icEncode8Bit"; | |||
9096 | ||||
9097 | case icEncode16Bit: | |||
9098 | return "icEncode16Bit"; | |||
9099 | ||||
9100 | case icEncode16BitV2: | |||
9101 | return "icEncode16BitV2"; | |||
9102 | ||||
9103 | default: | |||
9104 | return "icEncodeUnknown"; | |||
9105 | } | |||
9106 | } | |||
9107 | ||||
9108 | /** | |||
9109 | ************************************************************************** | |||
9110 | * Name: CIccCmm::GetFloatColorEncoding | |||
9111 | * | |||
9112 | * Purpose: | |||
9113 | * Converts the string containing encoding type to icFloatColorEncoding | |||
9114 | * | |||
9115 | * Args: | |||
9116 | * val = string containing encoding type | |||
9117 | * | |||
9118 | * Return: | |||
9119 | * encoding type | |||
9120 | ************************************************************************** | |||
9121 | */ | |||
9122 | icFloatColorEncoding CIccCmm::GetFloatColorEncoding(const icChar* val) | |||
9123 | { | |||
9124 | if (!stricmpstrcasecmp(val, "icEncodePercent")) { | |||
9125 | return icEncodePercent; | |||
9126 | } | |||
9127 | else if (!stricmpstrcasecmp(val, "icEncodeUnitFloat")) { | |||
9128 | return icEncodeUnitFloat; | |||
9129 | } | |||
9130 | else if (!stricmpstrcasecmp(val, "icEncodeFloat")) { | |||
9131 | return icEncodeFloat; | |||
9132 | } | |||
9133 | else if (!stricmpstrcasecmp(val, "icEncode8Bit")) { | |||
9134 | return icEncode8Bit; | |||
9135 | } | |||
9136 | else if (!stricmpstrcasecmp(val, "icEncode16Bit")) { | |||
9137 | return icEncode16Bit; | |||
9138 | } | |||
9139 | else if (!stricmpstrcasecmp(val, "icEncode16BitV2")) { | |||
9140 | return icEncode16BitV2; | |||
9141 | } | |||
9142 | else if (!stricmpstrcasecmp(val, "icEncodeValue")) { | |||
9143 | return icEncodeValue; | |||
9144 | } | |||
9145 | else { | |||
9146 | return icEncodeUnknown; | |||
9147 | } | |||
9148 | ||||
9149 | } | |||
9150 | ||||
9151 | /** | |||
9152 | ************************************************************************** | |||
9153 | * Name: CIccCmm::GetNumXforms | |||
9154 | * | |||
9155 | * Purpose: | |||
9156 | * Get number of xforms in the xform list | |||
9157 | * | |||
9158 | * Return: | |||
9159 | * number of m_Xforms | |||
9160 | ************************************************************************** | |||
9161 | */ | |||
9162 | icUInt32Number CIccCmm::GetNumXforms() const | |||
9163 | { | |||
9164 | return (icUInt32Number)m_Xforms->size(); | |||
9165 | } | |||
9166 | ||||
9167 | ||||
9168 | /** | |||
9169 | ************************************************************************** | |||
9170 | * Name: CIccCmm::GetFirstXformSource | |||
9171 | * | |||
9172 | * Purpose: | |||
9173 | * Get source colorspace of first transform (similar to m_nSrcSpace with differences in dev colorimetric spaces) | |||
9174 | * | |||
9175 | * Return: | |||
9176 | * colorspace | |||
9177 | ************************************************************************** | |||
9178 | */ | |||
9179 | icColorSpaceSignature CIccCmm::GetFirstXformSource() | |||
9180 | { | |||
9181 | if (!m_Xforms->size()) | |||
9182 | return m_nSrcSpace; | |||
9183 | ||||
9184 | return m_Xforms->begin()->ptr->GetSrcSpace(); | |||
9185 | } | |||
9186 | ||||
9187 | /** | |||
9188 | ************************************************************************** | |||
9189 | * Name: CIccCmm::GetNumXforms | |||
9190 | * | |||
9191 | * Purpose: | |||
9192 | * Get source colorspace of last transform (similar to m_nSrcSpace with differences in dev colorimetric spaces) | |||
9193 | * | |||
9194 | * Return: | |||
9195 | * colorspace | |||
9196 | ************************************************************************** | |||
9197 | */ | |||
9198 | icColorSpaceSignature CIccCmm::GetLastXformDest() | |||
9199 | { | |||
9200 | if (!m_Xforms->size()) | |||
9201 | return m_nDestSpace; | |||
9202 | ||||
9203 | return m_Xforms->rbegin()->ptr->GetDstSpace(); | |||
9204 | } | |||
9205 | ||||
9206 | /** | |||
9207 | ************************************************************************** | |||
9208 | * Name: CIccApplyCmm::CIccApplyCmm | |||
9209 | * | |||
9210 | * Purpose: | |||
9211 | * Constructor | |||
9212 | * | |||
9213 | * Args: | |||
9214 | * pCmm = ptr to CMM to apply against | |||
9215 | ************************************************************************** | |||
9216 | */ | |||
9217 | CIccApplyNamedColorCmm::CIccApplyNamedColorCmm(CIccNamedColorCmm *pCmm) : CIccApplyCmm(pCmm) | |||
9218 | { | |||
9219 | } | |||
9220 | ||||
9221 | ||||
9222 | /** | |||
9223 | ************************************************************************** | |||
9224 | * Name: CIccApplyCmm::CIccApplyCmm | |||
9225 | * | |||
9226 | * Purpose: | |||
9227 | * Destructor | |||
9228 | ************************************************************************** | |||
9229 | */ | |||
9230 | CIccApplyNamedColorCmm::~CIccApplyNamedColorCmm() | |||
9231 | { | |||
9232 | } | |||
9233 | ||||
9234 | ||||
9235 | /** | |||
9236 | ************************************************************************** | |||
9237 | * Name: CIccApplyNamedColorCmm::Apply | |||
9238 | * | |||
9239 | * Purpose: | |||
9240 | * Does the actual application of the Xforms in the list. | |||
9241 | * | |||
9242 | * Args: | |||
9243 | * DstPixel = Destination pixel where the result is stored, | |||
9244 | * SrcPixel = Source pixel which is to be applied. | |||
9245 | ************************************************************************** | |||
9246 | */ | |||
9247 | icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | |||
9248 | { | |||
9249 | icFloatNumber *pDst, *pTmp; | |||
9250 | const icFloatNumber *pSrc; | |||
9251 | CIccApplyXformList::iterator i; | |||
9252 | int j, n = (int)m_Xforms->size(); | |||
9253 | CIccApplyXform *pApply; | |||
9254 | const CIccXform *pApplyXform; | |||
9255 | CIccXformNamedColor *pXform; | |||
9256 | ||||
9257 | if (!n) | |||
9258 | return icCmmStatBadXform; | |||
9259 | ||||
9260 | if (!m_Pixel && !InitPixel()) { | |||
9261 | return icCmmStatAllocErr; | |||
9262 | } | |||
9263 | ||||
9264 | icChar NamedColor[256]; | |||
9265 | icStatusCMM rv; | |||
9266 | ||||
9267 | m_pPCS->Reset(m_pCmm->GetSourceSpace()); | |||
9268 | ||||
9269 | pSrc = SrcPixel; | |||
9270 | pDst = m_Pixel; | |||
9271 | ||||
9272 | if (n>1) { | |||
9273 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | |||
9274 | ||||
9275 | pApply = i->ptr; | |||
9276 | pApplyXform = pApply->GetXform(); | |||
9277 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9278 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9279 | ||||
9280 | switch(pXform->GetInterface()) { | |||
9281 | case icApplyPixel2Pixel: | |||
9282 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | |||
9283 | break; | |||
9284 | ||||
9285 | case icApplyPixel2Named: | |||
9286 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | |||
9287 | break; | |||
9288 | ||||
9289 | case icApplyNamed2Pixel: | |||
9290 | if (j==0) { | |||
9291 | return icCmmStatIncorrectApply; | |||
9292 | } | |||
9293 | ||||
9294 | rv = pXform->Apply(pApply, pDst, NamedColor); | |||
9295 | ||||
9296 | if (rv) { | |||
9297 | return rv; | |||
9298 | } | |||
9299 | break; | |||
9300 | ||||
9301 | default: | |||
9302 | break; | |||
9303 | } | |||
9304 | } | |||
9305 | else { | |||
9306 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | |||
9307 | } | |||
9308 | pTmp = (icFloatNumber*)pSrc; | |||
9309 | pSrc = pDst; | |||
9310 | if (pTmp==SrcPixel) | |||
9311 | pDst = m_Pixel2; | |||
9312 | else | |||
9313 | pDst = pTmp; | |||
9314 | } | |||
9315 | ||||
9316 | pApply = i->ptr; | |||
9317 | pApplyXform = pApply->GetXform(); | |||
9318 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9319 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9320 | ||||
9321 | switch(pXform->GetInterface()) { | |||
9322 | case icApplyPixel2Pixel: | |||
9323 | pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); | |||
9324 | break; | |||
9325 | ||||
9326 | case icApplyPixel2Named: | |||
9327 | default: | |||
9328 | return icCmmStatIncorrectApply; | |||
9329 | break; | |||
9330 | ||||
9331 | case icApplyNamed2Pixel: | |||
9332 | rv = pXform->Apply(pApply, DstPixel, NamedColor); | |||
9333 | if (rv) { | |||
9334 | return rv; | |||
9335 | } | |||
9336 | break; | |||
9337 | ||||
9338 | } | |||
9339 | } | |||
9340 | else { | |||
9341 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | |||
9342 | } | |||
9343 | ||||
9344 | } | |||
9345 | else if (n==1) { | |||
9346 | i = m_Xforms->begin(); | |||
9347 | ||||
9348 | pApply = i->ptr; | |||
9349 | pApplyXform = pApply->GetXform(); | |||
9350 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9351 | return icCmmStatIncorrectApply; | |||
9352 | } | |||
9353 | ||||
9354 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | |||
9355 | } | |||
9356 | ||||
9357 | m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace(), true); | |||
9358 | ||||
9359 | return icCmmStatOk; | |||
9360 | } | |||
9361 | ||||
9362 | ||||
9363 | /** | |||
9364 | ************************************************************************** | |||
9365 | * Name: CIccApplyNamedColorCmm::Apply | |||
9366 | * | |||
9367 | * Purpose: | |||
9368 | * Does the actual application of the Xforms in the list. | |||
9369 | * | |||
9370 | * Args: | |||
9371 | * DstPixel = Destination pixel where the result is stored, | |||
9372 | * SrcPixel = Source pixel which is to be applied. | |||
9373 | ************************************************************************** | |||
9374 | */ | |||
9375 | icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | |||
9376 | { | |||
9377 | icFloatNumber *pDst; | |||
9378 | const icFloatNumber *pSrc; | |||
9379 | CIccApplyXformList::iterator i; | |||
9380 | int j, n = (int)m_Xforms->size(); | |||
9381 | CIccApplyXform *pApply; | |||
9382 | const CIccXform *pApplyXform; | |||
9383 | CIccXformNamedColor *pXform; | |||
9384 | icUInt32Number k; | |||
9385 | ||||
9386 | if (!n) | |||
9387 | return icCmmStatBadXform; | |||
9388 | ||||
9389 | if (!m_Pixel && !InitPixel()) { | |||
9390 | return icCmmStatAllocErr; | |||
9391 | } | |||
9392 | ||||
9393 | icChar NamedColor[255]; | |||
9394 | icStatusCMM rv; | |||
9395 | ||||
9396 | for (k=0; k<nPixels; k++) { | |||
9397 | m_pPCS->Reset(m_pCmm->GetSourceSpace()); | |||
9398 | ||||
9399 | pSrc = SrcPixel; | |||
9400 | pDst = m_Pixel; | |||
9401 | ||||
9402 | if (n>1) { | |||
9403 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | |||
9404 | ||||
9405 | pApply = i->ptr; | |||
9406 | pApplyXform = pApply->GetXform(); | |||
9407 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9408 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9409 | ||||
9410 | switch(pXform->GetInterface()) { | |||
9411 | case icApplyPixel2Pixel: | |||
9412 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | |||
9413 | break; | |||
9414 | ||||
9415 | case icApplyPixel2Named: | |||
9416 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | |||
9417 | break; | |||
9418 | ||||
9419 | case icApplyNamed2Pixel: | |||
9420 | if (j==0) { | |||
9421 | return icCmmStatIncorrectApply; | |||
9422 | } | |||
9423 | ||||
9424 | rv = pXform->Apply(pApply, pDst, NamedColor); | |||
9425 | ||||
9426 | if (rv) { | |||
9427 | return rv; | |||
9428 | } | |||
9429 | break; | |||
9430 | ||||
9431 | default: | |||
9432 | break; | |||
9433 | } | |||
9434 | } | |||
9435 | else { | |||
9436 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | |||
9437 | } | |||
9438 | pSrc = pDst; | |||
9439 | } | |||
9440 | ||||
9441 | pApply = i->ptr; | |||
9442 | pApplyXform = pApply->GetXform(); | |||
9443 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9444 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9445 | ||||
9446 | switch(pXform->GetInterface()) { | |||
9447 | case icApplyPixel2Pixel: | |||
9448 | pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); | |||
9449 | break; | |||
9450 | ||||
9451 | case icApplyPixel2Named: | |||
9452 | default: | |||
9453 | return icCmmStatIncorrectApply; | |||
9454 | break; | |||
9455 | ||||
9456 | case icApplyNamed2Pixel: | |||
9457 | rv = pXform->Apply(pApply, DstPixel, NamedColor); | |||
9458 | if (rv) { | |||
9459 | return rv; | |||
9460 | } | |||
9461 | break; | |||
9462 | ||||
9463 | } | |||
9464 | } | |||
9465 | else { | |||
9466 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | |||
9467 | } | |||
9468 | ||||
9469 | } | |||
9470 | else if (n==1) { | |||
9471 | i = m_Xforms->begin(); | |||
9472 | ||||
9473 | pApply = i->ptr; | |||
9474 | pApplyXform = pApply->GetXform(); | |||
9475 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9476 | return icCmmStatIncorrectApply; | |||
9477 | } | |||
9478 | ||||
9479 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | |||
9480 | } | |||
9481 | ||||
9482 | m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace()); | |||
9483 | ||||
9484 | SrcPixel += m_pCmm->GetSourceSamples(); | |||
9485 | DstPixel += m_pCmm->GetDestSamples(); | |||
9486 | } | |||
9487 | ||||
9488 | return icCmmStatOk; | |||
9489 | } | |||
9490 | ||||
9491 | ||||
9492 | /** | |||
9493 | ************************************************************************** | |||
9494 | * Name: CIccApplyNamedColorCmm::Apply | |||
9495 | * | |||
9496 | * Purpose: | |||
9497 | * Does the actual application of the Xforms in the list. | |||
9498 | * | |||
9499 | * Args: | |||
9500 | * DstColorName = Destination string where the result is stored, | |||
9501 | * SrcPixel = Source pixel which is to be applied. | |||
9502 | ************************************************************************** | |||
9503 | */ | |||
9504 | icStatusCMM CIccApplyNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel) | |||
9505 | { | |||
9506 | icFloatNumber *pDst, *pTmp; | |||
9507 | const icFloatNumber *pSrc; | |||
9508 | CIccApplyXformList::iterator i; | |||
9509 | int j, n = (int)m_Xforms->size(); | |||
9510 | CIccApplyXform *pApply; | |||
9511 | const CIccXform *pApplyXform; | |||
9512 | CIccXformNamedColor *pXform; | |||
9513 | ||||
9514 | if (!n) | |||
9515 | return icCmmStatBadXform; | |||
9516 | ||||
9517 | if (!m_Pixel && !InitPixel()) { | |||
9518 | return icCmmStatAllocErr; | |||
9519 | } | |||
9520 | ||||
9521 | icChar NamedColor[256]; | |||
9522 | icStatusCMM rv; | |||
9523 | ||||
9524 | m_pPCS->Reset(m_pCmm->GetSourceSpace()); | |||
9525 | ||||
9526 | pSrc = SrcPixel; | |||
9527 | pDst = m_Pixel; | |||
9528 | ||||
9529 | if (n>1) { | |||
9530 | for (j=0, i=m_Xforms->begin(); j<n-1 && i!=m_Xforms->end(); i++, j++) { | |||
9531 | ||||
9532 | pApply = i->ptr; | |||
9533 | pApplyXform = pApply->GetXform(); | |||
9534 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9535 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9536 | switch(pXform->GetInterface()) { | |||
9537 | case icApplyPixel2Pixel: | |||
9538 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | |||
9539 | break; | |||
9540 | ||||
9541 | case icApplyPixel2Named: | |||
9542 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | |||
9543 | break; | |||
9544 | ||||
9545 | case icApplyNamed2Pixel: | |||
9546 | if (j==0) { | |||
9547 | return icCmmStatIncorrectApply; | |||
9548 | } | |||
9549 | rv = pXform->Apply(pApply, pDst, NamedColor); | |||
9550 | if (rv) { | |||
9551 | return rv; | |||
9552 | } | |||
9553 | break; | |||
9554 | ||||
9555 | default: | |||
9556 | break; | |||
9557 | } | |||
9558 | } | |||
9559 | else { | |||
9560 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | |||
9561 | } | |||
9562 | pTmp = (icFloatNumber*)pSrc; | |||
9563 | pSrc = pDst; | |||
9564 | if (pTmp==SrcPixel) | |||
9565 | pDst = m_Pixel2; | |||
9566 | else | |||
9567 | pDst = pTmp; | |||
9568 | } | |||
9569 | ||||
9570 | pApply = i->ptr; | |||
9571 | pApplyXform = pApply->GetXform(); | |||
9572 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9573 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9574 | switch(pXform->GetInterface()) { | |||
9575 | ||||
9576 | case icApplyPixel2Named: | |||
9577 | pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); | |||
9578 | break; | |||
9579 | ||||
9580 | case icApplyPixel2Pixel: | |||
9581 | case icApplyNamed2Pixel: | |||
9582 | default: | |||
9583 | return icCmmStatIncorrectApply; | |||
9584 | break; | |||
9585 | } | |||
9586 | } | |||
9587 | else { | |||
9588 | return icCmmStatIncorrectApply; | |||
9589 | } | |||
9590 | ||||
9591 | } | |||
9592 | else if (n==1) { | |||
9593 | i = m_Xforms->begin(); | |||
9594 | pApply = i->ptr; | |||
9595 | pApplyXform = pApply->GetXform(); | |||
9596 | if (pApplyXform->GetXformType()!=icXformTypeNamedColor) { | |||
9597 | return icCmmStatIncorrectApply; | |||
9598 | } | |||
9599 | ||||
9600 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9601 | pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); | |||
9602 | } | |||
9603 | ||||
9604 | return icCmmStatOk; | |||
9605 | } | |||
9606 | ||||
9607 | ||||
9608 | /** | |||
9609 | ************************************************************************** | |||
9610 | * Name: CIccApplyNamedColorCmm::Apply | |||
9611 | * | |||
9612 | * Purpose: | |||
9613 | * Does the actual application of the Xforms in the list. | |||
9614 | * | |||
9615 | * Args: | |||
9616 | * DstPixel = Destination pixel where the result is stored, | |||
9617 | * SrcColorName = Source color name which is to be searched. | |||
9618 | ************************************************************************** | |||
9619 | */ | |||
9620 | icStatusCMM CIccApplyNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | |||
9621 | { | |||
9622 | icFloatNumber *pDst, *pTmp; | |||
9623 | const icFloatNumber *pSrc; | |||
9624 | CIccApplyXformList::iterator i; | |||
9625 | int j, n = (int)m_Xforms->size(); | |||
9626 | CIccApplyXform *pApply; | |||
9627 | const CIccXform *pApplyXform; | |||
9628 | CIccXformNamedColor *pXform; | |||
9629 | ||||
9630 | if (!n) | |||
9631 | return icCmmStatBadXform; | |||
9632 | ||||
9633 | if (!m_Pixel && !InitPixel()) { | |||
9634 | return icCmmStatAllocErr; | |||
9635 | } | |||
9636 | ||||
9637 | icChar NamedColor[255]; | |||
9638 | icStatusCMM rv; | |||
9639 | ||||
9640 | i=m_Xforms->begin(); | |||
9641 | pApply = i->ptr; | |||
9642 | pApplyXform = pApply->GetXform(); | |||
9643 | if (pApplyXform->GetXformType()!=icXformTypeNamedColor) | |||
9644 | return icCmmStatIncorrectApply; | |||
9645 | ||||
9646 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9647 | m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS()); | |||
9648 | ||||
9649 | pDst = m_Pixel; | |||
9650 | ||||
9651 | if (n>1) { | |||
9652 | rv = pXform->Apply(pApply, pDst, SrcColorName, tint); | |||
9653 | if (rv) { | |||
9654 | return rv; | |||
9655 | } | |||
9656 | ||||
9657 | pSrc = pDst; | |||
9658 | pDst = m_Pixel2; | |||
9659 | ||||
9660 | for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) { | |||
9661 | ||||
9662 | pApply = i->ptr; | |||
9663 | pApplyXform = pApply->GetXform(); | |||
9664 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9665 | CIccXformNamedColor *pXform = (CIccXformNamedColor*)pApplyXform; | |||
9666 | switch(pXform->GetInterface()) { | |||
9667 | case icApplyPixel2Pixel: | |||
9668 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | |||
9669 | break; | |||
9670 | ||||
9671 | case icApplyPixel2Named: | |||
9672 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | |||
9673 | break; | |||
9674 | ||||
9675 | case icApplyNamed2Pixel: | |||
9676 | rv = pXform->Apply(pApply, pDst, NamedColor); | |||
9677 | if (rv) { | |||
9678 | return rv; | |||
9679 | } | |||
9680 | break; | |||
9681 | ||||
9682 | default: | |||
9683 | break; | |||
9684 | } | |||
9685 | } | |||
9686 | else { | |||
9687 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pApplyXform)); | |||
9688 | } | |||
9689 | pTmp = (icFloatNumber*)pSrc; | |||
9690 | pSrc = pDst; | |||
9691 | pDst = pTmp; | |||
9692 | } | |||
9693 | ||||
9694 | pApply = i->ptr; | |||
9695 | pApplyXform = pApply->GetXform(); | |||
9696 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9697 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9698 | switch(pXform->GetInterface()) { | |||
9699 | case icApplyPixel2Pixel: | |||
9700 | pXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pXform)); | |||
9701 | break; | |||
9702 | ||||
9703 | case icApplyPixel2Named: | |||
9704 | default: | |||
9705 | return icCmmStatIncorrectApply; | |||
9706 | break; | |||
9707 | ||||
9708 | case icApplyNamed2Pixel: | |||
9709 | rv = pXform->Apply(pApply, DstPixel, NamedColor); | |||
9710 | if (rv) { | |||
9711 | return rv; | |||
9712 | } | |||
9713 | break; | |||
9714 | ||||
9715 | } | |||
9716 | } | |||
9717 | else { | |||
9718 | pApplyXform->Apply(pApply, DstPixel, m_pPCS->Check(pSrc, pApplyXform)); | |||
9719 | } | |||
9720 | ||||
9721 | } | |||
9722 | else if (n==1) { | |||
9723 | rv = pXform->Apply(pApply, DstPixel, SrcColorName, tint); | |||
9724 | if (rv) { | |||
9725 | return rv; | |||
9726 | } | |||
9727 | m_pPCS->Check(DstPixel, pXform); | |||
9728 | } | |||
9729 | ||||
9730 | m_pPCS->CheckLast(DstPixel, m_pCmm->GetDestSpace()); | |||
9731 | ||||
9732 | return icCmmStatOk; | |||
9733 | } | |||
9734 | ||||
9735 | /** | |||
9736 | ************************************************************************** | |||
9737 | * Name: CIccApplyNamedColorCmm::Apply | |||
9738 | * | |||
9739 | * Purpose: | |||
9740 | * Does the actual application of the Xforms in the list. | |||
9741 | * | |||
9742 | * Args: | |||
9743 | * DstColorName = Destination string where the result is stored, | |||
9744 | * SrcColorName = Source color name which is to be searched. | |||
9745 | ************************************************************************** | |||
9746 | */ | |||
9747 | icStatusCMM CIccApplyNamedColorCmm::Apply(icChar *DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | |||
9748 | { | |||
9749 | icFloatNumber *pDst, *pTmp; | |||
9750 | const icFloatNumber *pSrc; | |||
9751 | CIccApplyXformList::iterator i; | |||
9752 | int j, n = (int)m_Xforms->size(); | |||
9753 | icChar NamedColor[256]; | |||
9754 | icStatusCMM rv; | |||
9755 | CIccApplyXform *pApply; | |||
9756 | const CIccXform *pApplyXform; | |||
9757 | CIccXformNamedColor *pXform; | |||
9758 | ||||
9759 | if (!n) | |||
9760 | return icCmmStatBadXform; | |||
9761 | ||||
9762 | if (!m_Pixel && !InitPixel()) { | |||
9763 | return icCmmStatAllocErr; | |||
9764 | } | |||
9765 | ||||
9766 | i=m_Xforms->begin(); | |||
9767 | ||||
9768 | pApply = i->ptr; | |||
9769 | pApplyXform = pApply->GetXform(); | |||
9770 | if (pApplyXform->GetXformType()!=icXformTypeNamedColor) | |||
9771 | return icCmmStatIncorrectApply; | |||
9772 | ||||
9773 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9774 | ||||
9775 | m_pPCS->Reset(pXform->GetSrcSpace(), pXform->UseLegacyPCS()); | |||
9776 | ||||
9777 | pDst = m_Pixel; | |||
9778 | ||||
9779 | if (n>1) { | |||
9780 | rv = pXform->Apply(pApply, pDst, SrcColorName, tint); | |||
9781 | ||||
9782 | if (rv) { | |||
9783 | return rv; | |||
9784 | } | |||
9785 | ||||
9786 | pSrc = pDst; | |||
9787 | pDst = m_Pixel2; | |||
9788 | ||||
9789 | for (j=0, i++; j<n-2 && i!=m_Xforms->end(); i++, j++) { | |||
9790 | ||||
9791 | pApply = i->ptr; | |||
9792 | pApplyXform = pApply->GetXform(); | |||
9793 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9794 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9795 | switch(pXform->GetInterface()) { | |||
9796 | case icApplyPixel2Pixel: | |||
9797 | pXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | |||
9798 | break; | |||
9799 | ||||
9800 | ||||
9801 | case icApplyPixel2Named: | |||
9802 | pXform->Apply(pApply, NamedColor, m_pPCS->Check(pSrc, pXform)); | |||
9803 | break; | |||
9804 | ||||
9805 | case icApplyNamed2Pixel: | |||
9806 | rv = pXform->Apply(pApply, pDst, NamedColor); | |||
9807 | if (rv) { | |||
9808 | return rv; | |||
9809 | } | |||
9810 | break; | |||
9811 | ||||
9812 | default: | |||
9813 | break; | |||
9814 | } | |||
9815 | } | |||
9816 | else { | |||
9817 | pApplyXform->Apply(pApply, pDst, m_pPCS->Check(pSrc, pXform)); | |||
9818 | } | |||
9819 | pTmp = (icFloatNumber*)pSrc; | |||
9820 | pSrc = pDst; | |||
9821 | pDst = pTmp; | |||
9822 | } | |||
9823 | ||||
9824 | pApply = i->ptr; | |||
9825 | pApplyXform = pApply->GetXform(); | |||
9826 | if (pApplyXform->GetXformType()==icXformTypeNamedColor) { | |||
9827 | pXform = (CIccXformNamedColor*)pApplyXform; | |||
9828 | switch(pXform->GetInterface()) { | |||
9829 | case icApplyPixel2Named: | |||
9830 | pXform->Apply(pApply, DstColorName, m_pPCS->Check(pSrc, pXform)); | |||
9831 | break; | |||
9832 | ||||
9833 | case icApplyPixel2Pixel: | |||
9834 | case icApplyNamed2Pixel: | |||
9835 | default: | |||
9836 | return icCmmStatIncorrectApply; | |||
9837 | break; | |||
9838 | } | |||
9839 | } | |||
9840 | else { | |||
9841 | return icCmmStatIncorrectApply; | |||
9842 | } | |||
9843 | ||||
9844 | } | |||
9845 | else if (n==1) { | |||
9846 | return icCmmStatIncorrectApply; | |||
9847 | } | |||
9848 | ||||
9849 | return icCmmStatOk; | |||
9850 | } | |||
9851 | ||||
9852 | /** | |||
9853 | ************************************************************************** | |||
9854 | * Name: CIccNamedColorCmm::CIccNamedColorCmm | |||
9855 | * | |||
9856 | * Purpose: | |||
9857 | * Constructor | |||
9858 | * | |||
9859 | * Args: | |||
9860 | * nSrcSpace = signature of the source color space, | |||
9861 | * nDestSpace = signature of the destination color space, | |||
9862 | * bFirstInput = true if the first profile added is an input profile | |||
9863 | ************************************************************************** | |||
9864 | */ | |||
9865 | CIccNamedColorCmm::CIccNamedColorCmm(icColorSpaceSignature nSrcSpace, icColorSpaceSignature nDestSpace, | |||
9866 | bool bFirstInput) : CIccCmm(nSrcSpace, nDestSpace, bFirstInput) | |||
9867 | { | |||
9868 | m_nApplyInterface = icApplyPixel2Pixel; | |||
9869 | } | |||
9870 | ||||
9871 | /** | |||
9872 | ************************************************************************** | |||
9873 | * Name: CIccNamedColorCmm::~CIccNamedColorCmm | |||
9874 | * | |||
9875 | * Purpose: | |||
9876 | * Destructor | |||
9877 | ************************************************************************** | |||
9878 | */ | |||
9879 | CIccNamedColorCmm::~CIccNamedColorCmm() | |||
9880 | { | |||
9881 | } | |||
9882 | ||||
9883 | ||||
9884 | /** | |||
9885 | ************************************************************************** | |||
9886 | * Name: CIccNamedColorCmm::AddXform | |||
9887 | * | |||
9888 | * Purpose: | |||
9889 | * Adds a profile at the end of the Xform list | |||
9890 | * | |||
9891 | * Args: | |||
9892 | * szProfilePath = file name of the profile to be added, | |||
9893 | * nIntent = rendering intent to be used with the profile, | |||
9894 | * nInterp = type of interpolation to be used with the profile | |||
9895 | * pHintManager = hints for creating the xform | |||
9896 | * | |||
9897 | * Return: | |||
9898 | * icCmmStatOk, if the profile was added to the list succesfully | |||
9899 | ************************************************************************** | |||
9900 | */ | |||
9901 | icStatusCMM CIccNamedColorCmm::AddXform(const icChar *szProfilePath, | |||
9902 | icRenderingIntent nIntent /*=icUnknownIntent*/, | |||
9903 | icXformInterp nInterp /*icXformInterp*/, | |||
9904 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
9905 | icXformLutType nLutType /*=icXformLutColor*/, | |||
9906 | bool bUseD2BxB2DxTags /*=true*/, | |||
9907 | CIccCreateXformHintManager *pHintManager /*=NULL*/, | |||
9908 | bool bUseSubProfile /*=false*/) | |||
9909 | { | |||
9910 | CIccProfile *pProfile = OpenIccProfile(szProfilePath, bUseSubProfile); | |||
9911 | ||||
9912 | if (!pProfile) | |||
9913 | return icCmmStatCantOpenProfile; | |||
9914 | ||||
9915 | icStatusCMM rv = AddXform(pProfile, nIntent, nInterp, pPcc, nLutType, bUseD2BxB2DxTags, pHintManager); | |||
9916 | ||||
9917 | if (rv != icCmmStatOk) | |||
9918 | delete pProfile; | |||
9919 | ||||
9920 | return rv; | |||
9921 | } | |||
9922 | ||||
9923 | /** | |||
9924 | ************************************************************************** | |||
9925 | * Name: CIccNamedColorCmm::AddXform | |||
9926 | * | |||
9927 | * Purpose: | |||
9928 | * Adds a profile at the end of the Xform list | |||
9929 | * | |||
9930 | * Args: | |||
9931 | * pProfile = pointer to the CIccProfile object to be added, | |||
9932 | * nIntent = rendering intent to be used with the profile, | |||
9933 | * nInterp = type of interpolation to be used with the profile | |||
9934 | * nLutType = type of lut to use from the profile | |||
9935 | * pHintManager = hints for creating the xform | |||
9936 | * | |||
9937 | * Return: | |||
9938 | * icCmmStatOk, if the profile was added to the list succesfully | |||
9939 | ************************************************************************** | |||
9940 | */ | |||
9941 | icStatusCMM CIccNamedColorCmm::AddXform(CIccProfile *pProfile, | |||
9942 | icRenderingIntent nIntent /*=icUnknownIntent*/, | |||
9943 | icXformInterp nInterp /*=icInterpLinear*/, | |||
9944 | IIccProfileConnectionConditions *pPcc/*=NULL*/, | |||
9945 | icXformLutType nLutType /*=icXformLutColor*/, | |||
9946 | bool bUseD2BxB2DxTags /*=true*/, | |||
9947 | CIccCreateXformHintManager *pHintManager /*=NULL*/) | |||
9948 | { | |||
9949 | icColorSpaceSignature nSrcSpace, nDstSpace; | |||
9950 | CIccXformPtr Xform; | |||
9951 | bool bInput = !m_bLastInput; | |||
9952 | icStatusCMM rv; | |||
9953 | icXformLutType nUseLutType = nLutType; | |||
9954 | ||||
9955 | switch(pProfile->m_Header.deviceClass) { | |||
9956 | case icSigMaterialIdentificationClass: | |||
9957 | case icSigMaterialLinkClass: | |||
9958 | nIntent = icPerceptual; | |||
9959 | nLutType = icXformLutMCS; | |||
9960 | break; | |||
9961 | ||||
9962 | case icSigMaterialVisualizationClass: | |||
9963 | nLutType = icXformLutMCS; | |||
9964 | break; | |||
9965 | ||||
9966 | default: | |||
9967 | break; | |||
9968 | } | |||
9969 | ||||
9970 | Xform.ptr = NULL__null; | |||
9971 | switch (nUseLutType) { | |||
9972 | //Automatically choose which one | |||
9973 | case icXformLutColor: | |||
9974 | case icXformLutColorimetric: | |||
9975 | case icXformLutSpectral: | |||
9976 | case icXformLutNamedColor: | |||
9977 | { | |||
9978 | CIccTag *pTag = pProfile->FindTag(icSigNamedColor2Tag); | |||
9979 | ||||
9980 | if (pTag && (pProfile->m_Header.deviceClass==icSigNamedColorClass || nLutType == icXformLutNamedColor)) { | |||
9981 | if (bInput) { | |||
9982 | nSrcSpace = icSigNamedData; | |||
9983 | } | |||
9984 | else if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | |||
9985 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
9986 | bUseD2BxB2DxTags = true; | |||
9987 | } | |||
9988 | else { | |||
9989 | nSrcSpace = pProfile->m_Header.pcs; | |||
9990 | } | |||
9991 | ||||
9992 | if (!m_Xforms->size()) { | |||
9993 | if (m_nSrcSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
9994 | m_nSrcSpace = nSrcSpace; | |||
9995 | } | |||
9996 | else { | |||
9997 | nSrcSpace = m_nSrcSpace; | |||
9998 | } | |||
9999 | } | |||
10000 | else { | |||
10001 | if (m_nLastSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
10002 | m_nLastSpace = nSrcSpace; | |||
10003 | } | |||
10004 | else { | |||
10005 | nSrcSpace = m_nLastSpace; | |||
10006 | } | |||
10007 | } | |||
10008 | ||||
10009 | if (nSrcSpace==icSigNamedData) { | |||
10010 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | |||
10011 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
10012 | bUseD2BxB2DxTags = true; | |||
10013 | } | |||
10014 | else { | |||
10015 | nDstSpace = pProfile->m_Header.pcs; | |||
10016 | } | |||
10017 | bInput = true; | |||
10018 | } | |||
10019 | else { | |||
10020 | nDstSpace = icSigNamedData; | |||
10021 | bInput = false; | |||
10022 | } | |||
10023 | ||||
10024 | Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, icXformLutNamedColor, bUseD2BxB2DxTags, pHintManager); | |||
10025 | if (!Xform.ptr) { | |||
10026 | return icCmmStatBadXform; | |||
10027 | } | |||
10028 | CIccXformNamedColor *pXform = (CIccXformNamedColor *)Xform.ptr; | |||
10029 | rv = pXform->SetSrcSpace(nSrcSpace); | |||
10030 | if (rv) | |||
10031 | return rv; | |||
10032 | ||||
10033 | rv = pXform->SetDestSpace(nDstSpace); | |||
10034 | if (rv) | |||
10035 | return rv; | |||
10036 | } | |||
10037 | else { | |||
10038 | //It isn't named color so make we will use color lut. | |||
10039 | if (nUseLutType==icXformLutNamedColor) | |||
10040 | nUseLutType = icXformLutColor; | |||
10041 | ||||
10042 | //Check pProfile if nIntent and input can be found. | |||
10043 | if (bInput) { | |||
10044 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
10045 | ||||
10046 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | |||
10047 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
10048 | bUseD2BxB2DxTags = true; | |||
10049 | } | |||
10050 | else | |||
10051 | nDstSpace = pProfile->m_Header.pcs; | |||
10052 | } | |||
10053 | else { | |||
10054 | if (pProfile->m_Header.deviceClass == icSigLinkClass) { | |||
10055 | return icCmmStatBadSpaceLink; | |||
10056 | } | |||
10057 | if (pProfile->m_Header.deviceClass == icSigAbstractClass) { | |||
10058 | bInput = true; | |||
10059 | nIntent = icPerceptual; // Note: icPerceptualIntent = 0 | |||
10060 | } | |||
10061 | ||||
10062 | if (nLutType == icXformLutSpectral || (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS && nLutType != icXformLutColorimetric)) { | |||
10063 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
10064 | bUseD2BxB2DxTags = true; | |||
10065 | } | |||
10066 | else | |||
10067 | nSrcSpace = pProfile->m_Header.pcs; | |||
10068 | ||||
10069 | nDstSpace = pProfile->m_Header.colorSpace; | |||
10070 | } | |||
10071 | } | |||
10072 | } | |||
10073 | break; | |||
10074 | ||||
10075 | case icXformLutPreview: | |||
10076 | nSrcSpace = pProfile->m_Header.pcs; | |||
10077 | nDstSpace = pProfile->m_Header.pcs; | |||
10078 | bInput = false; | |||
10079 | break; | |||
10080 | ||||
10081 | case icXformLutGamut: | |||
10082 | nSrcSpace = pProfile->m_Header.pcs; | |||
10083 | nDstSpace = icSigGamutData((icColorSpaceSignature) 0x67616D74); | |||
10084 | bInput = true; | |||
10085 | break; | |||
10086 | ||||
10087 | case icXformLutBRDFParam: | |||
10088 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
10089 | nDstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | |||
10090 | break; | |||
10091 | ||||
10092 | case icXformLutBRDFDirect: | |||
10093 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
10094 | nDstSpace = icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f); | |||
10095 | break; | |||
10096 | ||||
10097 | case icXformLutMCS: | |||
10098 | switch(pProfile->m_Header.deviceClass) | |||
10099 | { | |||
10100 | case icSigInputClass: | |||
10101 | case icSigMaterialIdentificationClass: | |||
10102 | nSrcSpace = pProfile->m_Header.colorSpace; | |||
10103 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | |||
10104 | break; | |||
10105 | case icSigMaterialVisualizationClass: | |||
10106 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | |||
10107 | if (bUseD2BxB2DxTags && pProfile->m_Header.spectralPCS) { | |||
10108 | nDstSpace = (icColorSpaceSignature)pProfile->m_Header.spectralPCS; | |||
10109 | } | |||
10110 | else { | |||
10111 | nDstSpace = pProfile->m_Header.pcs; | |||
10112 | } | |||
10113 | bInput = true; | |||
10114 | break; | |||
10115 | ||||
10116 | case icSigMaterialLinkClass: | |||
10117 | nSrcSpace = (icColorSpaceSignature)pProfile->m_Header.mcs; | |||
10118 | nDstSpace = pProfile->m_Header.colorSpace; | |||
10119 | break; | |||
10120 | ||||
10121 | default: | |||
10122 | return icCmmStatBadLutType; | |||
10123 | } | |||
10124 | break; | |||
10125 | ||||
10126 | default: | |||
10127 | return icCmmStatBadLutType; | |||
10128 | } | |||
10129 | ||||
10130 | //Make sure color spaces match with previous xforms | |||
10131 | if (!m_Xforms->size()) { | |||
10132 | if (m_nSrcSpace == icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
10133 | m_nLastSpace = nSrcSpace; | |||
10134 | m_nSrcSpace = nSrcSpace; | |||
10135 | } | |||
10136 | else if (!IsCompatSpace(m_nSrcSpace, nSrcSpace)((m_nSrcSpace)==(nSrcSpace) || ((((m_nSrcSpace)==icSigXYZData || (m_nSrcSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nSrcSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nSrcSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) ) && !IsNChannelCompat(m_nSrcSpace, nSrcSpace)(((((icColorSpaceSignature)(((icUInt32Number)m_nSrcSpace)& 0xffff0000))==icSigNChannelData) && (((icUInt32Number )m_nSrcSpace)&0x0000ffff)==icGetSpaceSamples(nSrcSpace)) || ((((icColorSpaceSignature)(((icUInt32Number)nSrcSpace)&0xffff0000 ))==icSigNChannelData) && (((icUInt32Number)nSrcSpace )&0x0000ffff)==icGetSpaceSamples(m_nSrcSpace)))) { | |||
10137 | return icCmmStatBadSpaceLink; | |||
10138 | } | |||
10139 | } | |||
10140 | else if (!IsCompatSpace(m_nLastSpace, nSrcSpace)((m_nLastSpace)==(nSrcSpace) || ((((m_nLastSpace)==icSigXYZData || (m_nLastSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace )) && (((nSrcSpace)==icSigXYZData || (nSrcSpace)==icSigLabData ) || IsSpaceSpectralPCS(nSrcSpace))) || ((((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData ) && (((icColorSpaceSignature)(((icUInt32Number)nSrcSpace )&0xffff0000))==icSigSrcMCSChannelData)) ) && !IsNChannelCompat(m_nSrcSpace, nSrcSpace)(((((icColorSpaceSignature)(((icUInt32Number)m_nSrcSpace)& 0xffff0000))==icSigNChannelData) && (((icUInt32Number )m_nSrcSpace)&0x0000ffff)==icGetSpaceSamples(nSrcSpace)) || ((((icColorSpaceSignature)(((icUInt32Number)nSrcSpace)&0xffff0000 ))==icSigNChannelData) && (((icUInt32Number)nSrcSpace )&0x0000ffff)==icGetSpaceSamples(m_nSrcSpace)))) { | |||
10141 | return icCmmStatBadSpaceLink; | |||
10142 | } | |||
10143 | ||||
10144 | //Automatic creation of intent from header/last profile | |||
10145 | if (nIntent==icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) { | |||
10146 | if (bInput) { | |||
10147 | nIntent = (icRenderingIntent)pProfile->m_Header.renderingIntent; | |||
10148 | } | |||
10149 | else { | |||
10150 | nIntent = m_nLastIntent; | |||
10151 | } | |||
10152 | if (nIntent == icUnknownIntent((icRenderingIntent) 0x3f3f3f3f)) | |||
10153 | nIntent = icPerceptual; | |||
10154 | } | |||
10155 | ||||
10156 | if (!Xform.ptr) | |||
10157 | Xform.ptr = CIccXform::Create(pProfile, bInput, nIntent, nInterp, pPcc, nUseLutType, bUseD2BxB2DxTags, pHintManager); | |||
10158 | ||||
10159 | if (!Xform.ptr) { | |||
10160 | return icCmmStatBadXform; | |||
10161 | } | |||
10162 | ||||
10163 | m_nLastSpace = Xform.ptr->GetDstSpace(); | |||
10164 | m_nLastIntent = nIntent; | |||
10165 | ||||
10166 | if (pProfile->m_Header.deviceClass == icSigLinkClass) | |||
10167 | bInput = false; | |||
10168 | m_bLastInput = bInput; | |||
10169 | ||||
10170 | m_Xforms->push_back(Xform); | |||
10171 | ||||
10172 | return icCmmStatOk; | |||
10173 | } | |||
10174 | ||||
10175 | /** | |||
10176 | ************************************************************************** | |||
10177 | * Name: CIccNamedColorCmm::Begin | |||
10178 | * | |||
10179 | * Purpose: | |||
10180 | * Does the initialization of the Xforms in the list before Apply() is called. | |||
10181 | * Must be called before Apply(). | |||
10182 | * | |||
10183 | ************************************************************************** | |||
10184 | */ | |||
10185 | icStatusCMM CIccNamedColorCmm::Begin(bool bAllocNewApply/* =true */, bool bUsePcsConversion/*=false*/) | |||
10186 | { | |||
10187 | if (m_nDestSpace==icSigUnknownData((icColorSpaceSignature) 0x3f3f3f3f)) { | |||
10188 | m_nDestSpace = m_nLastSpace; | |||
10189 | } | |||
10190 | else if (!IsCompatSpace(m_nDestSpace, m_nLastSpace)((m_nDestSpace)==(m_nLastSpace) || ((((m_nDestSpace)==icSigXYZData || (m_nDestSpace)==icSigLabData) || IsSpaceSpectralPCS(m_nDestSpace )) && (((m_nLastSpace)==icSigXYZData || (m_nLastSpace )==icSigLabData) || IsSpaceSpectralPCS(m_nLastSpace))) || ((( (icColorSpaceSignature)(((icUInt32Number)m_nDestSpace)&0xffff0000 ))==icSigSrcMCSChannelData) && (((icColorSpaceSignature )(((icUInt32Number)m_nLastSpace)&0xffff0000))==icSigSrcMCSChannelData )) )) { | |||
10191 | return icCmmStatBadSpaceLink; | |||
10192 | } | |||
10193 | ||||
10194 | if (m_nSrcSpace != icSigNamedData) { | |||
10195 | if (m_nDestSpace != icSigNamedData) { | |||
10196 | m_nApplyInterface = icApplyPixel2Pixel; | |||
10197 | } | |||
10198 | else { | |||
10199 | m_nApplyInterface = icApplyPixel2Named; | |||
10200 | } | |||
10201 | } | |||
10202 | else { | |||
10203 | if (m_nDestSpace != icSigNamedData) { | |||
10204 | m_nApplyInterface = icApplyNamed2Pixel; | |||
10205 | } | |||
10206 | else { | |||
10207 | m_nApplyInterface = icApplyNamed2Named; | |||
10208 | } | |||
10209 | } | |||
10210 | ||||
10211 | SetLateBindingCC(); | |||
10212 | ||||
10213 | icStatusCMM rv; | |||
10214 | CIccXformList::iterator i; | |||
10215 | ||||
10216 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
10217 | rv = i->ptr->Begin(); | |||
10218 | ||||
10219 | if (rv!= icCmmStatOk) { | |||
10220 | return rv; | |||
10221 | } | |||
10222 | } | |||
10223 | ||||
10224 | rv = CheckPCSConnections(bUsePcsConversion); | |||
10225 | if (rv != icCmmStatOk && rv!=icCmmStatIdentityXform) | |||
10226 | return rv; | |||
10227 | ||||
10228 | if (bAllocNewApply) { | |||
10229 | rv = icCmmStatOk; | |||
10230 | ||||
10231 | m_pApply = GetNewApplyCmm(rv); | |||
10232 | } | |||
10233 | else | |||
10234 | rv = icCmmStatOk; | |||
10235 | ||||
10236 | return rv; | |||
10237 | } | |||
10238 | ||||
10239 | /** | |||
10240 | ************************************************************************** | |||
10241 | * Name: CIccNamedColorCmm::GetNewApplyCmm | |||
10242 | * | |||
10243 | * Purpose: | |||
10244 | * Allocates a CIccApplyCmm object that allows one to call apply from | |||
10245 | * multiple threads. | |||
10246 | * | |||
10247 | ************************************************************************** | |||
10248 | */ | |||
10249 | CIccApplyCmm *CIccNamedColorCmm::GetNewApplyCmm(icStatusCMM &status) | |||
10250 | { | |||
10251 | CIccApplyCmm *pApply = new CIccApplyNamedColorCmm(this); | |||
10252 | ||||
10253 | CIccXformList::iterator i; | |||
10254 | ||||
10255 | for (i=m_Xforms->begin(); i!=m_Xforms->end(); i++) { | |||
10256 | CIccApplyXform *pXform = i->ptr->GetNewApply(status); | |||
10257 | if (status != icCmmStatOk || !pXform) { | |||
10258 | delete pApply; | |||
10259 | return NULL__null; | |||
10260 | } | |||
10261 | pApply->AppendApplyXform(pXform); | |||
10262 | } | |||
10263 | ||||
10264 | m_bValid = true; | |||
10265 | ||||
10266 | status = icCmmStatOk; | |||
10267 | return pApply; | |||
10268 | } | |||
10269 | ||||
10270 | ||||
10271 | /** | |||
10272 | ************************************************************************** | |||
10273 | * Name: CIccApplyNamedColorCmm::Apply | |||
10274 | * | |||
10275 | * Purpose: | |||
10276 | * Does the actual application of the Xforms in the list. | |||
10277 | * | |||
10278 | * Args: | |||
10279 | * DstColorName = Destination string where the result is stored, | |||
10280 | * SrcPoxel = Source pixel | |||
10281 | ************************************************************************** | |||
10282 | */ | |||
10283 | icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icFloatNumber *SrcPixel) | |||
10284 | { | |||
10285 | return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcPixel); | |||
10286 | } | |||
10287 | ||||
10288 | ||||
10289 | /** | |||
10290 | ************************************************************************** | |||
10291 | * Name: CIccApplyNamedColorCmm::Apply | |||
10292 | * | |||
10293 | * Purpose: | |||
10294 | * Does the actual application of the Xforms in the list. | |||
10295 | * | |||
10296 | * Args: | |||
10297 | * DestPixel = Destination pixel where the result is stored, | |||
10298 | * SrcColorName = Source color name which is to be searched. | |||
10299 | ************************************************************************** | |||
10300 | */ | |||
10301 | icStatusCMM CIccNamedColorCmm::Apply(icFloatNumber *DstPixel, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | |||
10302 | { | |||
10303 | return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstPixel, SrcColorName, tint); | |||
10304 | } | |||
10305 | ||||
10306 | ||||
10307 | /** | |||
10308 | ************************************************************************** | |||
10309 | * Name: CIccApplyNamedColorCmm::Apply | |||
10310 | * | |||
10311 | * Purpose: | |||
10312 | * Does the actual application of the Xforms in the list. | |||
10313 | * | |||
10314 | * Args: | |||
10315 | * DstColorName = Destination string where the result is stored, | |||
10316 | * SrcColorName = Source color name which is to be searched. | |||
10317 | ************************************************************************** | |||
10318 | */ | |||
10319 | icStatusCMM CIccNamedColorCmm::Apply(icChar* DstColorName, const icChar *SrcColorName, icFloatNumber tint/*=1.0*/) | |||
10320 | { | |||
10321 | return ((CIccApplyNamedColorCmm*)m_pApply)->Apply(DstColorName, SrcColorName, tint); | |||
10322 | } | |||
10323 | ||||
10324 | ||||
10325 | /** | |||
10326 | ************************************************************************** | |||
10327 | * Name: CIccNamedColorCmm::SetLastXformDest | |||
10328 | * | |||
10329 | * Purpose: | |||
10330 | * Sets the destination Color space of the last Xform in the list | |||
10331 | * | |||
10332 | * Args: | |||
10333 | * nDestSpace = signature of the color space to be set | |||
10334 | ************************************************************************** | |||
10335 | */ | |||
10336 | icStatusCMM CIccNamedColorCmm::SetLastXformDest(icColorSpaceSignature nDestSpace) | |||
10337 | { | |||
10338 | int n = (int)m_Xforms->size(); | |||
10339 | CIccXformPtr *pLastXform; | |||
10340 | ||||
10341 | if (!n) | |||
10342 | return icCmmStatBadXform; | |||
10343 | ||||
10344 | pLastXform = &m_Xforms->back(); | |||
10345 | ||||
10346 | if (pLastXform->ptr->GetXformType()==icXformTypeNamedColor) { | |||
10347 | CIccXformNamedColor *pXform = (CIccXformNamedColor *)pLastXform->ptr; | |||
10348 | if (pXform->GetSrcSpace() == icSigNamedData && | |||
10349 | nDestSpace == icSigNamedData) { | |||
10350 | return icCmmStatBadSpaceLink; | |||
10351 | } | |||
10352 | ||||
10353 | if (nDestSpace != icSigNamedData && | |||
10354 | pXform->GetDstSpace() == icSigNamedData) { | |||
10355 | return icCmmStatBadSpaceLink; | |||
10356 | } | |||
10357 | ||||
10358 | return pXform->SetDestSpace(nDestSpace); | |||
10359 | } | |||
10360 | ||||
10361 | return icCmmStatBadXform; | |||
10362 | } | |||
10363 | ||||
10364 | ||||
10365 | /** | |||
10366 | **************************************************************************** | |||
10367 | * Name: CIccMruCmm::CIccMruCmm | |||
10368 | * | |||
10369 | * Purpose: private constructor - Use Attach to create CIccMruCmm objects | |||
10370 | ***************************************************************************** | |||
10371 | */ | |||
10372 | CIccMruCmm::CIccMruCmm() | |||
10373 | { | |||
10374 | m_pCmm = NULL__null; | |||
10375 | m_bDeleteCmm = false; | |||
10376 | } | |||
10377 | ||||
10378 | ||||
10379 | /** | |||
10380 | **************************************************************************** | |||
10381 | * Name: CIccMruCmm::~CIccMruCmm | |||
10382 | * | |||
10383 | * Purpose: destructor | |||
10384 | ***************************************************************************** | |||
10385 | */ | |||
10386 | CIccMruCmm::~CIccMruCmm() | |||
10387 | { | |||
10388 | if (m_pCmm && m_bDeleteCmm) | |||
10389 | delete m_pCmm; | |||
10390 | } | |||
10391 | ||||
10392 | ||||
10393 | /** | |||
10394 | **************************************************************************** | |||
10395 | * Name: CIccMruCmm::Attach | |||
10396 | * | |||
10397 | * Purpose: Create a Cmm decorator object that implements a cache of most | |||
10398 | * recently used pixel transformations. | |||
10399 | * | |||
10400 | * Args: | |||
10401 | * pCmm - pointer to cmm object that we are attaching to. | |||
10402 | * nCacheSize - number of most recently used transformations to cache | |||
10403 | * bDeleteCmm - flag to indicate whether cmm should be deleted when | |||
10404 | * this is destroyed. | |||
10405 | * | |||
10406 | * Return: | |||
10407 | * A CIccMruCmm object that represents a cached form of the pCmm passed in. | |||
10408 | * The pCmm will be owned by the returned object unless. | |||
10409 | * | |||
10410 | * If this function fails the pCmm object will be deleted. | |||
10411 | ***************************************************************************** | |||
10412 | */ | |||
10413 | CIccMruCmm* CIccMruCmm::Attach(CIccCmm *pCmm, icUInt8Number nCacheSize/* =4 */, bool bDeleteCmm/*=true*/) | |||
10414 | { | |||
10415 | if (!pCmm || !nCacheSize) | |||
10416 | return NULL__null; | |||
10417 | ||||
10418 | if (!pCmm->Valid()) { | |||
10419 | if (bDeleteCmm) | |||
10420 | delete pCmm; | |||
10421 | return NULL__null; | |||
10422 | } | |||
10423 | ||||
10424 | CIccMruCmm *rv = new CIccMruCmm(); | |||
10425 | ||||
10426 | rv->m_pCmm = pCmm; | |||
10427 | rv->m_nCacheSize = nCacheSize; | |||
10428 | rv->m_bDeleteCmm = bDeleteCmm; | |||
10429 | ||||
10430 | rv->m_nSrcSpace = pCmm->GetSourceSpace(); | |||
10431 | rv->m_nDestSpace = pCmm->GetDestSpace(); | |||
10432 | rv->m_nLastSpace = pCmm->GetLastSpace(); | |||
10433 | rv->m_nLastIntent = pCmm->GetLastIntent(); | |||
10434 | ||||
10435 | if (rv->Begin()!=icCmmStatOk) { | |||
10436 | delete rv; | |||
10437 | return NULL__null; | |||
10438 | } | |||
10439 | ||||
10440 | return rv; | |||
10441 | } | |||
10442 | ||||
10443 | CIccApplyCmm *CIccMruCmm::GetNewApplyCmm(icStatusCMM &status) | |||
10444 | { | |||
10445 | CIccApplyMruCmm *rv = new CIccApplyMruCmm(this); | |||
10446 | ||||
10447 | if (!rv) { | |||
10448 | status = icCmmStatAllocErr; | |||
10449 | return NULL__null; | |||
10450 | } | |||
10451 | ||||
10452 | if (!rv->Init(m_pCmm, m_nCacheSize)) { | |||
10453 | delete rv; | |||
10454 | status = icCmmStatBad; | |||
10455 | return NULL__null; | |||
10456 | } | |||
10457 | ||||
10458 | return rv; | |||
10459 | } | |||
10460 | ||||
10461 | /** | |||
10462 | **************************************************************************** | |||
10463 | * Name: CIccMruCache::CIccMruCache | |||
10464 | * | |||
10465 | * Purpose: constructor | |||
10466 | ***************************************************************************** | |||
10467 | */ | |||
10468 | template<class T> | |||
10469 | CIccMruCache<T>::CIccMruCache() | |||
10470 | { | |||
10471 | m_cache = NULL__null; | |||
10472 | ||||
10473 | m_pixelData = NULL__null; | |||
10474 | } | |||
10475 | ||||
10476 | /** | |||
10477 | **************************************************************************** | |||
10478 | * Name: CIccMruCache::~CIccMruCache | |||
10479 | * | |||
10480 | * Purpose: destructor | |||
10481 | ***************************************************************************** | |||
10482 | */ | |||
10483 | template<class T> | |||
10484 | CIccMruCache<T>::~CIccMruCache() | |||
10485 | { | |||
10486 | if (m_cache) | |||
10487 | delete[] m_cache; | |||
10488 | ||||
10489 | if (m_pixelData) | |||
10490 | free(m_pixelData); | |||
10491 | } | |||
10492 | ||||
10493 | /** | |||
10494 | **************************************************************************** | |||
10495 | * Name: CIccMruCache::Init | |||
10496 | * | |||
10497 | * Purpose: Initialize the object and set up the cache | |||
10498 | * | |||
10499 | * Args: | |||
10500 | * pCmm - pointer to cmm object that we are attaching to. | |||
10501 | * nCacheSize - number of most recently used transformations to cache | |||
10502 | * | |||
10503 | * Return: | |||
10504 | * true if successful | |||
10505 | ***************************************************************************** | |||
10506 | */ | |||
10507 | template<class T> | |||
10508 | bool CIccMruCache<T>::Init(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize) | |||
10509 | { | |||
10510 | m_nSrcSamples = nSrcSamples; | |||
10511 | m_nSrcSize = nSrcSamples * sizeof(T); | |||
10512 | m_nDstSize = nDstSamples * sizeof(T); | |||
10513 | ||||
10514 | m_nTotalSamples = m_nSrcSamples + nDstSamples; | |||
10515 | ||||
10516 | m_nNumPixel = 0; | |||
10517 | m_nCacheSize = nCacheSize; | |||
10518 | ||||
10519 | m_pFirst = NULL__null; | |||
10520 | m_cache = new CIccMruPixel<T>[nCacheSize]; | |||
10521 | ||||
10522 | if (!m_cache) | |||
10523 | return false; | |||
10524 | ||||
10525 | m_pixelData = (T*)malloc(nCacheSize * m_nTotalSamples * sizeof(T)); | |||
10526 | ||||
10527 | if (!m_pixelData) | |||
10528 | return false; | |||
10529 | ||||
10530 | return true; | |||
10531 | } | |||
10532 | ||||
10533 | template<class T> | |||
10534 | CIccMruCache<T> *CIccMruCache<T>::NewMruCache(icUInt16Number nSrcSamples, icUInt16Number nDstSamples, icUInt16Number nCacheSize /* = 4 */) | |||
10535 | { | |||
10536 | CIccMruCache<T> *rv = new CIccMruCache<T>; | |||
10537 | ||||
10538 | if (!rv->Init(nSrcSamples, nDstSamples, nCacheSize)) { | |||
10539 | delete rv; | |||
10540 | return NULL__null; | |||
10541 | } | |||
10542 | ||||
10543 | return rv; | |||
10544 | } | |||
10545 | ||||
10546 | /** | |||
10547 | **************************************************************************** | |||
10548 | * Name: CIccMruCache::Apply | |||
10549 | * | |||
10550 | * Purpose: Apply a transformation to a pixel. | |||
10551 | * | |||
10552 | * Args: | |||
10553 | * DstPixel - Location to store pixel results | |||
10554 | * SrcPixel - Location to get pixel values from | |||
10555 | * | |||
10556 | * Return: | |||
10557 | * true if SrcPixel found in cache and DstPixel initialized with value | |||
10558 | * fails if SrcPixel not found (DstPixel not touched) | |||
10559 | ***************************************************************************** | |||
10560 | */ | |||
10561 | template<class T> | |||
10562 | bool CIccMruCache<T>::Apply(T *DstPixel, const T *SrcPixel) | |||
10563 | { | |||
10564 | CIccMruPixel<T> *ptr, *prev = NULL__null, *last = NULL__null; | |||
10565 | int i; | |||
10566 | T *pixel; | |||
10567 | ||||
10568 | for (ptr = m_pFirst, i = 0; ptr; ptr = ptr->pNext, i++) { | |||
10569 | if (!memcmp(SrcPixel, ptr->pPixelData, m_nSrcSize)) { | |||
10570 | memcpy(DstPixel, &ptr->pPixelData[m_nSrcSamples], m_nDstSize); | |||
10571 | if (ptr != m_pFirst) { | |||
10572 | last->pNext = ptr->pNext; | |||
10573 | ||||
10574 | ptr->pNext = m_pFirst; | |||
10575 | m_pFirst = ptr; | |||
10576 | } | |||
10577 | return true; | |||
10578 | } | |||
10579 | prev = last; | |||
10580 | last = ptr; | |||
10581 | } | |||
10582 | ||||
10583 | //If we get here SrcPixel is not in the cache | |||
10584 | if (i < m_nCacheSize) { | |||
10585 | pixel = &m_pixelData[i*m_nTotalSamples]; | |||
10586 | ||||
10587 | ptr = &m_cache[i]; | |||
10588 | ptr->pPixelData = pixel; | |||
10589 | ||||
10590 | if (m_pFirst) { | |||
10591 | ptr->pNext = m_pFirst; | |||
10592 | } | |||
10593 | m_pFirst = ptr; | |||
10594 | } | |||
10595 | else { //Reuse oldest value and put it at the front of the list | |||
10596 | prev->pNext = NULL__null; | |||
10597 | last->pNext = m_pFirst; | |||
10598 | ||||
10599 | m_pFirst = last; | |||
10600 | pixel = last->pPixelData; | |||
10601 | } | |||
10602 | T *dest = &pixel[m_nSrcSamples]; | |||
10603 | ||||
10604 | memcpy(pixel, SrcPixel, m_nSrcSize); | |||
10605 | ||||
10606 | return false; | |||
10607 | } | |||
10608 | ||||
10609 | template<class T> | |||
10610 | void CIccMruCache<T>::Update(T* DstPixel) | |||
10611 | { | |||
10612 | memcpy(&m_pFirst->pPixelData[m_nSrcSamples], DstPixel, m_nDstSize); | |||
10613 | } | |||
10614 | ||||
10615 | //Make sure typedef classes get built | |||
10616 | template class CIccMruCache<icFloatNumber>; | |||
10617 | template class CIccMruCache<icUInt8Number>; | |||
10618 | template class CIccMruCache<icUInt16Number>; | |||
10619 | ||||
10620 | ||||
10621 | CIccApplyMruCmm::CIccApplyMruCmm(CIccMruCmm *pCmm) : CIccApplyCmm(pCmm) | |||
10622 | { | |||
10623 | m_pCachedCmm = NULL__null; | |||
10624 | m_pCache = NULL__null; | |||
10625 | } | |||
10626 | ||||
10627 | /** | |||
10628 | **************************************************************************** | |||
10629 | * Name: CIccApplyMruCmm::~CIccApplyMruCmm | |||
10630 | * | |||
10631 | * Purpose: destructor | |||
10632 | ***************************************************************************** | |||
10633 | */ | |||
10634 | CIccApplyMruCmm::~CIccApplyMruCmm() | |||
10635 | { | |||
10636 | if (m_pCache) | |||
10637 | delete m_pCache; | |||
10638 | ||||
10639 | } | |||
10640 | ||||
10641 | /** | |||
10642 | **************************************************************************** | |||
10643 | * Name: CIccApplyMruCmm::Init | |||
10644 | * | |||
10645 | * Purpose: Initialize the object and set up the cache | |||
10646 | * | |||
10647 | * Args: | |||
10648 | * pCmm - pointer to cmm object that we are attaching to. | |||
10649 | * nCacheSize - number of most recently used transformations to cache | |||
10650 | * | |||
10651 | * Return: | |||
10652 | * true if successful | |||
10653 | ***************************************************************************** | |||
10654 | */ | |||
10655 | bool CIccApplyMruCmm::Init(CIccCmm *pCachedCmm, icUInt16Number nCacheSize) | |||
10656 | { | |||
10657 | m_pCachedCmm = pCachedCmm; | |||
10658 | ||||
10659 | m_pCache = CIccMruCacheFloat::NewMruCache(m_pCmm->GetSourceSamples(), m_pCmm->GetDestSamples(), nCacheSize); | |||
10660 | ||||
10661 | if (!m_pCache) | |||
10662 | return false; | |||
10663 | ||||
10664 | return true; | |||
10665 | } | |||
10666 | ||||
10667 | /** | |||
10668 | **************************************************************************** | |||
10669 | * Name: CIccMruCmm::Apply | |||
10670 | * | |||
10671 | * Purpose: Apply a transformation to a pixel. | |||
10672 | * | |||
10673 | * Args: | |||
10674 | * DstPixel - Location to store pixel results | |||
10675 | * SrcPixel - Location to get pixel values from | |||
10676 | * | |||
10677 | * Return: | |||
10678 | * icCmmStatOk if successful | |||
10679 | ***************************************************************************** | |||
10680 | */ | |||
10681 | icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel) | |||
10682 | { | |||
10683 | #if defined(_DEBUG) | |||
10684 | if (!m_pCache) | |||
10685 | return icCmmStatInvalidLut; | |||
10686 | #endif | |||
10687 | ||||
10688 | if (!m_pCache->Apply(DstPixel, SrcPixel)) { | |||
10689 | ||||
10690 | m_pCachedCmm->Apply(DstPixel, SrcPixel); | |||
10691 | ||||
10692 | m_pCache->Update(DstPixel); | |||
10693 | } | |||
10694 | ||||
10695 | return icCmmStatOk; | |||
10696 | } | |||
10697 | ||||
10698 | /** | |||
10699 | **************************************************************************** | |||
10700 | * Name: CIccMruCmm::Apply | |||
10701 | * | |||
10702 | * Purpose: Apply a transformation to a pixel. | |||
10703 | * | |||
10704 | * Args: | |||
10705 | * DstPixel - Location to store pixel results | |||
10706 | * SrcPixel - Location to get pixel values from | |||
10707 | * nPixels - number of pixels to convert | |||
10708 | * | |||
10709 | * Return: | |||
10710 | * icCmmStatOk if successful | |||
10711 | ***************************************************************************** | |||
10712 | */ | |||
10713 | icStatusCMM CIccApplyMruCmm::Apply(icFloatNumber *DstPixel, const icFloatNumber *SrcPixel, icUInt32Number nPixels) | |||
10714 | { | |||
10715 | icUInt32Number k; | |||
10716 | ||||
10717 | #if defined(_DEBUG) | |||
10718 | if (!m_pCache) | |||
10719 | return icCmmStatInvalidLut; | |||
10720 | #endif | |||
10721 | ||||
10722 | for (k=0; k<nPixels;k++) { | |||
10723 | if (!m_pCache->Apply(DstPixel, SrcPixel)) { | |||
10724 | m_pCachedCmm->Apply(DstPixel, SrcPixel); | |||
10725 | m_pCache->Update(DstPixel); | |||
10726 | } | |||
10727 | SrcPixel += m_pCmm->GetSourceSamples(); | |||
10728 | DstPixel += m_pCmm->GetDestSamples(); | |||
10729 | } | |||
10730 | ||||
10731 | return icCmmStatOk; | |||
10732 | } | |||
10733 | ||||
10734 | ||||
10735 | #ifdef USEREFICCMAXNAMESPACE | |||
10736 | } //namespace refIccMAX | |||
10737 | #endif |