Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 PDFium Authors. All rights reserved. | 1 // Copyright 2014 PDFium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com |
| 6 | 6 |
| 7 #include "core/fxcodec/codec/codec_int.h" | 7 #include "core/fxcodec/codec/codec_int.h" |
| 8 #include "core/fxcodec/include/fx_codec.h" | 8 #include "core/fxcodec/include/fx_codec.h" |
| 9 #include "third_party/lcms2-2.6/include/lcms2.h" | 9 #include "third_party/lcms2-2.6/include/lcms2.h" |
| 10 | 10 |
| 11 const uint32_t N_COMPONENT_LAB = 3; | 11 const uint32_t N_COMPONENT_LAB = 3; |
| 12 const uint32_t N_COMPONENT_GRAY = 1; | 12 const uint32_t N_COMPONENT_GRAY = 1; |
| 13 const uint32_t N_COMPONENT_RGB = 3; | 13 const uint32_t N_COMPONENT_RGB = 3; |
| 14 const uint32_t N_COMPONENT_CMYK = 4; | 14 const uint32_t N_COMPONENT_CMYK = 4; |
| 15 const uint32_t N_COMPONENT_DEFAULT = 3; | 15 const uint32_t N_COMPONENT_DEFAULT = 3; |
| 16 | 16 |
| 17 FX_BOOL MD5ComputeID(const void* buf, uint32_t dwSize, uint8_t ID[16]) { | |
| 18 return cmsMD5computeIDExt(buf, dwSize, ID); | |
| 19 } | |
| 20 struct CLcmsCmm { | 17 struct CLcmsCmm { |
|
Tom Sepez
2016/09/19 16:40:22
note: as a follow-up CL, you might want to put thi
| |
| 21 cmsHTRANSFORM m_hTransform; | 18 cmsHTRANSFORM m_hTransform; |
| 22 int m_nSrcComponents; | 19 int m_nSrcComponents; |
| 23 int m_nDstComponents; | 20 int m_nDstComponents; |
| 24 FX_BOOL m_bLab; | 21 FX_BOOL m_bLab; |
| 25 }; | 22 }; |
| 26 extern "C" { | |
| 27 int ourHandler(int ErrorCode, const char* ErrorText) { | |
| 28 return TRUE; | |
| 29 } | |
| 30 }; | |
| 31 FX_BOOL CheckComponents(cmsColorSpaceSignature cs, | 23 FX_BOOL CheckComponents(cmsColorSpaceSignature cs, |
| 32 int nComponents, | 24 int nComponents, |
| 33 FX_BOOL bDst) { | 25 FX_BOOL bDst) { |
| 34 if (nComponents <= 0 || nComponents > 15) { | 26 if (nComponents <= 0 || nComponents > 15) { |
| 35 return FALSE; | 27 return FALSE; |
| 36 } | 28 } |
| 37 switch (cs) { | 29 switch (cs) { |
| 38 case cmsSigLabData: | 30 case cmsSigLabData: |
| 39 if (nComponents < 3) { | 31 if (nComponents < 3) { |
| 40 return FALSE; | 32 return FALSE; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 231 break; | 223 break; |
| 232 } | 224 } |
| 233 } | 225 } |
| 234 void IccLib_TranslateImage(void* pTransform, | 226 void IccLib_TranslateImage(void* pTransform, |
| 235 unsigned char* pDest, | 227 unsigned char* pDest, |
| 236 const unsigned char* pSrc, | 228 const unsigned char* pSrc, |
| 237 int32_t pixels) { | 229 int32_t pixels) { |
| 238 cmsDoTransform(((CLcmsCmm*)pTransform)->m_hTransform, (void*)pSrc, pDest, | 230 cmsDoTransform(((CLcmsCmm*)pTransform)->m_hTransform, (void*)pSrc, pDest, |
| 239 pixels); | 231 pixels); |
| 240 } | 232 } |
| 241 void* CreateProfile_Gray(double gamma) { | |
| 242 cmsCIExyY* D50 = (cmsCIExyY*)cmsD50_xyY(); | |
| 243 if (!cmsWhitePointFromTemp(D50, 6504)) { | |
| 244 return nullptr; | |
| 245 } | |
| 246 cmsToneCurve* curve = cmsBuildGamma(nullptr, gamma); | |
| 247 if (!curve) { | |
| 248 return nullptr; | |
| 249 } | |
| 250 void* profile = cmsCreateGrayProfile(D50, curve); | |
| 251 cmsFreeToneCurve(curve); | |
| 252 return profile; | |
| 253 } | |
| 254 CCodec_IccModule::IccCS GetProfileCSFromHandle(void* pProfile) { | |
| 255 if (!pProfile) { | |
| 256 return CCodec_IccModule::IccCS_Unknown; | |
| 257 } | |
| 258 switch (cmsGetColorSpace(pProfile)) { | |
| 259 case cmsSigXYZData: | |
| 260 return CCodec_IccModule::IccCS_XYZ; | |
| 261 case cmsSigLabData: | |
| 262 return CCodec_IccModule::IccCS_Lab; | |
| 263 case cmsSigLuvData: | |
| 264 return CCodec_IccModule::IccCS_Luv; | |
| 265 case cmsSigYCbCrData: | |
| 266 return CCodec_IccModule::IccCS_YCbCr; | |
| 267 case cmsSigYxyData: | |
| 268 return CCodec_IccModule::IccCS_Yxy; | |
| 269 case cmsSigRgbData: | |
| 270 return CCodec_IccModule::IccCS_Rgb; | |
| 271 case cmsSigGrayData: | |
| 272 return CCodec_IccModule::IccCS_Gray; | |
| 273 case cmsSigHsvData: | |
| 274 return CCodec_IccModule::IccCS_Hsv; | |
| 275 case cmsSigHlsData: | |
| 276 return CCodec_IccModule::IccCS_Hls; | |
| 277 case cmsSigCmykData: | |
| 278 return CCodec_IccModule::IccCS_Cmyk; | |
| 279 case cmsSigCmyData: | |
| 280 return CCodec_IccModule::IccCS_Cmy; | |
| 281 default: | |
| 282 return CCodec_IccModule::IccCS_Unknown; | |
| 283 } | |
| 284 } | |
| 285 CCodec_IccModule::IccCS CCodec_IccModule::GetProfileCS( | |
| 286 const uint8_t* pProfileData, | |
| 287 uint32_t dwProfileSize) { | |
| 288 CCodec_IccModule::IccCS cs; | |
| 289 cmsHPROFILE hProfile = | |
| 290 cmsOpenProfileFromMem((void*)pProfileData, dwProfileSize); | |
| 291 if (!hProfile) { | |
| 292 return IccCS_Unknown; | |
| 293 } | |
| 294 cs = GetProfileCSFromHandle(hProfile); | |
| 295 if (hProfile) { | |
| 296 cmsCloseProfile(hProfile); | |
| 297 } | |
| 298 return cs; | |
| 299 } | |
| 300 CCodec_IccModule::IccCS CCodec_IccModule::GetProfileCS(IFX_FileRead* pFile) { | |
| 301 if (!pFile) { | |
| 302 return IccCS_Unknown; | |
| 303 } | |
| 304 CCodec_IccModule::IccCS cs; | |
| 305 uint32_t dwSize = (uint32_t)pFile->GetSize(); | |
| 306 uint8_t* pBuf = FX_Alloc(uint8_t, dwSize); | |
| 307 pFile->ReadBlock(pBuf, 0, dwSize); | |
| 308 cs = GetProfileCS(pBuf, dwSize); | |
| 309 FX_Free(pBuf); | |
| 310 return cs; | |
| 311 } | |
| 312 uint32_t TransferProfileType(void* pProfile, uint32_t dwFormat) { | |
| 313 cmsColorSpaceSignature cs = cmsGetColorSpace(pProfile); | |
| 314 switch (cs) { | |
| 315 case cmsSigXYZData: | |
| 316 return TYPE_XYZ_16; | |
| 317 case cmsSigLabData: | |
| 318 return TYPE_Lab_DBL; | |
| 319 case cmsSigLuvData: | |
| 320 return TYPE_YUV_8; | |
| 321 case cmsSigYCbCrData: | |
| 322 return TYPE_YCbCr_8; | |
| 323 case cmsSigYxyData: | |
| 324 return TYPE_Yxy_16; | |
| 325 case cmsSigRgbData: | |
| 326 return T_DOSWAP(dwFormat) ? TYPE_RGB_8 : TYPE_BGR_8; | |
| 327 case cmsSigGrayData: | |
| 328 return TYPE_GRAY_8; | |
| 329 case cmsSigHsvData: | |
| 330 return TYPE_HSV_8; | |
| 331 case cmsSigHlsData: | |
| 332 return TYPE_HLS_8; | |
| 333 case cmsSigCmykData: | |
| 334 return T_DOSWAP(dwFormat) ? TYPE_KYMC_8 : TYPE_CMYK_8; | |
| 335 case cmsSigCmyData: | |
| 336 return TYPE_CMY_8; | |
| 337 case cmsSigMCH5Data: | |
| 338 return T_DOSWAP(dwFormat) ? TYPE_KYMC5_8 : TYPE_CMYK5_8; | |
| 339 case cmsSigMCH6Data: | |
| 340 return TYPE_CMYK6_8; | |
| 341 case cmsSigMCH7Data: | |
| 342 return T_DOSWAP(dwFormat) ? TYPE_KYMC7_8 : TYPE_CMYK7_8; | |
| 343 case cmsSigMCH8Data: | |
| 344 return T_DOSWAP(dwFormat) ? TYPE_KYMC8_8 : TYPE_CMYK8_8; | |
| 345 case cmsSigMCH9Data: | |
| 346 return T_DOSWAP(dwFormat) ? TYPE_KYMC9_8 : TYPE_CMYK9_8; | |
| 347 case cmsSigMCHAData: | |
| 348 return T_DOSWAP(dwFormat) ? TYPE_KYMC10_8 : TYPE_CMYK10_8; | |
| 349 case cmsSigMCHBData: | |
| 350 return T_DOSWAP(dwFormat) ? TYPE_KYMC11_8 : TYPE_CMYK11_8; | |
| 351 case cmsSigMCHCData: | |
| 352 return T_DOSWAP(dwFormat) ? TYPE_KYMC12_8 : TYPE_CMYK12_8; | |
| 353 default: | |
| 354 return 0; | |
| 355 } | |
| 356 } | |
| 357 class CFX_IccProfileCache { | |
| 358 public: | |
| 359 CFX_IccProfileCache(); | |
| 360 ~CFX_IccProfileCache(); | |
| 361 void* m_pProfile; | |
| 362 uint32_t m_dwRate; | |
| 363 | |
| 364 protected: | |
| 365 void Purge(); | |
| 366 }; | |
| 367 CFX_IccProfileCache::CFX_IccProfileCache() { | |
| 368 m_pProfile = nullptr; | |
| 369 m_dwRate = 1; | |
| 370 } | |
| 371 CFX_IccProfileCache::~CFX_IccProfileCache() { | |
| 372 if (m_pProfile) { | |
| 373 cmsCloseProfile(m_pProfile); | |
| 374 } | |
| 375 } | |
| 376 void CFX_IccProfileCache::Purge() {} | |
| 377 class CFX_IccTransformCache { | |
| 378 public: | |
| 379 CFX_IccTransformCache(CLcmsCmm* pCmm = nullptr); | |
| 380 ~CFX_IccTransformCache(); | |
| 381 void* m_pIccTransform; | |
| 382 uint32_t m_dwRate; | |
| 383 CLcmsCmm* m_pCmm; | |
| 384 | |
| 385 protected: | |
| 386 void Purge(); | |
| 387 }; | |
| 388 CFX_IccTransformCache::CFX_IccTransformCache(CLcmsCmm* pCmm) { | |
| 389 m_pIccTransform = nullptr; | |
| 390 m_dwRate = 1; | |
| 391 m_pCmm = pCmm; | |
| 392 } | |
| 393 CFX_IccTransformCache::~CFX_IccTransformCache() { | |
| 394 if (m_pIccTransform) { | |
| 395 cmsDeleteTransform(m_pIccTransform); | |
| 396 } | |
| 397 FX_Free(m_pCmm); | |
| 398 } | |
| 399 void CFX_IccTransformCache::Purge() {} | |
| 400 class CFX_ByteStringKey : public CFX_BinaryBuf { | |
| 401 public: | |
| 402 CFX_ByteStringKey() : CFX_BinaryBuf() {} | |
| 403 CFX_ByteStringKey& operator<<(uint32_t i); | |
| 404 }; | |
| 405 CFX_ByteStringKey& CFX_ByteStringKey::operator<<(uint32_t i) { | |
| 406 AppendBlock(&i, sizeof(uint32_t)); | |
| 407 return *this; | |
| 408 } | |
| 409 void* CCodec_IccModule::CreateProfile(CCodec_IccModule::IccParam* pIccParam, | |
| 410 Icc_CLASS ic, | |
| 411 CFX_BinaryBuf* pTransformKey) { | |
| 412 CFX_IccProfileCache* pCache = nullptr; | |
| 413 CFX_ByteStringKey key; | |
| 414 CFX_ByteString text; | |
| 415 key << pIccParam->ColorSpace << (pIccParam->dwProfileType | ic << 8); | |
| 416 uint8_t ID[16]; | |
| 417 switch (pIccParam->dwProfileType) { | |
| 418 case Icc_PARAMTYPE_NONE: | |
| 419 return nullptr; | |
| 420 case Icc_PARAMTYPE_BUFFER: | |
| 421 MD5ComputeID(pIccParam->pProfileData, pIccParam->dwProfileSize, ID); | |
| 422 break; | |
| 423 case Icc_PARAMTYPE_PARAM: | |
| 424 FXSYS_memset(ID, 0, 16); | |
| 425 switch (pIccParam->ColorSpace) { | |
| 426 case IccCS_Gray: | |
| 427 text.Format("%lf", pIccParam->Gamma); | |
| 428 break; | |
| 429 default: | |
| 430 break; | |
| 431 } | |
| 432 MD5ComputeID(text.GetBuffer(0), text.GetLength(), ID); | |
| 433 break; | |
| 434 default: | |
| 435 break; | |
| 436 } | |
| 437 key.AppendBlock(ID, 16); | |
| 438 CFX_ByteString ProfileKey(key.GetBuffer(), key.GetSize()); | |
| 439 ASSERT(pTransformKey); | |
| 440 pTransformKey->AppendBlock(ProfileKey.GetBuffer(0), ProfileKey.GetLength()); | |
| 441 auto it = m_MapProfile.find(ProfileKey); | |
| 442 if (it == m_MapProfile.end()) { | |
| 443 pCache = new CFX_IccProfileCache; | |
| 444 switch (pIccParam->dwProfileType) { | |
| 445 case Icc_PARAMTYPE_BUFFER: | |
| 446 pCache->m_pProfile = cmsOpenProfileFromMem(pIccParam->pProfileData, | |
| 447 pIccParam->dwProfileSize); | |
| 448 break; | |
| 449 case Icc_PARAMTYPE_PARAM: | |
| 450 switch (pIccParam->ColorSpace) { | |
| 451 case IccCS_Rgb: | |
| 452 pCache->m_pProfile = cmsCreate_sRGBProfile(); | |
| 453 break; | |
| 454 case IccCS_Gray: | |
| 455 pCache->m_pProfile = CreateProfile_Gray(pIccParam->Gamma); | |
| 456 break; | |
| 457 default: | |
| 458 break; | |
| 459 } | |
| 460 break; | |
| 461 default: | |
| 462 break; | |
| 463 } | |
| 464 m_MapProfile[ProfileKey] = pCache; | |
| 465 } else { | |
| 466 pCache = it->second; | |
| 467 pCache->m_dwRate++; | |
| 468 } | |
| 469 return pCache->m_pProfile; | |
| 470 } | |
| 471 void* CCodec_IccModule::CreateTransform( | |
| 472 CCodec_IccModule::IccParam* pInputParam, | |
| 473 CCodec_IccModule::IccParam* pOutputParam, | |
| 474 CCodec_IccModule::IccParam* pProofParam, | |
| 475 uint32_t dwIntent, | |
| 476 uint32_t dwFlag, | |
| 477 uint32_t dwPrfIntent, | |
| 478 uint32_t dwPrfFlag) { | |
| 479 CLcmsCmm* pCmm = nullptr; | |
| 480 ASSERT(pInputParam && pOutputParam); | |
| 481 CFX_ByteStringKey key; | |
| 482 void* pInputProfile = CreateProfile(pInputParam, Icc_CLASS_INPUT, &key); | |
| 483 if (!pInputProfile) { | |
| 484 return nullptr; | |
| 485 } | |
| 486 void* pOutputProfile = CreateProfile(pOutputParam, Icc_CLASS_OUTPUT, &key); | |
| 487 if (!pOutputProfile) { | |
| 488 return nullptr; | |
| 489 } | |
| 490 uint32_t dwInputProfileType = | |
| 491 TransferProfileType(pInputProfile, pInputParam->dwFormat); | |
| 492 uint32_t dwOutputProfileType = | |
| 493 TransferProfileType(pOutputProfile, pOutputParam->dwFormat); | |
| 494 if (dwInputProfileType == 0 || dwOutputProfileType == 0) { | |
| 495 return nullptr; | |
| 496 } | |
| 497 void* pProofProfile = nullptr; | |
| 498 if (pProofParam) { | |
| 499 pProofProfile = CreateProfile(pProofParam, Icc_CLASS_PROOF, &key); | |
| 500 } | |
| 501 key << dwInputProfileType << dwOutputProfileType << dwIntent << dwFlag | |
| 502 << !!pProofProfile << dwPrfIntent << dwPrfFlag; | |
| 503 CFX_ByteString TransformKey(key.GetBuffer(), key.GetSize()); | |
| 504 CFX_IccTransformCache* pTransformCache; | |
| 505 auto it = m_MapTranform.find(TransformKey); | |
| 506 if (it == m_MapTranform.end()) { | |
| 507 pCmm = FX_Alloc(CLcmsCmm, 1); | |
| 508 pCmm->m_nSrcComponents = T_CHANNELS(dwInputProfileType); | |
| 509 pCmm->m_nDstComponents = T_CHANNELS(dwOutputProfileType); | |
| 510 pCmm->m_bLab = T_COLORSPACE(pInputParam->dwFormat) == PT_Lab; | |
| 511 pTransformCache = new CFX_IccTransformCache(pCmm); | |
| 512 if (pProofProfile) { | |
| 513 pTransformCache->m_pIccTransform = cmsCreateProofingTransform( | |
| 514 pInputProfile, dwInputProfileType, pOutputProfile, | |
| 515 dwOutputProfileType, pProofProfile, dwIntent, dwPrfIntent, dwPrfFlag); | |
| 516 } else { | |
| 517 pTransformCache->m_pIccTransform = | |
| 518 cmsCreateTransform(pInputProfile, dwInputProfileType, pOutputProfile, | |
| 519 dwOutputProfileType, dwIntent, dwFlag); | |
| 520 } | |
| 521 pCmm->m_hTransform = pTransformCache->m_pIccTransform; | |
| 522 m_MapTranform[TransformKey] = pTransformCache; | |
| 523 } else { | |
| 524 pTransformCache = it->second; | |
| 525 pTransformCache->m_dwRate++; | |
| 526 } | |
| 527 return pTransformCache->m_pCmm; | |
| 528 } | |
| 529 | 233 |
| 530 CCodec_IccModule::CCodec_IccModule() : m_nComponents(0) {} | 234 CCodec_IccModule::CCodec_IccModule() : m_nComponents(0) {} |
| 531 | 235 |
| 532 CCodec_IccModule::~CCodec_IccModule() { | 236 CCodec_IccModule::~CCodec_IccModule() { |
| 533 for (const auto& pair : m_MapProfile) { | |
| 534 delete pair.second; | |
| 535 } | |
| 536 m_MapProfile.clear(); | |
| 537 for (const auto& pair : m_MapTranform) { | |
| 538 delete pair.second; | |
| 539 } | |
| 540 m_MapTranform.clear(); | |
| 541 } | 237 } |
| 542 void* CCodec_IccModule::CreateTransform_sRGB(const uint8_t* pProfileData, | 238 void* CCodec_IccModule::CreateTransform_sRGB(const uint8_t* pProfileData, |
| 543 uint32_t dwProfileSize, | 239 uint32_t dwProfileSize, |
| 544 uint32_t& nComponents, | 240 uint32_t& nComponents, |
| 545 int32_t intent, | 241 int32_t intent, |
| 546 uint32_t dwSrcFormat) { | 242 uint32_t dwSrcFormat) { |
| 547 return IccLib_CreateTransform_sRGB(pProfileData, dwProfileSize, nComponents, | 243 return IccLib_CreateTransform_sRGB(pProfileData, dwProfileSize, nComponents, |
| 548 intent, dwSrcFormat); | 244 intent, dwSrcFormat); |
| 549 } | 245 } |
| 550 | 246 |
| 551 void* CCodec_IccModule::CreateTransform_CMYK(const uint8_t* pSrcProfileData, | |
| 552 uint32_t dwSrcProfileSize, | |
| 553 uint32_t& nSrcComponents, | |
| 554 const uint8_t* pDstProfileData, | |
| 555 uint32_t dwDstProfileSize, | |
| 556 int32_t intent, | |
| 557 uint32_t dwSrcFormat, | |
| 558 uint32_t dwDstFormat) { | |
| 559 return IccLib_CreateTransform( | |
| 560 pSrcProfileData, dwSrcProfileSize, nSrcComponents, pDstProfileData, | |
| 561 dwDstProfileSize, 4, intent, dwSrcFormat, dwDstFormat); | |
| 562 } | |
| 563 | |
| 564 void CCodec_IccModule::DestroyTransform(void* pTransform) { | 247 void CCodec_IccModule::DestroyTransform(void* pTransform) { |
| 565 IccLib_DestroyTransform(pTransform); | 248 IccLib_DestroyTransform(pTransform); |
| 566 } | 249 } |
| 567 void CCodec_IccModule::Translate(void* pTransform, | 250 void CCodec_IccModule::Translate(void* pTransform, |
| 568 FX_FLOAT* pSrcValues, | 251 FX_FLOAT* pSrcValues, |
| 569 FX_FLOAT* pDestValues) { | 252 FX_FLOAT* pDestValues) { |
| 570 IccLib_Translate(pTransform, m_nComponents, pSrcValues, pDestValues); | 253 IccLib_Translate(pTransform, m_nComponents, pSrcValues, pDestValues); |
| 571 } | 254 } |
| 572 void CCodec_IccModule::TranslateScanline(void* pTransform, | 255 void CCodec_IccModule::TranslateScanline(void* pTransform, |
| 573 uint8_t* pDest, | 256 uint8_t* pDest, |
| (...skipping 1424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1998 ASSERT(k1 == FXSYS_round(k * 255)); | 1681 ASSERT(k1 == FXSYS_round(k * 255)); |
| 1999 | 1682 |
| 2000 uint8_t r, g, b; | 1683 uint8_t r, g, b; |
| 2001 AdobeCMYK_to_sRGB1(c1, m1, y1, k1, r, g, b); | 1684 AdobeCMYK_to_sRGB1(c1, m1, y1, k1, r, g, b); |
| 2002 // Multiply by a constant rather than dividing because division is much | 1685 // Multiply by a constant rather than dividing because division is much |
| 2003 // more expensive. | 1686 // more expensive. |
| 2004 R = r * (1.0f / 255); | 1687 R = r * (1.0f / 255); |
| 2005 G = g * (1.0f / 255); | 1688 G = g * (1.0f / 255); |
| 2006 B = b * (1.0f / 255); | 1689 B = b * (1.0f / 255); |
| 2007 } | 1690 } |
| OLD | NEW |