| 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 |
|
|---|