1 // Copyright 2016 PDFium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com 6 7 #include "core/fpdfapi/page/cpdf_colorspace.h" 8 9 #include <algorithm> 10 #include <limits> 11 #include <memory> 12 #include <utility> 13 #include <vector> 14 15 #include "core/fpdfapi/cpdf_modulemgr.h" 16 #include "core/fpdfapi/page/cpdf_devicecs.h" 17 #include "core/fpdfapi/page/cpdf_docpagedata.h" 18 #include "core/fpdfapi/page/cpdf_function.h" 19 #include "core/fpdfapi/page/cpdf_iccprofile.h" 20 #include "core/fpdfapi/page/cpdf_pagemodule.h" 21 #include "core/fpdfapi/page/cpdf_pattern.h" 22 #include "core/fpdfapi/page/cpdf_patterncs.h" 23 #include "core/fpdfapi/parser/cpdf_array.h" 24 #include "core/fpdfapi/parser/cpdf_dictionary.h" 25 #include "core/fpdfapi/parser/cpdf_document.h" 26 #include "core/fpdfapi/parser/cpdf_name.h" 27 #include "core/fpdfapi/parser/cpdf_object.h" 28 #include "core/fpdfapi/parser/cpdf_stream.h" 29 #include "core/fpdfapi/parser/cpdf_stream_acc.h" 30 #include "core/fpdfapi/parser/cpdf_string.h" 31 #include "core/fpdfdoc/cpdf_action.h" 32 #include "core/fxcodec/codec/ccodec_iccmodule.h" 33 #include "core/fxcodec/fx_codec.h" 34 #include "core/fxcrt/cfx_fixedbufgrow.h" 35 #include "core/fxcrt/fx_memory.h" 36 #include "core/fxcrt/maybe_owned.h" 37 #include "third_party/base/stl_util.h" 38 39 namespace { 40 41 const uint8_t g_sRGBSamples1[] = { 42 0, 3, 6, 10, 13, 15, 18, 20, 22, 23, 25, 27, 28, 30, 31, 43 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 44 48, 49, 49, 50, 51, 52, 53, 53, 54, 55, 56, 56, 57, 58, 58, 45 59, 60, 61, 61, 62, 62, 63, 64, 64, 65, 66, 66, 67, 67, 68, 46 68, 69, 70, 70, 71, 71, 72, 72, 73, 73, 74, 74, 75, 76, 76, 47 77, 77, 78, 78, 79, 79, 79, 80, 80, 81, 81, 82, 82, 83, 83, 48 84, 84, 85, 85, 85, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90, 49 90, 91, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95, 96, 50 96, 97, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101, 51 102, 102, 102, 103, 103, 103, 104, 104, 104, 105, 105, 106, 106, 106, 107, 52 107, 107, 108, 108, 108, 109, 109, 109, 110, 110, 110, 110, 111, 111, 111, 53 112, 112, 112, 113, 113, 113, 114, 114, 114, 115, 115, 115, 115, 116, 116, 54 116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119, 120, 55 }; 56 57 const uint8_t g_sRGBSamples2[] = { 58 120, 121, 122, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 59 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 60 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 159, 160, 161, 162, 61 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 62 174, 175, 175, 176, 177, 178, 178, 179, 180, 180, 181, 182, 182, 183, 184, 63 185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193, 194, 64 194, 195, 196, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202, 203, 65 203, 204, 205, 205, 206, 206, 207, 208, 208, 209, 209, 210, 210, 211, 212, 66 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 218, 218, 219, 219, 220, 67 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 226, 226, 227, 227, 228, 68 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235, 235, 69 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240, 241, 241, 242, 242, 70 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 249, 249, 71 250, 250, 251, 251, 251, 252, 252, 253, 253, 254, 254, 255, 255, 72 }; 73 74 class CPDF_CalGray : public CPDF_ColorSpace { 75 public: 76 explicit CPDF_CalGray(CPDF_Document* pDoc); 77 ~CPDF_CalGray() override {} 78 79 // CPDF_ColorSpace: 80 uint32_t v_Load(CPDF_Document* pDoc, 81 CPDF_Array* pArray, 82 std::set<CPDF_Object*>* pVisited) override; 83 bool GetRGB(float* pBuf, float* R, float* G, float* B) const override; 84 void TranslateImageLine(uint8_t* pDestBuf, 85 const uint8_t* pSrcBuf, 86 int pixels, 87 int image_width, 88 int image_height, 89 bool bTransMask) const override; 90 91 private: 92 float m_WhitePoint[3]; 93 float m_BlackPoint[3]; 94 float m_Gamma; 95 }; 96 97 class CPDF_CalRGB : public CPDF_ColorSpace { 98 public: 99 explicit CPDF_CalRGB(CPDF_Document* pDoc); 100 ~CPDF_CalRGB() override {} 101 102 uint32_t v_Load(CPDF_Document* pDoc, 103 CPDF_Array* pArray, 104 std::set<CPDF_Object*>* pVisited) override; 105 106 bool GetRGB(float* pBuf, float* R, float* G, float* B) const override; 107 108 void TranslateImageLine(uint8_t* pDestBuf, 109 const uint8_t* pSrcBuf, 110 int pixels, 111 int image_width, 112 int image_height, 113 bool bTransMask) const override; 114 115 float m_WhitePoint[3]; 116 float m_BlackPoint[3]; 117 float m_Gamma[3]; 118 float m_Matrix[9]; 119 bool m_bGamma; 120 bool m_bMatrix; 121 }; 122 123 class CPDF_LabCS : public CPDF_ColorSpace { 124 public: 125 explicit CPDF_LabCS(CPDF_Document* pDoc); 126 ~CPDF_LabCS() override {} 127 128 uint32_t v_Load(CPDF_Document* pDoc, 129 CPDF_Array* pArray, 130 std::set<CPDF_Object*>* pVisited) override; 131 132 void GetDefaultValue(int iComponent, 133 float* value, 134 float* min, 135 float* max) const override; 136 bool GetRGB(float* pBuf, float* R, float* G, float* B) const override; 137 138 void TranslateImageLine(uint8_t* pDestBuf, 139 const uint8_t* pSrcBuf, 140 int pixels, 141 int image_width, 142 int image_height, 143 bool bTransMask) const override; 144 145 float m_WhitePoint[3]; 146 float m_BlackPoint[3]; 147 float m_Ranges[4]; 148 }; 149 150 class CPDF_ICCBasedCS : public CPDF_ColorSpace { 151 public: 152 explicit CPDF_ICCBasedCS(CPDF_Document* pDoc); 153 ~CPDF_ICCBasedCS() override; 154 155 // CPDF_ColorSpace: 156 uint32_t v_Load(CPDF_Document* pDoc, 157 CPDF_Array* pArray, 158 std::set<CPDF_Object*>* pVisited) override; 159 bool GetRGB(float* pBuf, float* R, float* G, float* B) const override; 160 void EnableStdConversion(bool bEnabled) override; 161 void TranslateImageLine(uint8_t* pDestBuf, 162 const uint8_t* pSrcBuf, 163 int pixels, 164 int image_width, 165 int image_height, 166 bool bTransMask) const override; 167 168 bool IsSRGB() const { return m_pProfile->IsSRGB(); } 169 170 private: 171 // If no valid ICC profile or using sRGB, try looking for an alternate. 172 bool FindAlternateProfile(CPDF_Document* pDoc, 173 CPDF_Dictionary* pDict, 174 std::set<CPDF_Object*>* pVisited, 175 uint32_t nExpectedComponents); 176 static CPDF_ColorSpace* GetStockAlternateProfile(uint32_t nComponents); 177 static bool IsValidComponents(int32_t nComps); 178 static std::vector<float> GetRanges(CPDF_Dictionary* pDict, 179 uint32_t nComponents); 180 181 MaybeOwned<CPDF_ColorSpace> m_pAlterCS; 182 RetainPtr<CPDF_IccProfile> m_pProfile; 183 mutable std::unique_ptr<uint8_t, FxFreeDeleter> m_pCache; 184 std::vector<float> m_pRanges; 185 }; 186 187 class CPDF_IndexedCS : public CPDF_ColorSpace { 188 public: 189 explicit CPDF_IndexedCS(CPDF_Document* pDoc); 190 ~CPDF_IndexedCS() override; 191 192 uint32_t v_Load(CPDF_Document* pDoc, 193 CPDF_Array* pArray, 194 std::set<CPDF_Object*>* pVisited) override; 195 196 bool GetRGB(float* pBuf, float* R, float* G, float* B) const override; 197 198 void EnableStdConversion(bool bEnabled) override; 199 200 CPDF_ColorSpace* m_pBaseCS = nullptr; 201 UnownedPtr<CPDF_CountedColorSpace> m_pCountedBaseCS; 202 uint32_t m_nBaseComponents = 0; 203 int m_MaxIndex = 0; 204 ByteString m_Table; 205 float* m_pCompMinMax = nullptr; 206 }; 207 208 class CPDF_SeparationCS : public CPDF_ColorSpace { 209 public: 210 explicit CPDF_SeparationCS(CPDF_Document* pDoc); 211 ~CPDF_SeparationCS() override; 212 213 // CPDF_ColorSpace: 214 void GetDefaultValue(int iComponent, 215 float* value, 216 float* min, 217 float* max) const override; 218 uint32_t v_Load(CPDF_Document* pDoc, 219 CPDF_Array* pArray, 220 std::set<CPDF_Object*>* pVisited) override; 221 bool GetRGB(float* pBuf, float* R, float* G, float* B) const override; 222 void EnableStdConversion(bool bEnabled) override; 223 224 std::unique_ptr<CPDF_ColorSpace> m_pAltCS; 225 std::unique_ptr<CPDF_Function> m_pFunc; 226 enum { None, All, Colorant } m_Type; 227 }; 228 229 class CPDF_DeviceNCS : public CPDF_ColorSpace { 230 public: 231 explicit CPDF_DeviceNCS(CPDF_Document* pDoc); 232 ~CPDF_DeviceNCS() override; 233 234 // CPDF_ColorSpace: 235 void GetDefaultValue(int iComponent, 236 float* value, 237 float* min, 238 float* max) const override; 239 uint32_t v_Load(CPDF_Document* pDoc, 240 CPDF_Array* pArray, 241 std::set<CPDF_Object*>* pVisited) override; 242 bool GetRGB(float* pBuf, float* R, float* G, float* B) const override; 243 void EnableStdConversion(bool bEnabled) override; 244 245 std::unique_ptr<CPDF_ColorSpace> m_pAltCS; 246 std::unique_ptr<CPDF_Function> m_pFunc; 247 }; 248 249 class Vector_3by1 { 250 public: 251 Vector_3by1() : a(0.0f), b(0.0f), c(0.0f) {} 252 253 Vector_3by1(float a1, float b1, float c1) : a(a1), b(b1), c(c1) {} 254 255 float a; 256 float b; 257 float c; 258 }; 259 260 class Matrix_3by3 { 261 public: 262 Matrix_3by3() 263 : a(0.0f), 264 b(0.0f), 265 c(0.0f), 266 d(0.0f), 267 e(0.0f), 268 f(0.0f), 269 g(0.0f), 270 h(0.0f), 271 i(0.0f) {} 272 273 Matrix_3by3(float a1, 274 float b1, 275 float c1, 276 float d1, 277 float e1, 278 float f1, 279 float g1, 280 float h1, 281 float i1) 282 : a(a1), b(b1), c(c1), d(d1), e(e1), f(f1), g(g1), h(h1), i(i1) {} 283 284 Matrix_3by3 Inverse() { 285 float det = a * (e * i - f * h) - b * (i * d - f * g) + c * (d * h - e * g); 286 if (fabs(det) < std::numeric_limits<float>::epsilon()) 287 return Matrix_3by3(); 288 289 return Matrix_3by3( 290 (e * i - f * h) / det, -(b * i - c * h) / det, (b * f - c * e) / det, 291 -(d * i - f * g) / det, (a * i - c * g) / det, -(a * f - c * d) / det, 292 (d * h - e * g) / det, -(a * h - b * g) / det, (a * e - b * d) / det); 293 } 294 295 Matrix_3by3 Multiply(const Matrix_3by3& m) { 296 return Matrix_3by3(a * m.a + b * m.d + c * m.g, a * m.b + b * m.e + c * m.h, 297 a * m.c + b * m.f + c * m.i, d * m.a + e * m.d + f * m.g, 298 d * m.b + e * m.e + f * m.h, d * m.c + e * m.f + f * m.i, 299 g * m.a + h * m.d + i * m.g, g * m.b + h * m.e + i * m.h, 300 g * m.c + h * m.f + i * m.i); 301 } 302 303 Vector_3by1 TransformVector(const Vector_3by1& v) { 304 return Vector_3by1(a * v.a + b * v.b + c * v.c, d * v.a + e * v.b + f * v.c, 305 g * v.a + h * v.b + i * v.c); 306 } 307 308 float a; 309 float b; 310 float c; 311 float d; 312 float e; 313 float f; 314 float g; 315 float h; 316 float i; 317 }; 318 319 float RGB_Conversion(float colorComponent) { 320 colorComponent = pdfium::clamp(colorComponent, 0.0f, 1.0f); 321 int scale = std::max(static_cast<int>(colorComponent * 1023), 0); 322 if (scale < 192) 323 return g_sRGBSamples1[scale] / 255.0f; 324 return g_sRGBSamples2[scale / 4 - 48] / 255.0f; 325 } 326 327 void XYZ_to_sRGB(float X, float Y, float Z, float* R, float* G, float* B) { 328 float R1 = 3.2410f * X - 1.5374f * Y - 0.4986f * Z; 329 float G1 = -0.9692f * X + 1.8760f * Y + 0.0416f * Z; 330 float B1 = 0.0556f * X - 0.2040f * Y + 1.0570f * Z; 331 332 *R = RGB_Conversion(R1); 333 *G = RGB_Conversion(G1); 334 *B = RGB_Conversion(B1); 335 } 336 337 void XYZ_to_sRGB_WhitePoint(float X, 338 float Y, 339 float Z, 340 float Xw, 341 float Yw, 342 float Zw, 343 float* R, 344 float* G, 345 float* B) { 346 // The following RGB_xyz is based on 347 // sRGB value {Rx,Ry}={0.64, 0.33}, {Gx,Gy}={0.30, 0.60}, {Bx,By}={0.15, 0.06} 348 349 float Rx = 0.64f, Ry = 0.33f; 350 float Gx = 0.30f, Gy = 0.60f; 351 float Bx = 0.15f, By = 0.06f; 352 Matrix_3by3 RGB_xyz(Rx, Gx, Bx, Ry, Gy, By, 1 - Rx - Ry, 1 - Gx - Gy, 353 1 - Bx - By); 354 Vector_3by1 whitePoint(Xw, Yw, Zw); 355 Vector_3by1 XYZ(X, Y, Z); 356 357 Vector_3by1 RGB_Sum_XYZ = RGB_xyz.Inverse().TransformVector(whitePoint); 358 Matrix_3by3 RGB_SUM_XYZ_DIAG(RGB_Sum_XYZ.a, 0, 0, 0, RGB_Sum_XYZ.b, 0, 0, 0, 359 RGB_Sum_XYZ.c); 360 Matrix_3by3 M = RGB_xyz.Multiply(RGB_SUM_XYZ_DIAG); 361 Vector_3by1 RGB = M.Inverse().TransformVector(XYZ); 362 363 *R = RGB_Conversion(RGB.a); 364 *G = RGB_Conversion(RGB.b); 365 *B = RGB_Conversion(RGB.c); 366 } 367 368 } // namespace 369 370 // static 371 CPDF_ColorSpace* CPDF_ColorSpace::ColorspaceFromName(const ByteString& name) { 372 if (name == "DeviceRGB" || name == "RGB") 373 return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB); 374 if (name == "DeviceGray" || name == "G") 375 return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICEGRAY); 376 if (name == "DeviceCMYK" || name == "CMYK") 377 return CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK); 378 if (name == "Pattern") 379 return CPDF_ColorSpace::GetStockCS(PDFCS_PATTERN); 380 return nullptr; 381 } 382 383 // static 384 CPDF_ColorSpace* CPDF_ColorSpace::GetStockCS(int family) { 385 return CPDF_ModuleMgr::Get()->GetPageModule()->GetStockCS(family); 386 } 387 388 // static 389 std::unique_ptr<CPDF_ColorSpace> CPDF_ColorSpace::Load(CPDF_Document* pDoc, 390 CPDF_Object* pObj) { 391 std::set<CPDF_Object*> visited; 392 return Load(pDoc, pObj, &visited); 393 } 394 395 // static 396 std::unique_ptr<CPDF_ColorSpace> CPDF_ColorSpace::Load( 397 CPDF_Document* pDoc, 398 CPDF_Object* pObj, 399 std::set<CPDF_Object*>* pVisited) { 400 if (!pObj) 401 return nullptr; 402 403 if (pObj->IsName()) { 404 return std::unique_ptr<CPDF_ColorSpace>( 405 ColorspaceFromName(pObj->GetString())); 406 } 407 if (CPDF_Stream* pStream = pObj->AsStream()) { 408 CPDF_Dictionary* pDict = pStream->GetDict(); 409 if (!pDict) 410 return nullptr; 411 412 for (const auto& it : *pDict) { 413 std::unique_ptr<CPDF_ColorSpace> pRet; 414 CPDF_Object* pValue = it.second.get(); 415 if (ToName(pValue)) 416 pRet.reset(ColorspaceFromName(pValue->GetString())); 417 if (pRet) 418 return pRet; 419 } 420 return nullptr; 421 } 422 423 CPDF_Array* pArray = pObj->AsArray(); 424 if (!pArray || pArray->IsEmpty()) 425 return nullptr; 426 427 CPDF_Object* pFamilyObj = pArray->GetDirectObjectAt(0); 428 if (!pFamilyObj) 429 return nullptr; 430 431 ByteString familyname = pFamilyObj->GetString(); 432 if (pArray->GetCount() == 1) 433 return std::unique_ptr<CPDF_ColorSpace>(ColorspaceFromName(familyname)); 434 435 std::unique_ptr<CPDF_ColorSpace> pCS; 436 switch (familyname.GetID()) { 437 case FXBSTR_ID('C', 'a', 'l', 'G'): 438 pCS.reset(new CPDF_CalGray(pDoc)); 439 break; 440 case FXBSTR_ID('C', 'a', 'l', 'R'): 441 pCS.reset(new CPDF_CalRGB(pDoc)); 442 break; 443 case FXBSTR_ID('L', 'a', 'b', 0): 444 pCS.reset(new CPDF_LabCS(pDoc)); 445 break; 446 case FXBSTR_ID('I', 'C', 'C', 'B'): 447 pCS.reset(new CPDF_ICCBasedCS(pDoc)); 448 break; 449 case FXBSTR_ID('I', 'n', 'd', 'e'): 450 case FXBSTR_ID('I', 0, 0, 0): 451 pCS.reset(new CPDF_IndexedCS(pDoc)); 452 break; 453 case FXBSTR_ID('S', 'e', 'p', 'a'): 454 pCS.reset(new CPDF_SeparationCS(pDoc)); 455 break; 456 case FXBSTR_ID('D', 'e', 'v', 'i'): 457 pCS.reset(new CPDF_DeviceNCS(pDoc)); 458 break; 459 case FXBSTR_ID('P', 'a', 't', 't'): 460 pCS.reset(new CPDF_PatternCS(pDoc)); 461 break; 462 default: 463 return nullptr; 464 } 465 pCS->m_pArray = pArray; 466 pCS->m_nComponents = pCS->v_Load(pDoc, pArray, pVisited); 467 if (pCS->m_nComponents == 0) 468 return nullptr; 469 470 return pCS; 471 } 472 473 void CPDF_ColorSpace::Release() { 474 if (this == GetStockCS(PDFCS_DEVICERGB) || 475 this == GetStockCS(PDFCS_DEVICEGRAY) || 476 this == GetStockCS(PDFCS_DEVICECMYK) || 477 this == GetStockCS(PDFCS_PATTERN)) { 478 return; 479 } 480 delete this; 481 } 482 483 int CPDF_ColorSpace::GetBufSize() const { 484 if (m_Family == PDFCS_PATTERN) 485 return sizeof(PatternValue); 486 return m_nComponents * sizeof(float); 487 } 488 489 float* CPDF_ColorSpace::CreateBuf() { 490 int size = GetBufSize(); 491 return reinterpret_cast<float*>(FX_Alloc(uint8_t, size)); 492 } 493 494 void CPDF_ColorSpace::GetDefaultColor(float* buf) const { 495 if (!buf || m_Family == PDFCS_PATTERN) 496 return; 497 498 float min; 499 float max; 500 for (uint32_t i = 0; i < m_nComponents; i++) 501 GetDefaultValue(i, &buf[i], &min, &max); 502 } 503 504 uint32_t CPDF_ColorSpace::CountComponents() const { 505 return m_nComponents; 506 } 507 508 void CPDF_ColorSpace::GetDefaultValue(int iComponent, 509 float* value, 510 float* min, 511 float* max) const { 512 *value = 0.0f; 513 *min = 0.0f; 514 *max = 1.0f; 515 } 516 517 void CPDF_ColorSpace::TranslateImageLine(uint8_t* dest_buf, 518 const uint8_t* src_buf, 519 int pixels, 520 int image_width, 521 int image_height, 522 bool bTransMask) const { 523 CFX_FixedBufGrow<float, 16> srcbuf(m_nComponents); 524 float* src = srcbuf; 525 float R; 526 float G; 527 float B; 528 const int divisor = m_Family != PDFCS_INDEXED ? 255 : 1; 529 for (int i = 0; i < pixels; i++) { 530 for (uint32_t j = 0; j < m_nComponents; j++) 531 src[j] = static_cast<float>(*src_buf++) / divisor; 532 GetRGB(src, &R, &G, &B); 533 *dest_buf++ = static_cast<int32_t>(B * 255); 534 *dest_buf++ = static_cast<int32_t>(G * 255); 535 *dest_buf++ = static_cast<int32_t>(R * 255); 536 } 537 } 538 539 void CPDF_ColorSpace::EnableStdConversion(bool bEnabled) { 540 if (bEnabled) 541 m_dwStdConversion++; 542 else if (m_dwStdConversion) 543 m_dwStdConversion--; 544 } 545 546 CPDF_ColorSpace::CPDF_ColorSpace(CPDF_Document* pDoc, int family) 547 : m_pDocument(pDoc), m_Family(family) {} 548 549 CPDF_ColorSpace::~CPDF_ColorSpace() {} 550 551 void CPDF_ColorSpace::SetComponentsForStockCS(uint32_t nComponents) { 552 ASSERT(!m_pDocument); // Stock colorspace is not associated with a document. 553 m_nComponents = nComponents; 554 } 555 556 CPDF_CalGray::CPDF_CalGray(CPDF_Document* pDoc) 557 : CPDF_ColorSpace(pDoc, PDFCS_CALGRAY) {} 558 559 uint32_t CPDF_CalGray::v_Load(CPDF_Document* pDoc, 560 CPDF_Array* pArray, 561 std::set<CPDF_Object*>* pVisited) { 562 CPDF_Dictionary* pDict = pArray->GetDictAt(1); 563 if (!pDict) 564 return 0; 565 566 CPDF_Array* pParam = pDict->GetArrayFor("WhitePoint"); 567 for (int i = 0; i < 3; i++) 568 m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0; 569 570 pParam = pDict->GetArrayFor("BlackPoint"); 571 for (int i = 0; i < 3; i++) 572 m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0; 573 574 m_Gamma = pDict->GetNumberFor("Gamma"); 575 if (m_Gamma == 0) 576 m_Gamma = 1.0f; 577 return 1; 578 } 579 580 bool CPDF_CalGray::GetRGB(float* pBuf, float* R, float* G, float* B) const { 581 *R = *pBuf; 582 *G = *pBuf; 583 *B = *pBuf; 584 return true; 585 } 586 587 void CPDF_CalGray::TranslateImageLine(uint8_t* pDestBuf, 588 const uint8_t* pSrcBuf, 589 int pixels, 590 int image_width, 591 int image_height, 592 bool bTransMask) const { 593 for (int i = 0; i < pixels; i++) { 594 *pDestBuf++ = pSrcBuf[i]; 595 *pDestBuf++ = pSrcBuf[i]; 596 *pDestBuf++ = pSrcBuf[i]; 597 } 598 } 599 600 CPDF_CalRGB::CPDF_CalRGB(CPDF_Document* pDoc) 601 : CPDF_ColorSpace(pDoc, PDFCS_CALRGB) {} 602 603 uint32_t CPDF_CalRGB::v_Load(CPDF_Document* pDoc, 604 CPDF_Array* pArray, 605 std::set<CPDF_Object*>* pVisited) { 606 CPDF_Dictionary* pDict = pArray->GetDictAt(1); 607 if (!pDict) 608 return 0; 609 610 CPDF_Array* pParam = pDict->GetArrayFor("WhitePoint"); 611 for (int i = 0; i < 3; i++) 612 m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0; 613 614 pParam = pDict->GetArrayFor("BlackPoint"); 615 for (int i = 0; i < 3; i++) 616 m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0; 617 618 pParam = pDict->GetArrayFor("Gamma"); 619 if (pParam) { 620 m_bGamma = true; 621 for (int i = 0; i < 3; i++) 622 m_Gamma[i] = pParam->GetNumberAt(i); 623 } else { 624 m_bGamma = false; 625 } 626 627 pParam = pDict->GetArrayFor("Matrix"); 628 if (pParam) { 629 m_bMatrix = true; 630 for (int i = 0; i < 9; i++) 631 m_Matrix[i] = pParam->GetNumberAt(i); 632 } else { 633 m_bMatrix = false; 634 } 635 return 3; 636 } 637 638 bool CPDF_CalRGB::GetRGB(float* pBuf, float* R, float* G, float* B) const { 639 float A_ = pBuf[0]; 640 float B_ = pBuf[1]; 641 float C_ = pBuf[2]; 642 if (m_bGamma) { 643 A_ = FXSYS_pow(A_, m_Gamma[0]); 644 B_ = FXSYS_pow(B_, m_Gamma[1]); 645 C_ = FXSYS_pow(C_, m_Gamma[2]); 646 } 647 648 float X; 649 float Y; 650 float Z; 651 if (m_bMatrix) { 652 X = m_Matrix[0] * A_ + m_Matrix[3] * B_ + m_Matrix[6] * C_; 653 Y = m_Matrix[1] * A_ + m_Matrix[4] * B_ + m_Matrix[7] * C_; 654 Z = m_Matrix[2] * A_ + m_Matrix[5] * B_ + m_Matrix[8] * C_; 655 } else { 656 X = A_; 657 Y = B_; 658 Z = C_; 659 } 660 XYZ_to_sRGB_WhitePoint(X, Y, Z, m_WhitePoint[0], m_WhitePoint[1], 661 m_WhitePoint[2], R, G, B); 662 return true; 663 } 664 665 void CPDF_CalRGB::TranslateImageLine(uint8_t* pDestBuf, 666 const uint8_t* pSrcBuf, 667 int pixels, 668 int image_width, 669 int image_height, 670 bool bTransMask) const { 671 if (bTransMask) { 672 float Cal[3]; 673 float R; 674 float G; 675 float B; 676 for (int i = 0; i < pixels; i++) { 677 Cal[0] = static_cast<float>(pSrcBuf[2]) / 255; 678 Cal[1] = static_cast<float>(pSrcBuf[1]) / 255; 679 Cal[2] = static_cast<float>(pSrcBuf[0]) / 255; 680 GetRGB(Cal, &R, &G, &B); 681 pDestBuf[0] = FXSYS_round(B * 255); 682 pDestBuf[1] = FXSYS_round(G * 255); 683 pDestBuf[2] = FXSYS_round(R * 255); 684 pSrcBuf += 3; 685 pDestBuf += 3; 686 } 687 } 688 ReverseRGB(pDestBuf, pSrcBuf, pixels); 689 } 690 691 CPDF_LabCS::CPDF_LabCS(CPDF_Document* pDoc) 692 : CPDF_ColorSpace(pDoc, PDFCS_LAB) {} 693 694 void CPDF_LabCS::GetDefaultValue(int iComponent, 695 float* value, 696 float* min, 697 float* max) const { 698 ASSERT(iComponent < 3); 699 if (iComponent == 0) { 700 *min = 0.0f; 701 *max = 100 * 1.0f; 702 *value = 0.0f; 703 return; 704 } 705 706 *min = m_Ranges[iComponent * 2 - 2]; 707 *max = m_Ranges[iComponent * 2 - 1]; 708 *value = pdfium::clamp(0.0f, *min, *max); 709 } 710 711 uint32_t CPDF_LabCS::v_Load(CPDF_Document* pDoc, 712 CPDF_Array* pArray, 713 std::set<CPDF_Object*>* pVisited) { 714 CPDF_Dictionary* pDict = pArray->GetDictAt(1); 715 if (!pDict) 716 return 0; 717 718 CPDF_Array* pParam = pDict->GetArrayFor("WhitePoint"); 719 for (int i = 0; i < 3; i++) 720 m_WhitePoint[i] = pParam ? pParam->GetNumberAt(i) : 0; 721 722 pParam = pDict->GetArrayFor("BlackPoint"); 723 for (int i = 0; i < 3; i++) 724 m_BlackPoint[i] = pParam ? pParam->GetNumberAt(i) : 0; 725 726 pParam = pDict->GetArrayFor("Range"); 727 const float kDefaultRanges[4] = {-100.0f, 100.0f, -100.0f, 100.0f}; 728 for (size_t i = 0; i < FX_ArraySize(kDefaultRanges); i++) 729 m_Ranges[i] = pParam ? pParam->GetNumberAt(i) : kDefaultRanges[i]; 730 return 3; 731 } 732 733 bool CPDF_LabCS::GetRGB(float* pBuf, float* R, float* G, float* B) const { 734 float Lstar = pBuf[0]; 735 float astar = pBuf[1]; 736 float bstar = pBuf[2]; 737 float M = (Lstar + 16.0f) / 116.0f; 738 float L = M + astar / 500.0f; 739 float N = M - bstar / 200.0f; 740 float X; 741 float Y; 742 float Z; 743 if (L < 0.2069f) 744 X = 0.957f * 0.12842f * (L - 0.1379f); 745 else 746 X = 0.957f * L * L * L; 747 748 if (M < 0.2069f) 749 Y = 0.12842f * (M - 0.1379f); 750 else 751 Y = M * M * M; 752 753 if (N < 0.2069f) 754 Z = 1.0889f * 0.12842f * (N - 0.1379f); 755 else 756 Z = 1.0889f * N * N * N; 757 758 XYZ_to_sRGB(X, Y, Z, R, G, B); 759 return true; 760 } 761 762 void CPDF_LabCS::TranslateImageLine(uint8_t* pDestBuf, 763 const uint8_t* pSrcBuf, 764 int pixels, 765 int image_width, 766 int image_height, 767 bool bTransMask) const { 768 for (int i = 0; i < pixels; i++) { 769 float lab[3]; 770 lab[0] = pSrcBuf[0] * 100 / 255.0f; 771 lab[1] = pSrcBuf[1] - 128; 772 lab[2] = pSrcBuf[2] - 128; 773 774 float R; 775 float G; 776 float B; 777 GetRGB(lab, &R, &G, &B); 778 pDestBuf[0] = static_cast<int32_t>(B * 255); 779 pDestBuf[1] = static_cast<int32_t>(G * 255); 780 pDestBuf[2] = static_cast<int32_t>(R * 255); 781 pDestBuf += 3; 782 pSrcBuf += 3; 783 } 784 } 785 786 CPDF_ICCBasedCS::CPDF_ICCBasedCS(CPDF_Document* pDoc) 787 : CPDF_ColorSpace(pDoc, PDFCS_ICCBASED) {} 788 789 CPDF_ICCBasedCS::~CPDF_ICCBasedCS() { 790 if (m_pProfile && m_pDocument) { 791 CPDF_Stream* pStream = m_pProfile->GetStream(); 792 m_pProfile.Reset(); // Give up our reference first. 793 auto* pPageData = m_pDocument->GetPageData(); 794 if (pPageData) 795 pPageData->MaybePurgeIccProfile(pStream); 796 } 797 } 798 799 uint32_t CPDF_ICCBasedCS::v_Load(CPDF_Document* pDoc, 800 CPDF_Array* pArray, 801 std::set<CPDF_Object*>* pVisited) { 802 CPDF_Stream* pStream = pArray->GetStreamAt(1); 803 if (!pStream) 804 return 0; 805 806 // The PDF 1.7 spec says the number of components must be valid. While some 807 // PDF viewers tolerate invalid values, Acrobat does not, so be consistent 808 // with Acrobat and reject bad values. 809 CPDF_Dictionary* pDict = pStream->GetDict(); 810 int32_t nDictComponents = pDict ? pDict->GetIntegerFor("N") : 0; 811 if (!IsValidComponents(nDictComponents)) 812 return 0; 813 814 uint32_t nComponents = static_cast<uint32_t>(nDictComponents); 815 m_pProfile = pDoc->LoadIccProfile(pStream); 816 if (!m_pProfile) 817 return 0; 818 819 // The PDF 1.7 spec also says the number of components in the ICC profile 820 // must match the N value. However, that assumes the viewer actually 821 // understands the ICC profile. 822 // If the valid ICC profile has a mismatch, fail. 823 if (m_pProfile->IsValid() && m_pProfile->GetComponents() != nComponents) 824 return 0; 825 826 // If PDFium does not understand the ICC profile format at all, or if it's 827 // SRGB, a profile PDFium recognizes but does not support well, then try the 828 // alternate profile. 829 if (!m_pProfile->IsSupported() && 830 !FindAlternateProfile(pDoc, pDict, pVisited, nComponents)) { 831 // If there is no alternate profile, use a stock profile as mentioned in 832 // the PDF 1.7 spec in table 4.16 in the "Alternate" key description. 833 ASSERT(!m_pAlterCS); 834 m_pAlterCS = GetStockAlternateProfile(nComponents); 835 } 836 837 m_pRanges = GetRanges(pDict, nComponents); 838 return nComponents; 839 } 840 841 bool CPDF_ICCBasedCS::GetRGB(float* pBuf, float* R, float* G, float* B) const { 842 ASSERT(m_pProfile); 843 if (IsSRGB()) { 844 *R = pBuf[0]; 845 *G = pBuf[1]; 846 *B = pBuf[2]; 847 return true; 848 } 849 if (m_pProfile->transform()) { 850 float rgb[3]; 851 CCodec_IccModule* pIccModule = CPDF_ModuleMgr::Get()->GetIccModule(); 852 pIccModule->SetComponents(CountComponents()); 853 pIccModule->Translate(m_pProfile->transform(), pBuf, rgb); 854 *R = rgb[0]; 855 *G = rgb[1]; 856 *B = rgb[2]; 857 return true; 858 } 859 860 if (m_pAlterCS) 861 return m_pAlterCS->GetRGB(pBuf, R, G, B); 862 863 *R = 0.0f; 864 *G = 0.0f; 865 *B = 0.0f; 866 return true; 867 } 868 869 void CPDF_ICCBasedCS::EnableStdConversion(bool bEnabled) { 870 CPDF_ColorSpace::EnableStdConversion(bEnabled); 871 if (m_pAlterCS) 872 m_pAlterCS->EnableStdConversion(bEnabled); 873 } 874 875 void CPDF_ICCBasedCS::TranslateImageLine(uint8_t* pDestBuf, 876 const uint8_t* pSrcBuf, 877 int pixels, 878 int image_width, 879 int image_height, 880 bool bTransMask) const { 881 if (IsSRGB()) { 882 ReverseRGB(pDestBuf, pSrcBuf, pixels); 883 return; 884 } 885 if (!m_pProfile->transform()) { 886 if (m_pAlterCS) { 887 m_pAlterCS->TranslateImageLine(pDestBuf, pSrcBuf, pixels, image_width, 888 image_height, false); 889 } 890 return; 891 } 892 893 // |nMaxColors| will not overflow since |nComponents| is limited in size. 894 const uint32_t nComponents = CountComponents(); 895 ASSERT(IsValidComponents(nComponents)); 896 int nMaxColors = 1; 897 for (uint32_t i = 0; i < nComponents; i++) 898 nMaxColors *= 52; 899 900 bool bTranslate = nComponents > 3; 901 if (!bTranslate) { 902 FX_SAFE_INT32 nPixelCount = image_width; 903 nPixelCount *= image_height; 904 if (nPixelCount.IsValid()) 905 bTranslate = nPixelCount.ValueOrDie() < nMaxColors * 3 / 2; 906 } 907 if (bTranslate) { 908 CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline( 909 m_pProfile->transform(), pDestBuf, pSrcBuf, pixels); 910 return; 911 } 912 913 if (!m_pCache) { 914 m_pCache.reset(FX_Alloc2D(uint8_t, nMaxColors, 3)); 915 std::unique_ptr<uint8_t, FxFreeDeleter> temp_src( 916 FX_Alloc2D(uint8_t, nMaxColors, nComponents)); 917 uint8_t* pSrc = temp_src.get(); 918 for (int i = 0; i < nMaxColors; i++) { 919 uint32_t color = i; 920 uint32_t order = nMaxColors / 52; 921 for (uint32_t c = 0; c < nComponents; c++) { 922 *pSrc++ = static_cast<uint8_t>(color / order * 5); 923 color %= order; 924 order /= 52; 925 } 926 } 927 CPDF_ModuleMgr::Get()->GetIccModule()->TranslateScanline( 928 m_pProfile->transform(), m_pCache.get(), temp_src.get(), nMaxColors); 929 } 930 uint8_t* pCachePtr = m_pCache.get(); 931 for (int i = 0; i < pixels; i++) { 932 int index = 0; 933 for (uint32_t c = 0; c < nComponents; c++) { 934 index = index * 52 + (*pSrcBuf) / 5; 935 pSrcBuf++; 936 } 937 index *= 3; 938 *pDestBuf++ = pCachePtr[index]; 939 *pDestBuf++ = pCachePtr[index + 1]; 940 *pDestBuf++ = pCachePtr[index + 2]; 941 } 942 } 943 944 bool CPDF_ICCBasedCS::FindAlternateProfile(CPDF_Document* pDoc, 945 CPDF_Dictionary* pDict, 946 std::set<CPDF_Object*>* pVisited, 947 uint32_t nExpectedComponents) { 948 CPDF_Object* pAlterCSObj = pDict->GetDirectObjectFor("Alternate"); 949 if (!pAlterCSObj) 950 return false; 951 952 auto pAlterCS = CPDF_ColorSpace::Load(pDoc, pAlterCSObj, pVisited); 953 if (!pAlterCS) 954 return false; 955 956 if (pAlterCS->GetFamily() == PDFCS_PATTERN) 957 return false; 958 959 if (pAlterCS->CountComponents() != nExpectedComponents) 960 return false; 961 962 m_pAlterCS = std::move(pAlterCS); 963 return true; 964 } 965 966 // static 967 CPDF_ColorSpace* CPDF_ICCBasedCS::GetStockAlternateProfile( 968 uint32_t nComponents) { 969 if (nComponents == 1) 970 return GetStockCS(PDFCS_DEVICEGRAY); 971 if (nComponents == 3) 972 return GetStockCS(PDFCS_DEVICERGB); 973 if (nComponents == 4) 974 return GetStockCS(PDFCS_DEVICECMYK); 975 NOTREACHED(); 976 return nullptr; 977 } 978 979 // static 980 bool CPDF_ICCBasedCS::IsValidComponents(int32_t nComps) { 981 return nComps == 1 || nComps == 3 || nComps == 4; 982 } 983 984 // static 985 std::vector<float> CPDF_ICCBasedCS::GetRanges(CPDF_Dictionary* pDict, 986 uint32_t nComponents) { 987 ASSERT(IsValidComponents(nComponents)); 988 989 std::vector<float> ranges; 990 ranges.reserve(nComponents * 2); 991 CPDF_Array* pRanges = pDict->GetArrayFor("Range"); 992 if (pRanges) { 993 for (uint32_t i = 0; i < nComponents * 2; i++) { 994 ranges.push_back(pRanges->GetNumberAt(i)); 995 } 996 } else { 997 for (uint32_t i = 0; i < nComponents; i++) { 998 ranges.push_back(0.0f); 999 ranges.push_back(1.0f); 1000 } 1001 } 1002 return ranges; 1003 } 1004 1005 CPDF_IndexedCS::CPDF_IndexedCS(CPDF_Document* pDoc) 1006 : CPDF_ColorSpace(pDoc, PDFCS_INDEXED) {} 1007 1008 CPDF_IndexedCS::~CPDF_IndexedCS() { 1009 FX_Free(m_pCompMinMax); 1010 CPDF_ColorSpace* pCS = m_pCountedBaseCS ? m_pCountedBaseCS->get() : nullptr; 1011 if (pCS && m_pDocument) { 1012 auto* pPageData = m_pDocument->GetPageData(); 1013 if (pPageData) 1014 pPageData->ReleaseColorSpace(pCS->GetArray()); 1015 } 1016 } 1017 1018 uint32_t CPDF_IndexedCS::v_Load(CPDF_Document* pDoc, 1019 CPDF_Array* pArray, 1020 std::set<CPDF_Object*>* pVisited) { 1021 if (pArray->GetCount() < 4) 1022 return 0; 1023 1024 CPDF_Object* pBaseObj = pArray->GetDirectObjectAt(1); 1025 if (pBaseObj == m_pArray) 1026 return 0; 1027 1028 CPDF_DocPageData* pDocPageData = pDoc->GetPageData(); 1029 m_pBaseCS = pDocPageData->GetColorSpaceGuarded(pBaseObj, nullptr, pVisited); 1030 if (!m_pBaseCS) 1031 return 0; 1032 1033 // The base color space cannot be a Pattern or Indexed space, according to the 1034 // PDF 1.7 spec, page 263. 1035 int family = m_pBaseCS->GetFamily(); 1036 if (family == PDFCS_INDEXED || family == PDFCS_PATTERN) 1037 return 0; 1038 1039 m_pCountedBaseCS = pDocPageData->FindColorSpacePtr(m_pBaseCS->GetArray()); 1040 m_nBaseComponents = m_pBaseCS->CountComponents(); 1041 m_pCompMinMax = FX_Alloc2D(float, m_nBaseComponents, 2); 1042 float defvalue; 1043 for (uint32_t i = 0; i < m_nBaseComponents; i++) { 1044 m_pBaseCS->GetDefaultValue(i, &defvalue, &m_pCompMinMax[i * 2], 1045 &m_pCompMinMax[i * 2 + 1]); 1046 m_pCompMinMax[i * 2 + 1] -= m_pCompMinMax[i * 2]; 1047 } 1048 m_MaxIndex = pArray->GetIntegerAt(2); 1049 1050 CPDF_Object* pTableObj = pArray->GetDirectObjectAt(3); 1051 if (!pTableObj) 1052 return 0; 1053 1054 if (CPDF_String* pString = pTableObj->AsString()) { 1055 m_Table = pString->GetString(); 1056 } else if (CPDF_Stream* pStream = pTableObj->AsStream()) { 1057 auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(pStream); 1058 pAcc->LoadAllDataFiltered(); 1059 m_Table = ByteStringView(pAcc->GetData(), pAcc->GetSize()); 1060 } 1061 return 1; 1062 } 1063 1064 bool CPDF_IndexedCS::GetRGB(float* pBuf, float* R, float* G, float* B) const { 1065 int32_t index = static_cast<int32_t>(*pBuf); 1066 if (index < 0 || index > m_MaxIndex) 1067 return false; 1068 1069 if (m_nBaseComponents) { 1070 FX_SAFE_SIZE_T length = index; 1071 length += 1; 1072 length *= m_nBaseComponents; 1073 if (!length.IsValid() || length.ValueOrDie() > m_Table.GetLength()) { 1074 *R = 0; 1075 *G = 0; 1076 *B = 0; 1077 return false; 1078 } 1079 } 1080 CFX_FixedBufGrow<float, 16> Comps(m_nBaseComponents); 1081 float* comps = Comps; 1082 const uint8_t* pTable = m_Table.raw_str(); 1083 for (uint32_t i = 0; i < m_nBaseComponents; i++) { 1084 comps[i] = 1085 m_pCompMinMax[i * 2] + 1086 m_pCompMinMax[i * 2 + 1] * pTable[index * m_nBaseComponents + i] / 255; 1087 } 1088 return m_pBaseCS->GetRGB(comps, R, G, B); 1089 } 1090 1091 void CPDF_IndexedCS::EnableStdConversion(bool bEnabled) { 1092 CPDF_ColorSpace::EnableStdConversion(bEnabled); 1093 if (m_pBaseCS) 1094 m_pBaseCS->EnableStdConversion(bEnabled); 1095 } 1096 1097 CPDF_SeparationCS::CPDF_SeparationCS(CPDF_Document* pDoc) 1098 : CPDF_ColorSpace(pDoc, PDFCS_SEPARATION) {} 1099 1100 CPDF_SeparationCS::~CPDF_SeparationCS() {} 1101 1102 void CPDF_SeparationCS::GetDefaultValue(int iComponent, 1103 float* value, 1104 float* min, 1105 float* max) const { 1106 *value = 1.0f; 1107 *min = 0; 1108 *max = 1.0f; 1109 } 1110 1111 uint32_t CPDF_SeparationCS::v_Load(CPDF_Document* pDoc, 1112 CPDF_Array* pArray, 1113 std::set<CPDF_Object*>* pVisited) { 1114 ByteString name = pArray->GetStringAt(1); 1115 if (name == "None") { 1116 m_Type = None; 1117 return 1; 1118 } 1119 1120 m_Type = Colorant; 1121 CPDF_Object* pAltCS = pArray->GetDirectObjectAt(2); 1122 if (pAltCS == m_pArray) 1123 return 0; 1124 1125 m_pAltCS = Load(pDoc, pAltCS, pVisited); 1126 if (!m_pAltCS) 1127 return 0; 1128 1129 if (m_pAltCS->IsSpecial()) 1130 return 0; 1131 1132 CPDF_Object* pFuncObj = pArray->GetDirectObjectAt(3); 1133 if (pFuncObj && !pFuncObj->IsName()) { 1134 auto pFunc = CPDF_Function::Load(pFuncObj); 1135 if (pFunc && pFunc->CountOutputs() >= m_pAltCS->CountComponents()) 1136 m_pFunc = std::move(pFunc); 1137 } 1138 return 1; 1139 } 1140 1141 bool CPDF_SeparationCS::GetRGB(float* pBuf, 1142 float* R, 1143 float* G, 1144 float* B) const { 1145 if (m_Type == None) 1146 return false; 1147 1148 if (!m_pFunc) { 1149 if (!m_pAltCS) 1150 return false; 1151 1152 int nComps = m_pAltCS->CountComponents(); 1153 CFX_FixedBufGrow<float, 16> results(nComps); 1154 for (int i = 0; i < nComps; i++) 1155 results[i] = *pBuf; 1156 return m_pAltCS->GetRGB(results, R, G, B); 1157 } 1158 1159 CFX_FixedBufGrow<float, 16> results(m_pFunc->CountOutputs()); 1160 int nresults = 0; 1161 m_pFunc->Call(pBuf, 1, results, &nresults); 1162 if (nresults == 0) 1163 return false; 1164 1165 if (m_pAltCS) 1166 return m_pAltCS->GetRGB(results, R, G, B); 1167 1168 R = 0; 1169 G = 0; 1170 B = 0; 1171 return false; 1172 } 1173 1174 void CPDF_SeparationCS::EnableStdConversion(bool bEnabled) { 1175 CPDF_ColorSpace::EnableStdConversion(bEnabled); 1176 if (m_pAltCS) 1177 m_pAltCS->EnableStdConversion(bEnabled); 1178 } 1179 1180 CPDF_DeviceNCS::CPDF_DeviceNCS(CPDF_Document* pDoc) 1181 : CPDF_ColorSpace(pDoc, PDFCS_DEVICEN) {} 1182 1183 CPDF_DeviceNCS::~CPDF_DeviceNCS() {} 1184 1185 void CPDF_DeviceNCS::GetDefaultValue(int iComponent, 1186 float* value, 1187 float* min, 1188 float* max) const { 1189 *value = 1.0f; 1190 *min = 0; 1191 *max = 1.0f; 1192 } 1193 1194 uint32_t CPDF_DeviceNCS::v_Load(CPDF_Document* pDoc, 1195 CPDF_Array* pArray, 1196 std::set<CPDF_Object*>* pVisited) { 1197 CPDF_Array* pObj = ToArray(pArray->GetDirectObjectAt(1)); 1198 if (!pObj) 1199 return 0; 1200 1201 CPDF_Object* pAltCS = pArray->GetDirectObjectAt(2); 1202 if (!pAltCS || pAltCS == m_pArray) 1203 return 0; 1204 1205 m_pAltCS = Load(pDoc, pAltCS, pVisited); 1206 m_pFunc = CPDF_Function::Load(pArray->GetDirectObjectAt(3)); 1207 if (!m_pAltCS || !m_pFunc) 1208 return 0; 1209 1210 if (m_pAltCS->IsSpecial()) 1211 return 0; 1212 1213 if (m_pFunc->CountOutputs() < m_pAltCS->CountComponents()) 1214 return 0; 1215 1216 return pObj->GetCount(); 1217 } 1218 1219 bool CPDF_DeviceNCS::GetRGB(float* pBuf, float* R, float* G, float* B) const { 1220 if (!m_pFunc) 1221 return false; 1222 1223 CFX_FixedBufGrow<float, 16> results(m_pFunc->CountOutputs()); 1224 int nresults = 0; 1225 m_pFunc->Call(pBuf, CountComponents(), results, &nresults); 1226 if (nresults == 0) 1227 return false; 1228 1229 return m_pAltCS->GetRGB(results, R, G, B); 1230 } 1231 1232 void CPDF_DeviceNCS::EnableStdConversion(bool bEnabled) { 1233 CPDF_ColorSpace::EnableStdConversion(bEnabled); 1234 if (m_pAltCS) { 1235 m_pAltCS->EnableStdConversion(bEnabled); 1236 } 1237 } 1238