Fix JPEG2000 image decoding with an indexed colorspace
Fix a regression in JPEG2000 image decoding, where the PDF specifies an
indexed colorspace for a grayscale JPEG2000 image. Add a test case for
this, where the JPEG2000 started as a PNG with a 2-bit colormap. The PNG
then gets converted to JPEG2000 using Imagemagick as follows:
convert input.png -colorspace Gray output.jp2
Bug: 393395940
Change-Id: I1a0265091a5ce906d3461fb803984c7345f6fe8e
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/128390
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp
index 4e2dc2c..fa2e93c 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -109,6 +109,7 @@
kFail,
kDoNothing,
kUseGray,
+ kUseIndexed,
kUseRgb,
kUseCmyk,
kConvertArgbToRgb,
@@ -169,6 +170,11 @@
return JpxDecodeAction::kConvertArgbToRgb;
}
+ if (pdf_colorspace->GetFamily() == CPDF_ColorSpace::Family::kIndexed &&
+ pdf_colorspace->ComponentCount() == 1) {
+ return JpxDecodeAction::kUseIndexed;
+ }
+
return JpxDecodeAction::kDoNothing;
}
@@ -690,6 +696,9 @@
CPDF_ColorSpace::GetStockCS(CPDF_ColorSpace::Family::kDeviceGray);
break;
+ case JpxDecodeAction::kUseIndexed:
+ break;
+
case JpxDecodeAction::kUseRgb:
DCHECK(image_info.channels >= 3);
swap_rgb = true;
@@ -705,6 +714,7 @@
swap_rgb = true;
convert_argb_to_rgb = true;
m_pColorSpace.Reset();
+ break;
}
// If |original_colorspace| exists, then LoadColorInfo() already set
@@ -720,7 +730,8 @@
}
FXDIB_Format format;
- if (action == JpxDecodeAction::kUseGray) {
+ if (action == JpxDecodeAction::kUseGray ||
+ action == JpxDecodeAction::kUseIndexed) {
format = FXDIB_Format::k8bppRgb;
} else if (action == JpxDecodeAction::kUseRgb && image_info.channels == 3) {
format = FXDIB_Format::kBgr;
diff --git a/testing/resources/pixel/jpxdecode_indexed.in b/testing/resources/pixel/jpxdecode_indexed.in
new file mode 100644
index 0000000..a48b3fe
--- /dev/null
+++ b/testing/resources/pixel/jpxdecode_indexed.in
@@ -0,0 +1,56 @@
+{{header}}
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+{{object 2 0}} <<
+ /Type /Pages
+ /Count 1
+ /Kids [3 0 R]
+>>
+endobj
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /Contents 4 0 R
+ /MediaBox [0 0 100 100]
+ /Resources <<
+ /XObject <<
+ /ImIndexed 5 0 R
+ >>
+ >>
+>>
+endobj
+{{object 4 0}} <<
+ {{streamlen}}
+>>
+stream
+q
+100 0 0 100 0 0 cm
+/ImIndexed Do
+Q
+endstream
+endobj
+{{object 5 0}} <<
+ /Type /XObject
+ /Subtype /Image
+ /BitsPerComponent 2
+ /ColorSpace [/Indexed /DeviceRGB 3 <FF0000 00FF00 0000FF FFFFFF>]
+ /Filter [/ASCII85Decode /FlateDecode /JPXDecode]
+ /Height 100
+ /Width 100
+ {{streamlen}}
+>>
+stream
+GhQY8@,T-6:f-*3C?K&6?k>m[W@Z+?0N%nV)5+>hONmjS@[S)_76im;N#<Md6#%83POijQ(r8m3+FXJn
+SG_:EIis@j==aW5@/uS=#R(0[(jJ;>#$)KT#0-Zt%)NJU&eYPmk^Nql.KcGe;/0Q3C5P>UV1O1_C7\LW
+X1L]$C/Jt_I\).RSuJ<trs9*=?t2!Dk"NK>+ipUkFJA?:G!Q=(g$'.Gk;o_=PS-2d/n_?"s4"Mag#u\E
+Pt?fuiTVVs8bHLN(acDfc[SuFAFj8b!9[jIk3qk7DL!d^DPGK$K,;`Lg^R$i><T%6lb<4I4obOV!,hd6
+3<~>
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/jpxdecode_indexed_expected.pdf.0.png b/testing/resources/pixel/jpxdecode_indexed_expected.pdf.0.png
new file mode 100644
index 0000000..1660af1
--- /dev/null
+++ b/testing/resources/pixel/jpxdecode_indexed_expected.pdf.0.png
Binary files differ