|
1 /* ************************************************************************** */ |
|
2 /* * For conditions of distribution and use, * */ |
|
3 /* * see copyright notice in libmng.h * */ |
|
4 /* ************************************************************************** */ |
|
5 /* * * */ |
|
6 /* * project : libmng * */ |
|
7 /* * file : libmng_cms.c copyright (c) 2000-2004 G.Juyn * */ |
|
8 /* * version : 1.0.9 * */ |
|
9 /* * * */ |
|
10 /* * purpose : color management routines (implementation) * */ |
|
11 /* * * */ |
|
12 /* * author : G.Juyn * */ |
|
13 /* * * */ |
|
14 /* * comment : implementation of the color management routines * */ |
|
15 /* * * */ |
|
16 /* * changes : 0.5.1 - 05/01/2000 - G.Juyn * */ |
|
17 /* * - B001(105795) - fixed a typo and misconception about * */ |
|
18 /* * freeing allocated gamma-table. (reported by Marti Maria) * */ |
|
19 /* * 0.5.1 - 05/08/2000 - G.Juyn * */ |
|
20 /* * - changed strict-ANSI stuff * */ |
|
21 /* * 0.5.1 - 05/09/2000 - G.Juyn * */ |
|
22 /* * - filled application-based color-management routines * */ |
|
23 /* * 0.5.1 - 05/11/2000 - G.Juyn * */ |
|
24 /* * - added creatememprofile * */ |
|
25 /* * - added callback error-reporting support * */ |
|
26 /* * 0.5.1 - 05/12/2000 - G.Juyn * */ |
|
27 /* * - changed trace to macro for callback error-reporting * */ |
|
28 /* * * */ |
|
29 /* * 0.5.2 - 06/10/2000 - G.Juyn * */ |
|
30 /* * - fixed some compilation-warnings (contrib Jason Morris) * */ |
|
31 /* * * */ |
|
32 /* * 0.5.3 - 06/21/2000 - G.Juyn * */ |
|
33 /* * - fixed problem with color-correction for stored images * */ |
|
34 /* * 0.5.3 - 06/23/2000 - G.Juyn * */ |
|
35 /* * - fixed problem with incorrect gamma-correction * */ |
|
36 /* * * */ |
|
37 /* * 0.9.2 - 08/05/2000 - G.Juyn * */ |
|
38 /* * - changed file-prefixes * */ |
|
39 /* * * */ |
|
40 /* * 0.9.3 - 08/31/2000 - G.Juyn * */ |
|
41 /* * - fixed sRGB precedence for gamma_only corection * */ |
|
42 /* * * */ |
|
43 /* * 0.9.4 - 12/16/2000 - G.Juyn * */ |
|
44 /* * - fixed mixup of data- & function-pointers (thanks Dimitri)* */ |
|
45 /* * * */ |
|
46 /* * 1.0.1 - 03/31/2001 - G.Juyn * */ |
|
47 /* * - ignore gamma=0 (see png-list for more info) * */ |
|
48 /* * 1.0.1 - 04/25/2001 - G.Juyn (reported by Gregg Kelly) * */ |
|
49 /* * - fixed problem with cms profile being created multiple * */ |
|
50 /* * times when both iCCP & cHRM/gAMA are present * */ |
|
51 /* * 1.0.1 - 04/25/2001 - G.Juyn * */ |
|
52 /* * - moved mng_clear_cms to libmng_cms * */ |
|
53 /* * 1.0.1 - 05/02/2001 - G.Juyn * */ |
|
54 /* * - added "default" sRGB generation (Thanks Marti!) * */ |
|
55 /* * * */ |
|
56 /* * 1.0.5 - 08/19/2002 - G.Juyn * */ |
|
57 /* * - B597134 - libmng pollutes the linker namespace * */ |
|
58 /* * 1.0.5 - 09/19/2002 - G.Juyn * */ |
|
59 /* * - optimized color-correction routines * */ |
|
60 /* * 1.0.5 - 09/23/2002 - G.Juyn * */ |
|
61 /* * - added in-memory color-correction of abstract images * */ |
|
62 /* * 1.0.5 - 11/08/2002 - G.Juyn * */ |
|
63 /* * - fixed issues in init_app_cms() * */ |
|
64 /* * * */ |
|
65 /* * 1.0.6 - 04/11/2003 - G.Juyn * */ |
|
66 /* * - B719420 - fixed several MNG_APP_CMS problems * */ |
|
67 /* * 1.0.6 - 07/11/2003 - G. R-P * */ |
|
68 /* * - added conditional MNG_SKIPCHUNK_cHRM/iCCP * */ |
|
69 /* * * */ |
|
70 /* * 1.0.9 - 12/20/2004 - G.Juyn * */ |
|
71 /* * - cleaned up macro-invocations (thanks to D. Airlie) * */ |
|
72 /* * * */ |
|
73 /* ************************************************************************** */ |
|
74 |
|
75 #include "libmng.h" |
|
76 #include "libmng_data.h" |
|
77 #include "libmng_error.h" |
|
78 #include "libmng_trace.h" |
|
79 #ifdef __BORLANDC__ |
|
80 #pragma hdrstop |
|
81 #endif |
|
82 #include "libmng_objects.h" |
|
83 #include "libmng_cms.h" |
|
84 |
|
85 #if defined(__BORLANDC__) && defined(MNG_STRICT_ANSI) |
|
86 #pragma option -A /* force ANSI-C */ |
|
87 #endif |
|
88 |
|
89 /* ************************************************************************** */ |
|
90 |
|
91 #ifdef MNG_INCLUDE_DISPLAY_PROCS |
|
92 |
|
93 /* ************************************************************************** */ |
|
94 /* * * */ |
|
95 /* * Little CMS helper routines * */ |
|
96 /* * * */ |
|
97 /* ************************************************************************** */ |
|
98 |
|
99 #ifdef MNG_INCLUDE_LCMS |
|
100 |
|
101 #define MNG_CMS_FLAGS 0 |
|
102 |
|
103 /* ************************************************************************** */ |
|
104 |
|
105 void mnglcms_initlibrary () |
|
106 { |
|
107 cmsErrorAction (LCMS_ERROR_IGNORE); /* LCMS should ignore errors! */ |
|
108 } |
|
109 |
|
110 /* ************************************************************************** */ |
|
111 |
|
112 mng_cmsprof mnglcms_createfileprofile (mng_pchar zFilename) |
|
113 { |
|
114 return cmsOpenProfileFromFile (zFilename, "r"); |
|
115 } |
|
116 |
|
117 /* ************************************************************************** */ |
|
118 |
|
119 mng_cmsprof mnglcms_creatememprofile (mng_uint32 iProfilesize, |
|
120 mng_ptr pProfile) |
|
121 { |
|
122 return cmsOpenProfileFromMem (pProfile, iProfilesize); |
|
123 } |
|
124 |
|
125 /* ************************************************************************** */ |
|
126 |
|
127 mng_cmsprof mnglcms_createsrgbprofile (void) |
|
128 { |
|
129 cmsCIExyY D65; |
|
130 cmsCIExyYTRIPLE Rec709Primaries = { |
|
131 {0.6400, 0.3300, 1.0}, |
|
132 {0.3000, 0.6000, 1.0}, |
|
133 {0.1500, 0.0600, 1.0} |
|
134 }; |
|
135 LPGAMMATABLE Gamma24[3]; |
|
136 mng_cmsprof hsRGB; |
|
137 |
|
138 cmsWhitePointFromTemp(6504, &D65); |
|
139 Gamma24[0] = Gamma24[1] = Gamma24[2] = cmsBuildGamma(256, 2.4); |
|
140 hsRGB = cmsCreateRGBProfile(&D65, &Rec709Primaries, Gamma24); |
|
141 cmsFreeGamma(Gamma24[0]); |
|
142 |
|
143 return hsRGB; |
|
144 } |
|
145 |
|
146 /* ************************************************************************** */ |
|
147 |
|
148 void mnglcms_freeprofile (mng_cmsprof hProf) |
|
149 { |
|
150 cmsCloseProfile (hProf); |
|
151 return; |
|
152 } |
|
153 |
|
154 /* ************************************************************************** */ |
|
155 |
|
156 void mnglcms_freetransform (mng_cmstrans hTrans) |
|
157 { |
|
158 /* B001 start */ |
|
159 cmsDeleteTransform (hTrans); |
|
160 /* B001 end */ |
|
161 return; |
|
162 } |
|
163 |
|
164 /* ************************************************************************** */ |
|
165 |
|
166 mng_retcode mng_clear_cms (mng_datap pData) |
|
167 { |
|
168 #ifdef MNG_SUPPORT_TRACE |
|
169 MNG_TRACE (pData, MNG_FN_CLEAR_CMS, MNG_LC_START); |
|
170 #endif |
|
171 |
|
172 if (pData->hTrans) /* transformation still active ? */ |
|
173 mnglcms_freetransform (pData->hTrans); |
|
174 |
|
175 pData->hTrans = 0; |
|
176 |
|
177 if (pData->hProf1) /* file profile still active ? */ |
|
178 mnglcms_freeprofile (pData->hProf1); |
|
179 |
|
180 pData->hProf1 = 0; |
|
181 |
|
182 #ifdef MNG_SUPPORT_TRACE |
|
183 MNG_TRACE (pData, MNG_FN_CLEAR_CMS, MNG_LC_END); |
|
184 #endif |
|
185 |
|
186 return MNG_NOERROR; |
|
187 } |
|
188 |
|
189 /* ************************************************************************** */ |
|
190 |
|
191 #endif /* MNG_INCLUDE_LCMS */ |
|
192 |
|
193 /* ************************************************************************** */ |
|
194 /* * * */ |
|
195 /* * Color-management initialization & correction routines * */ |
|
196 /* * * */ |
|
197 /* ************************************************************************** */ |
|
198 |
|
199 #ifdef MNG_INCLUDE_LCMS |
|
200 |
|
201 mng_retcode mng_init_full_cms (mng_datap pData, |
|
202 mng_bool bGlobal, |
|
203 mng_bool bObject, |
|
204 mng_bool bRetrobj) |
|
205 { |
|
206 mng_cmsprof hProf; |
|
207 mng_cmstrans hTrans; |
|
208 mng_imagep pImage = MNG_NULL; |
|
209 mng_imagedatap pBuf = MNG_NULL; |
|
210 |
|
211 #ifdef MNG_SUPPORT_TRACE |
|
212 MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS, MNG_LC_START); |
|
213 #endif |
|
214 |
|
215 if (bObject) /* use object if present ? */ |
|
216 { /* current object ? */ |
|
217 if ((mng_imagep)pData->pCurrentobj) |
|
218 pImage = (mng_imagep)pData->pCurrentobj; |
|
219 else /* if not; use object 0 */ |
|
220 pImage = (mng_imagep)pData->pObjzero; |
|
221 } |
|
222 |
|
223 if (bRetrobj) /* retrieving from an object ? */ |
|
224 pImage = (mng_imagep)pData->pRetrieveobj; |
|
225 |
|
226 if (pImage) /* are we using an object ? */ |
|
227 pBuf = pImage->pImgbuf; /* then address the buffer */ |
|
228 |
|
229 if ((!pBuf) || (!pBuf->bCorrected)) /* is the buffer already corrected ? */ |
|
230 { |
|
231 #ifndef MNG_SKIPCHUNK_iCCP |
|
232 if (((pBuf) && (pBuf->bHasICCP)) || ((bGlobal) && (pData->bHasglobalICCP))) |
|
233 { |
|
234 if (!pData->hProf2) /* output profile not defined ? */ |
|
235 { /* then assume sRGB !! */ |
|
236 pData->hProf2 = mnglcms_createsrgbprofile (); |
|
237 |
|
238 if (!pData->hProf2) /* handle error ? */ |
|
239 MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); |
|
240 } |
|
241 |
|
242 if ((pBuf) && (pBuf->bHasICCP)) /* generate a profile handle */ |
|
243 hProf = cmsOpenProfileFromMem (pBuf->pProfile, pBuf->iProfilesize); |
|
244 else |
|
245 hProf = cmsOpenProfileFromMem (pData->pGlobalProfile, pData->iGlobalProfilesize); |
|
246 |
|
247 pData->hProf1 = hProf; /* save for future use */ |
|
248 |
|
249 if (!hProf) /* handle error ? */ |
|
250 MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); |
|
251 |
|
252 #ifndef MNG_NO_16BIT_SUPPORT |
|
253 if (pData->bIsRGBA16) /* 16-bit intermediates ? */ |
|
254 hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, |
|
255 pData->hProf2, TYPE_RGBA_16_SE, |
|
256 INTENT_PERCEPTUAL, MNG_CMS_FLAGS); |
|
257 else |
|
258 #endif |
|
259 hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, |
|
260 pData->hProf2, TYPE_RGBA_8, |
|
261 INTENT_PERCEPTUAL, MNG_CMS_FLAGS); |
|
262 |
|
263 pData->hTrans = hTrans; /* save for future use */ |
|
264 |
|
265 if (!hTrans) /* handle error ? */ |
|
266 MNG_ERRORL (pData, MNG_LCMS_NOTRANS); |
|
267 /* load color-correction routine */ |
|
268 pData->fCorrectrow = (mng_fptr)mng_correct_full_cms; |
|
269 |
|
270 return MNG_NOERROR; /* and done */ |
|
271 } |
|
272 else |
|
273 #endif |
|
274 if (((pBuf) && (pBuf->bHasSRGB)) || ((bGlobal) && (pData->bHasglobalSRGB))) |
|
275 { |
|
276 mng_uint8 iIntent; |
|
277 |
|
278 if (pData->bIssRGB) /* sRGB system ? */ |
|
279 return MNG_NOERROR; /* no conversion required */ |
|
280 |
|
281 if (!pData->hProf3) /* sRGB profile not defined ? */ |
|
282 { /* then create it implicitly !! */ |
|
283 pData->hProf3 = mnglcms_createsrgbprofile (); |
|
284 |
|
285 if (!pData->hProf3) /* handle error ? */ |
|
286 MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); |
|
287 } |
|
288 |
|
289 hProf = pData->hProf3; /* convert from sRGB profile */ |
|
290 |
|
291 if ((pBuf) && (pBuf->bHasSRGB)) /* determine rendering intent */ |
|
292 iIntent = pBuf->iRenderingintent; |
|
293 else |
|
294 iIntent = pData->iGlobalRendintent; |
|
295 |
|
296 if (pData->bIsRGBA16) /* 16-bit intermediates ? */ |
|
297 hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, |
|
298 pData->hProf2, TYPE_RGBA_16_SE, |
|
299 iIntent, MNG_CMS_FLAGS); |
|
300 else |
|
301 hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, |
|
302 pData->hProf2, TYPE_RGBA_8, |
|
303 iIntent, MNG_CMS_FLAGS); |
|
304 |
|
305 pData->hTrans = hTrans; /* save for future use */ |
|
306 |
|
307 if (!hTrans) /* handle error ? */ |
|
308 MNG_ERRORL (pData, MNG_LCMS_NOTRANS); |
|
309 /* load color-correction routine */ |
|
310 pData->fCorrectrow = (mng_fptr)mng_correct_full_cms; |
|
311 |
|
312 return MNG_NOERROR; /* and done */ |
|
313 } |
|
314 else |
|
315 if ( (((pBuf) && (pBuf->bHasCHRM)) || ((bGlobal) && (pData->bHasglobalCHRM))) && |
|
316 ( ((pBuf) && (pBuf->bHasGAMA) && (pBuf->iGamma > 0)) || |
|
317 ((bGlobal) && (pData->bHasglobalGAMA) && (pData->iGlobalGamma > 0)) ) ) |
|
318 { |
|
319 mng_CIExyY sWhitepoint; |
|
320 mng_CIExyYTRIPLE sPrimaries; |
|
321 mng_gammatabp pGammatable[3]; |
|
322 mng_float dGamma; |
|
323 |
|
324 if (!pData->hProf2) /* output profile not defined ? */ |
|
325 { /* then assume sRGB !! */ |
|
326 pData->hProf2 = mnglcms_createsrgbprofile (); |
|
327 |
|
328 if (!pData->hProf2) /* handle error ? */ |
|
329 MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); |
|
330 } |
|
331 |
|
332 #ifndef MNG_SKIPCHUNK_cHRM |
|
333 if ((pBuf) && (pBuf->bHasCHRM)) /* local cHRM ? */ |
|
334 { |
|
335 sWhitepoint.x = (mng_float)pBuf->iWhitepointx / 100000; |
|
336 sWhitepoint.y = (mng_float)pBuf->iWhitepointy / 100000; |
|
337 sPrimaries.Red.x = (mng_float)pBuf->iPrimaryredx / 100000; |
|
338 sPrimaries.Red.y = (mng_float)pBuf->iPrimaryredy / 100000; |
|
339 sPrimaries.Green.x = (mng_float)pBuf->iPrimarygreenx / 100000; |
|
340 sPrimaries.Green.y = (mng_float)pBuf->iPrimarygreeny / 100000; |
|
341 sPrimaries.Blue.x = (mng_float)pBuf->iPrimarybluex / 100000; |
|
342 sPrimaries.Blue.y = (mng_float)pBuf->iPrimarybluey / 100000; |
|
343 } |
|
344 else |
|
345 { |
|
346 sWhitepoint.x = (mng_float)pData->iGlobalWhitepointx / 100000; |
|
347 sWhitepoint.y = (mng_float)pData->iGlobalWhitepointy / 100000; |
|
348 sPrimaries.Red.x = (mng_float)pData->iGlobalPrimaryredx / 100000; |
|
349 sPrimaries.Red.y = (mng_float)pData->iGlobalPrimaryredy / 100000; |
|
350 sPrimaries.Green.x = (mng_float)pData->iGlobalPrimarygreenx / 100000; |
|
351 sPrimaries.Green.y = (mng_float)pData->iGlobalPrimarygreeny / 100000; |
|
352 sPrimaries.Blue.x = (mng_float)pData->iGlobalPrimarybluex / 100000; |
|
353 sPrimaries.Blue.y = (mng_float)pData->iGlobalPrimarybluey / 100000; |
|
354 } |
|
355 #endif |
|
356 |
|
357 sWhitepoint.Y = /* Y component is always 1.0 */ |
|
358 sPrimaries.Red.Y = |
|
359 sPrimaries.Green.Y = |
|
360 sPrimaries.Blue.Y = 1.0; |
|
361 |
|
362 if ((pBuf) && (pBuf->bHasGAMA)) /* get the gamma value */ |
|
363 dGamma = (mng_float)pBuf->iGamma / 100000; |
|
364 else |
|
365 dGamma = (mng_float)pData->iGlobalGamma / 100000; |
|
366 |
|
367 dGamma = pData->dViewgamma / dGamma; |
|
368 |
|
369 pGammatable [0] = /* and build the lookup tables */ |
|
370 pGammatable [1] = |
|
371 pGammatable [2] = cmsBuildGamma (256, dGamma); |
|
372 |
|
373 if (!pGammatable [0]) /* enough memory ? */ |
|
374 MNG_ERRORL (pData, MNG_LCMS_NOMEM); |
|
375 /* create the profile */ |
|
376 hProf = cmsCreateRGBProfile (&sWhitepoint, &sPrimaries, pGammatable); |
|
377 |
|
378 cmsFreeGamma (pGammatable [0]); /* free the temporary gamma tables ? */ |
|
379 /* yes! but just the one! */ |
|
380 |
|
381 pData->hProf1 = hProf; /* save for future use */ |
|
382 |
|
383 if (!hProf) /* handle error ? */ |
|
384 MNG_ERRORL (pData, MNG_LCMS_NOHANDLE); |
|
385 |
|
386 if (pData->bIsRGBA16) /* 16-bit intermediates ? */ |
|
387 hTrans = cmsCreateTransform (hProf, TYPE_RGBA_16_SE, |
|
388 pData->hProf2, TYPE_RGBA_16_SE, |
|
389 INTENT_PERCEPTUAL, MNG_CMS_FLAGS); |
|
390 else |
|
391 hTrans = cmsCreateTransform (hProf, TYPE_RGBA_8, |
|
392 pData->hProf2, TYPE_RGBA_8, |
|
393 INTENT_PERCEPTUAL, MNG_CMS_FLAGS); |
|
394 |
|
395 pData->hTrans = hTrans; /* save for future use */ |
|
396 |
|
397 if (!hTrans) /* handle error ? */ |
|
398 MNG_ERRORL (pData, MNG_LCMS_NOTRANS); |
|
399 /* load color-correction routine */ |
|
400 pData->fCorrectrow = (mng_fptr)mng_correct_full_cms; |
|
401 |
|
402 return MNG_NOERROR; /* and done */ |
|
403 } |
|
404 } |
|
405 |
|
406 #ifdef MNG_SUPPORT_TRACE |
|
407 MNG_TRACE (pData, MNG_FN_INIT_FULL_CMS, MNG_LC_END); |
|
408 #endif |
|
409 /* if we get here, we'll only do gamma */ |
|
410 return mng_init_gamma_only (pData, bGlobal, bObject, bRetrobj); |
|
411 } |
|
412 #endif /* MNG_INCLUDE_LCMS */ |
|
413 |
|
414 /* ************************************************************************** */ |
|
415 |
|
416 #ifdef MNG_INCLUDE_LCMS |
|
417 mng_retcode mng_correct_full_cms (mng_datap pData) |
|
418 { |
|
419 #ifdef MNG_SUPPORT_TRACE |
|
420 MNG_TRACE (pData, MNG_FN_CORRECT_FULL_CMS, MNG_LC_START); |
|
421 #endif |
|
422 |
|
423 cmsDoTransform (pData->hTrans, pData->pRGBArow, pData->pRGBArow, pData->iRowsamples); |
|
424 |
|
425 #ifdef MNG_SUPPORT_TRACE |
|
426 MNG_TRACE (pData, MNG_FN_CORRECT_FULL_CMS, MNG_LC_END); |
|
427 #endif |
|
428 |
|
429 return MNG_NOERROR; |
|
430 } |
|
431 #endif /* MNG_INCLUDE_LCMS */ |
|
432 |
|
433 /* ************************************************************************** */ |
|
434 |
|
435 #if defined(MNG_GAMMA_ONLY) || defined(MNG_FULL_CMS) || defined(MNG_APP_CMS) |
|
436 mng_retcode mng_init_gamma_only (mng_datap pData, |
|
437 mng_bool bGlobal, |
|
438 mng_bool bObject, |
|
439 mng_bool bRetrobj) |
|
440 { |
|
441 mng_float dGamma; |
|
442 mng_imagep pImage = MNG_NULL; |
|
443 mng_imagedatap pBuf = MNG_NULL; |
|
444 |
|
445 #ifdef MNG_SUPPORT_TRACE |
|
446 MNG_TRACE (pData, MNG_FN_INIT_GAMMA_ONLY, MNG_LC_START); |
|
447 #endif |
|
448 |
|
449 if (bObject) /* use object if present ? */ |
|
450 { /* current object ? */ |
|
451 if ((mng_imagep)pData->pCurrentobj) |
|
452 pImage = (mng_imagep)pData->pCurrentobj; |
|
453 else /* if not; use object 0 */ |
|
454 pImage = (mng_imagep)pData->pObjzero; |
|
455 } |
|
456 |
|
457 if (bRetrobj) /* retrieving from an object ? */ |
|
458 pImage = (mng_imagep)pData->pRetrieveobj; |
|
459 |
|
460 if (pImage) /* are we using an object ? */ |
|
461 pBuf = pImage->pImgbuf; /* then address the buffer */ |
|
462 |
|
463 if ((!pBuf) || (!pBuf->bCorrected)) /* is the buffer already corrected ? */ |
|
464 { |
|
465 if ((pBuf) && (pBuf->bHasSRGB)) /* get the gamma value */ |
|
466 dGamma = 0.45455; |
|
467 else |
|
468 if ((pBuf) && (pBuf->bHasGAMA)) |
|
469 dGamma = (mng_float)pBuf->iGamma / 100000; |
|
470 else |
|
471 if ((bGlobal) && (pData->bHasglobalSRGB)) |
|
472 dGamma = 0.45455; |
|
473 else |
|
474 if ((bGlobal) && (pData->bHasglobalGAMA)) |
|
475 dGamma = (mng_float)pData->iGlobalGamma / 100000; |
|
476 else |
|
477 dGamma = pData->dDfltimggamma; |
|
478 |
|
479 if (dGamma > 0) /* ignore gamma=0 */ |
|
480 { |
|
481 dGamma = pData->dViewgamma / (dGamma * pData->dDisplaygamma); |
|
482 |
|
483 if (dGamma != pData->dLastgamma) /* lookup table needs to be computed ? */ |
|
484 { |
|
485 mng_int32 iX; |
|
486 |
|
487 pData->aGammatab [0] = 0; |
|
488 |
|
489 for (iX = 1; iX <= 255; iX++) |
|
490 pData->aGammatab [iX] = (mng_uint8)(pow (iX / 255.0, dGamma) * 255 + 0.5); |
|
491 |
|
492 pData->dLastgamma = dGamma; /* keep for next time */ |
|
493 } |
|
494 /* load color-correction routine */ |
|
495 pData->fCorrectrow = (mng_fptr)mng_correct_gamma_only; |
|
496 } |
|
497 } |
|
498 |
|
499 #ifdef MNG_SUPPORT_TRACE |
|
500 MNG_TRACE (pData, MNG_FN_INIT_GAMMA_ONLY, MNG_LC_END); |
|
501 #endif |
|
502 |
|
503 return MNG_NOERROR; |
|
504 } |
|
505 #endif /* MNG_GAMMA_ONLY || MNG_FULL_CMS || MNG_APP_CMS */ |
|
506 |
|
507 /* ************************************************************************** */ |
|
508 |
|
509 #if defined(MNG_GAMMA_ONLY) || defined(MNG_FULL_CMS) || defined(MNG_APP_CMS) |
|
510 mng_retcode mng_correct_gamma_only (mng_datap pData) |
|
511 { |
|
512 mng_uint8p pWork; |
|
513 mng_int32 iX; |
|
514 |
|
515 #ifdef MNG_SUPPORT_TRACE |
|
516 MNG_TRACE (pData, MNG_FN_CORRECT_GAMMA_ONLY, MNG_LC_START); |
|
517 #endif |
|
518 |
|
519 pWork = pData->pRGBArow; /* address intermediate row */ |
|
520 |
|
521 if (pData->bIsRGBA16) /* 16-bit intermediate row ? */ |
|
522 { |
|
523 |
|
524 |
|
525 /* TODO: 16-bit precision gamma processing */ |
|
526 /* we'll just do the high-order byte for now */ |
|
527 |
|
528 |
|
529 /* convert all samples in the row */ |
|
530 for (iX = 0; iX < pData->iRowsamples; iX++) |
|
531 { /* using the precalculated gamma lookup table */ |
|
532 *pWork = pData->aGammatab [*pWork]; |
|
533 *(pWork+2) = pData->aGammatab [*(pWork+2)]; |
|
534 *(pWork+4) = pData->aGammatab [*(pWork+4)]; |
|
535 |
|
536 pWork += 8; |
|
537 } |
|
538 } |
|
539 else |
|
540 { /* convert all samples in the row */ |
|
541 for (iX = 0; iX < pData->iRowsamples; iX++) |
|
542 { /* using the precalculated gamma lookup table */ |
|
543 *pWork = pData->aGammatab [*pWork]; |
|
544 *(pWork+1) = pData->aGammatab [*(pWork+1)]; |
|
545 *(pWork+2) = pData->aGammatab [*(pWork+2)]; |
|
546 |
|
547 pWork += 4; |
|
548 } |
|
549 } |
|
550 |
|
551 #ifdef MNG_SUPPORT_TRACE |
|
552 MNG_TRACE (pData, MNG_FN_CORRECT_GAMMA_ONLY, MNG_LC_END); |
|
553 #endif |
|
554 |
|
555 return MNG_NOERROR; |
|
556 } |
|
557 #endif /* MNG_GAMMA_ONLY || MNG_FULL_CMS || MNG_APP_CMS */ |
|
558 |
|
559 /* ************************************************************************** */ |
|
560 |
|
561 #ifdef MNG_APP_CMS |
|
562 mng_retcode mng_init_app_cms (mng_datap pData, |
|
563 mng_bool bGlobal, |
|
564 mng_bool bObject, |
|
565 mng_bool bRetrobj) |
|
566 { |
|
567 mng_imagep pImage = MNG_NULL; |
|
568 mng_imagedatap pBuf = MNG_NULL; |
|
569 mng_bool bDone = MNG_FALSE; |
|
570 mng_retcode iRetcode; |
|
571 |
|
572 #ifdef MNG_SUPPORT_TRACE |
|
573 MNG_TRACE (pData, MNG_FN_INIT_APP_CMS, MNG_LC_START); |
|
574 #endif |
|
575 |
|
576 if (bObject) /* use object if present ? */ |
|
577 { /* current object ? */ |
|
578 if ((mng_imagep)pData->pCurrentobj) |
|
579 pImage = (mng_imagep)pData->pCurrentobj; |
|
580 else /* if not; use object 0 */ |
|
581 pImage = (mng_imagep)pData->pObjzero; |
|
582 } |
|
583 |
|
584 if (bRetrobj) /* retrieving from an object ? */ |
|
585 pImage = (mng_imagep)pData->pRetrieveobj; |
|
586 |
|
587 if (pImage) /* are we using an object ? */ |
|
588 pBuf = pImage->pImgbuf; /* then address the buffer */ |
|
589 |
|
590 if ((!pBuf) || (!pBuf->bCorrected)) /* is the buffer already corrected ? */ |
|
591 { |
|
592 #ifndef MNG_SKIPCHUNK_iCCP |
|
593 if ( (pData->fProcessiccp) && |
|
594 (((pBuf) && (pBuf->bHasICCP)) || ((bGlobal) && (pData->bHasglobalICCP))) ) |
|
595 { |
|
596 mng_uint32 iProfilesize; |
|
597 mng_ptr pProfile; |
|
598 |
|
599 if ((pBuf) && (pBuf->bHasICCP)) /* get the right profile */ |
|
600 { |
|
601 iProfilesize = pBuf->iProfilesize; |
|
602 pProfile = pBuf->pProfile; |
|
603 } |
|
604 else |
|
605 { |
|
606 iProfilesize = pData->iGlobalProfilesize; |
|
607 pProfile = pData->pGlobalProfile; |
|
608 } |
|
609 /* inform the app */ |
|
610 if (!pData->fProcessiccp ((mng_handle)pData, iProfilesize, pProfile)) |
|
611 MNG_ERROR (pData, MNG_APPCMSERROR); |
|
612 /* load color-correction routine */ |
|
613 pData->fCorrectrow = (mng_fptr)mng_correct_app_cms; |
|
614 bDone = MNG_TRUE; |
|
615 } |
|
616 #endif |
|
617 |
|
618 if ( (pData->fProcesssrgb) && |
|
619 (((pBuf) && (pBuf->bHasSRGB)) || ((bGlobal) && (pData->bHasglobalSRGB))) ) |
|
620 { |
|
621 mng_uint8 iIntent; |
|
622 |
|
623 if ((pBuf) && (pBuf->bHasSRGB)) /* determine rendering intent */ |
|
624 iIntent = pBuf->iRenderingintent; |
|
625 else |
|
626 iIntent = pData->iGlobalRendintent; |
|
627 /* inform the app */ |
|
628 if (!pData->fProcesssrgb ((mng_handle)pData, iIntent)) |
|
629 MNG_ERROR (pData, MNG_APPCMSERROR); |
|
630 /* load color-correction routine */ |
|
631 pData->fCorrectrow = (mng_fptr)mng_correct_app_cms; |
|
632 bDone = MNG_TRUE; |
|
633 } |
|
634 |
|
635 #ifndef MNG_SKIPCHUNK_cHRM |
|
636 if ( (pData->fProcesschroma) && |
|
637 (((pBuf) && (pBuf->bHasCHRM)) || ((bGlobal) && (pData->bHasglobalCHRM))) ) |
|
638 { |
|
639 mng_uint32 iWhitepointx, iWhitepointy; |
|
640 mng_uint32 iPrimaryredx, iPrimaryredy; |
|
641 mng_uint32 iPrimarygreenx, iPrimarygreeny; |
|
642 mng_uint32 iPrimarybluex, iPrimarybluey; |
|
643 |
|
644 if ((pBuf) && (pBuf->bHasCHRM)) /* local cHRM ? */ |
|
645 { |
|
646 iWhitepointx = pBuf->iWhitepointx; |
|
647 iWhitepointy = pBuf->iWhitepointy; |
|
648 iPrimaryredx = pBuf->iPrimaryredx; |
|
649 iPrimaryredy = pBuf->iPrimaryredy; |
|
650 iPrimarygreenx = pBuf->iPrimarygreenx; |
|
651 iPrimarygreeny = pBuf->iPrimarygreeny; |
|
652 iPrimarybluex = pBuf->iPrimarybluex; |
|
653 iPrimarybluey = pBuf->iPrimarybluey; |
|
654 } |
|
655 else |
|
656 { |
|
657 iWhitepointx = pData->iGlobalWhitepointx; |
|
658 iWhitepointy = pData->iGlobalWhitepointy; |
|
659 iPrimaryredx = pData->iGlobalPrimaryredx; |
|
660 iPrimaryredy = pData->iGlobalPrimaryredy; |
|
661 iPrimarygreenx = pData->iGlobalPrimarygreenx; |
|
662 iPrimarygreeny = pData->iGlobalPrimarygreeny; |
|
663 iPrimarybluex = pData->iGlobalPrimarybluex; |
|
664 iPrimarybluey = pData->iGlobalPrimarybluey; |
|
665 } |
|
666 /* inform the app */ |
|
667 if (!pData->fProcesschroma ((mng_handle)pData, iWhitepointx, iWhitepointy, |
|
668 iPrimaryredx, iPrimaryredy, |
|
669 iPrimarygreenx, iPrimarygreeny, |
|
670 iPrimarybluex, iPrimarybluey)) |
|
671 MNG_ERROR (pData, MNG_APPCMSERROR); |
|
672 /* load color-correction routine */ |
|
673 pData->fCorrectrow = (mng_fptr)mng_correct_app_cms; |
|
674 bDone = MNG_TRUE; |
|
675 } |
|
676 #endif |
|
677 |
|
678 if ( (pData->fProcessgamma) && |
|
679 (((pBuf) && (pBuf->bHasGAMA)) || ((bGlobal) && (pData->bHasglobalGAMA))) ) |
|
680 { |
|
681 mng_uint32 iGamma; |
|
682 |
|
683 if ((pBuf) && (pBuf->bHasGAMA)) /* get the gamma value */ |
|
684 iGamma = pBuf->iGamma; |
|
685 else |
|
686 iGamma = pData->iGlobalGamma; |
|
687 /* inform the app */ |
|
688 if (!pData->fProcessgamma ((mng_handle)pData, iGamma)) |
|
689 { /* app wants us to use internal routines ! */ |
|
690 iRetcode = mng_init_gamma_only (pData, bGlobal, bObject, bRetrobj); |
|
691 if (iRetcode) /* on error bail out */ |
|
692 return iRetcode; |
|
693 } |
|
694 else |
|
695 { /* load color-correction routine */ |
|
696 pData->fCorrectrow = (mng_fptr)mng_correct_app_cms; |
|
697 } |
|
698 |
|
699 bDone = MNG_TRUE; |
|
700 } |
|
701 |
|
702 if (!bDone) /* no color-info at all ? */ |
|
703 { |
|
704 /* then use default image gamma ! */ |
|
705 if (!pData->fProcessgamma ((mng_handle)pData, |
|
706 (mng_uint32)((pData->dDfltimggamma * 100000) + 0.5))) |
|
707 { /* app wants us to use internal routines ! */ |
|
708 iRetcode = mng_init_gamma_only (pData, bGlobal, bObject, bRetrobj); |
|
709 if (iRetcode) /* on error bail out */ |
|
710 return iRetcode; |
|
711 } |
|
712 else |
|
713 { /* load color-correction routine */ |
|
714 pData->fCorrectrow = (mng_fptr)mng_correct_app_cms; |
|
715 } |
|
716 } |
|
717 } |
|
718 |
|
719 #ifdef MNG_SUPPORT_TRACE |
|
720 MNG_TRACE (pData, MNG_FN_INIT_APP_CMS, MNG_LC_END); |
|
721 #endif |
|
722 |
|
723 return MNG_NOERROR; |
|
724 } |
|
725 #endif /* MNG_APP_CMS */ |
|
726 |
|
727 /* ************************************************************************** */ |
|
728 |
|
729 #ifdef MNG_APP_CMS |
|
730 mng_retcode mng_correct_app_cms (mng_datap pData) |
|
731 { |
|
732 #ifdef MNG_SUPPORT_TRACE |
|
733 MNG_TRACE (pData, MNG_FN_CORRECT_APP_CMS, MNG_LC_START); |
|
734 #endif |
|
735 |
|
736 if (pData->fProcessarow) /* let the app do something with our row */ |
|
737 if (!pData->fProcessarow ((mng_handle)pData, pData->iRowsamples, |
|
738 pData->bIsRGBA16, pData->pRGBArow)) |
|
739 MNG_ERROR (pData, MNG_APPCMSERROR); |
|
740 |
|
741 #ifdef MNG_SUPPORT_TRACE |
|
742 MNG_TRACE (pData, MNG_FN_CORRECT_APP_CMS, MNG_LC_END); |
|
743 #endif |
|
744 |
|
745 return MNG_NOERROR; |
|
746 } |
|
747 #endif /* MNG_APP_CMS */ |
|
748 |
|
749 /* ************************************************************************** */ |
|
750 |
|
751 #endif /* MNG_INCLUDE_DISPLAY_PROCS */ |
|
752 |
|
753 /* ************************************************************************** */ |
|
754 /* * end of file * */ |
|
755 /* ************************************************************************** */ |
|
756 |
|
757 |
|
758 |