Handle a case of colorspace mismatch with JPEG2000 images.
Some PDFs generated on iOS have a mismatch between the PDF image
metadata and the JPEG2000 image metadata. Detect this case and do the
necessary image conversion.
Unsuppress a pixel test now that it renders correctly.
Bug: chromium:1012369
Change-Id: I36322a81ec70182d89f69b1f89d1af2bb4f2b106
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/65753
Commit-Queue: 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 6976a0d..9e73072 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -103,15 +103,24 @@
kDoNothing,
kUseRgb,
kUseCmyk,
+ kConvertArgbToRgb,
};
-JpxDecodeAction GetJpxDecodeAction(uint32_t jpx_components,
+JpxDecodeAction GetJpxDecodeAction(const CJPX_Decoder::JpxImageInfo& jpx_info,
const CPDF_ColorSpace* pdf_colorspace) {
if (pdf_colorspace) {
// Make sure the JPX image and the PDF colorspace agree on the number of
- // components.
- if (jpx_components != pdf_colorspace->CountComponents())
+ // components. In case of a mismatch, try to handle the discrepancy.
+ if (jpx_info.components != pdf_colorspace->CountComponents()) {
+ // Many PDFs generated by iOS meets this condition. See
+ // https://crbug.com/1012369 for example.
+ if (pdf_colorspace->CountComponents() == 3 && jpx_info.components == 4 &&
+ jpx_info.colorspace == OPJ_CLRSPC_SRGB) {
+ return JpxDecodeAction::kConvertArgbToRgb;
+ }
+
return JpxDecodeAction::kFail;
+ }
if (pdf_colorspace == CPDF_ColorSpace::GetStockCS(PDFCS_DEVICERGB))
return JpxDecodeAction::kUseRgb;
@@ -121,7 +130,7 @@
// Cases where the PDF did not provide a colorspace.
// Choose how to decode based on the number of components in the JPX image.
- switch (jpx_components) {
+ switch (jpx_info.components) {
case 3:
return JpxDecodeAction::kUseRgb;
@@ -632,7 +641,8 @@
RetainPtr<CPDF_ColorSpace> original_colorspace = m_pColorSpace;
bool swap_rgb = false;
- switch (GetJpxDecodeAction(image_info.components, m_pColorSpace.Get())) {
+ bool convert_argb_to_rgb = false;
+ switch (GetJpxDecodeAction(image_info, m_pColorSpace.Get())) {
case JpxDecodeAction::kFail:
return nullptr;
@@ -648,6 +658,11 @@
case JpxDecodeAction::kUseCmyk:
m_pColorSpace = CPDF_ColorSpace::GetStockCS(PDFCS_DEVICECMYK);
break;
+
+ case JpxDecodeAction::kConvertArgbToRgb:
+ swap_rgb = true;
+ convert_argb_to_rgb = true;
+ m_pColorSpace.Reset();
}
// If |original_colorspace| exists, then LoadColorInfo() already set
@@ -681,8 +696,26 @@
return nullptr;
}
- if (m_pColorSpace && m_pColorSpace->GetFamily() == PDFCS_INDEXED &&
- m_bpc < 8) {
+ if (convert_argb_to_rgb) {
+ DCHECK_EQ(3, m_nComponents);
+ auto rgb_bitmap = pdfium::MakeRetain<CFX_DIBitmap>();
+ if (!rgb_bitmap->Create(image_info.width, image_info.height, FXDIB_Rgb))
+ return nullptr;
+
+ // TODO(thestig): Is there existing code that does this already?
+ // TODO(crbug.com/pdfium/1469): Handle alpha channel.
+ for (uint32_t row = 0; row < image_info.height; ++row) {
+ const uint8_t* src = result_bitmap->GetScanline(row);
+ uint8_t* dest = rgb_bitmap->GetWritableScanline(row);
+ for (uint32_t col = 0; col < image_info.width; ++col) {
+ memcpy(dest, src, 3);
+ src += 4;
+ dest += 3;
+ }
+ }
+ result_bitmap = std::move(rgb_bitmap);
+ } else if (m_pColorSpace && m_pColorSpace->GetFamily() == PDFCS_INDEXED &&
+ m_bpc < 8) {
int scale = 8 - m_bpc;
for (uint32_t row = 0; row < image_info.height; ++row) {
uint8_t* scanline = result_bitmap->GetWritableScanline(row);
diff --git a/core/fxcodec/jpx/cjpx_decoder.cpp b/core/fxcodec/jpx/cjpx_decoder.cpp
index 95f76ff..29fb849 100644
--- a/core/fxcodec/jpx/cjpx_decoder.cpp
+++ b/core/fxcodec/jpx/cjpx_decoder.cpp
@@ -489,7 +489,7 @@
}
CJPX_Decoder::JpxImageInfo CJPX_Decoder::GetInfo() const {
- return {m_Image->x1, m_Image->y1, m_Image->numcomps};
+ return {m_Image->x1, m_Image->y1, m_Image->numcomps, m_Image->color_space};
}
bool CJPX_Decoder::Decode(uint8_t* dest_buf, uint32_t pitch, bool swap_rgb) {
diff --git a/core/fxcodec/jpx/cjpx_decoder.h b/core/fxcodec/jpx/cjpx_decoder.h
index 4d9883c..f0869c1 100644
--- a/core/fxcodec/jpx/cjpx_decoder.h
+++ b/core/fxcodec/jpx/cjpx_decoder.h
@@ -35,6 +35,7 @@
uint32_t width;
uint32_t height;
uint32_t components;
+ COLOR_SPACE colorspace;
};
static void Sycc420ToRgbForTesting(opj_image_t* img);
diff --git a/testing/SUPPRESSIONS b/testing/SUPPRESSIONS
index b3059e9..d8e0a2b 100644
--- a/testing/SUPPRESSIONS
+++ b/testing/SUPPRESSIONS
@@ -340,9 +340,6 @@
# TODO(chromium:451366): Remove after associated bug is fixed
bug_451366.in * * *
-# TODO(chromium:1012369): Remove after associated bug is fixed
-bug_1012369.in * * *
-
# xfa_specific
# TODO(pdfium:1107): Remove after associated bug is fixed