Extend the JPEG BGR decode to ICCBased color spaces with sRGB profiles For an ICCBased color space whose profile is recognized as sRGB, CPDF_ICCBasedCS::TranslateImageLine() is exactly fxcodec::ReverseRGB(), the same per-pixel RGB-to-BGR swap that ShouldDecodeJpegToBgr() already folds into the decode for DeviceRGB and CalRGB. Accept that case too. The component-count equality mirrors the guard in TranslateScanline24bppDefaultDecode(), which only translates when the sample count matches the color space; profiles that are not supported fall back to the alternate color space's float conversion and profiles that need a real ICC transform keep using the translate path, so neither is captured. Bug: 553831655 Change-Id: I428ae3d08d9020db3aa8840323433c948d7b0ea8 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/156090 Commit-Queue: Tom Sepez <tsepez@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp index 72ee8d9..6ab8004 100644 --- a/core/fpdfapi/page/cpdf_dib.cpp +++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -16,6 +16,7 @@ #include "core/fpdfapi/page/cpdf_colorspace.h" #include "core/fpdfapi/page/cpdf_docpagedata.h" +#include "core/fpdfapi/page/cpdf_iccprofile.h" #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" #include "core/fpdfapi/page/cpdf_indexedcs.h" @@ -522,19 +523,39 @@ return LoadState::kSuccess; } +bool CPDF_DIB::ComponentCountMatchesColorSpace() const { + return color_space_ && components_ == color_space_->ComponentCount(); +} + // Whether the JPEG decoder should be asked to emit BGR-ordered scanlines. // Only true when GetScanline()'s only transformation of the decoded RGB // scanline would be TranslateScanline24bppDefaultDecode()'s per-pixel // RGB-to-BGR swap, which a BGR decode makes a pass-through: // - a default Decode array (no per-component decode arithmetic), // - no color key mask (its comparisons read components in R,G,B order), -// - plain DeviceRGB or CalRGB (both translate as the bare swap; every -// other family goes through CPDF_ColorSpace::TranslateImageLine()), +// - a color space whose whole translation is the bare swap: DeviceRGB, +// CalRGB, or ICCBased with an sRGB profile (whose TranslateImageLine() +// is exactly fxcodec::ReverseRGB()); every other case goes through a +// real conversion, // - 3 components at 8 bpc (the swap case). bool CPDF_DIB::ShouldDecodeJpegToBgr() const { - return default_decode_ && !color_key_ && components_ == 3 && bpc_ == 8 && - (family_ == CPDF_ColorSpace::Family::kDeviceRGB || - family_ == CPDF_ColorSpace::Family::kCalRGB); + if (!default_decode_ || color_key_ || components_ != 3 || bpc_ != 8) { + return false; + } + if (family_ == CPDF_ColorSpace::Family::kDeviceRGB || + family_ == CPDF_ColorSpace::Family::kCalRGB) { + return true; + } + // For an sRGB profile, CPDF_ICCBasedCS::TranslateImageLine() is exactly + // fxcodec::ReverseRGB(), so the whole translation is the swap. Any other + // profile converts through the alternate color space instead, which is not + // a swap, so those keep the translate path. + if (family_ == CPDF_ColorSpace::Family::kICCBased && + ComponentCountMatchesColorSpace()) { + RetainPtr<CPDF_IccProfile> profile = color_space_->GetIccProfile(); + return profile && profile->IsSRGB(); + } + return false; } bool CPDF_DIB::CreateDCTDecoder(pdfium::span<const uint8_t> src_span, @@ -1082,7 +1103,7 @@ return false; } - if (components_ == color_space_->ComponentCount()) { + if (ComponentCountMatchesColorSpace()) { color_space_->TranslateImageLine(dest_scan, src_scan, GetWidth(), GetWidth(), GetHeight(), TransMask()); }
diff --git a/core/fpdfapi/page/cpdf_dib.h b/core/fpdfapi/page/cpdf_dib.h index 491313e..737da04 100644 --- a/core/fpdfapi/page/cpdf_dib.h +++ b/core/fpdfapi/page/cpdf_dib.h
@@ -100,6 +100,12 @@ bool CreateDCTDecoder(pdfium::span<const uint8_t> src_span, const CPDF_Dictionary* pParams, uint8_t resolution_levels_to_skip); + // Whether `components_` matches the color space's own component count, which + // is the condition under which a scanline gets translated at all. The two + // can disagree because LoadColorInfo() overrides `components_` for an + // ICCBased color space named DeviceGray, DeviceRGB or DeviceCMYK. Returns + // false when there is no color space. + bool ComponentCountMatchesColorSpace() const; bool ShouldDecodeJpegToBgr() const; void TranslateScanline24bpp(pdfium::span<uint8_t> dest_scan, pdfium::span<const uint8_t> src_scan) const;