Fix drawing of MMR general regions in JBIG2 images
CJBig2_Context::ParseGenericRegion() calls
page_->ComposeFromWithRect() with grd_->GetReplaceRect() as rect,
but for MMR images, GetReplaceRect() used to always return an
empty rect. That meant we decoded the image but then threw it away
when compositing it to the JBIG2 page.
To fix, set replace_rect_ to the whole bitmap at the end of MMR
decoding, similar to what ProgressiveDecodeArith() does.
Also add a few spec comments to FaxG4GetRow() (which I was reading while
debugging this.)
The test is a hand-draw bitmap that I converted to jbig2 format using
`jbig2` from the zip at https://www.itu.int/rec/T-REC-T.88-201808-I
I ran:
jbig2 -i bitmap -f bmp \
-o jbig2_mmr -F jb2 -ini jbig2-mmr.ini
with this jbig2-mmr.ini:
-Gen -Seg 1
-Gen -Param -Huff 1
I then ran the script linked to in the bug to convert it to a
PDF, and then manually edited it to convert it to .in format.
(Among other things, I ran the file through `xxd` and converted
the stream to /ASCIIHexDecode. I compared dumps from locally-added
hexdumping code and it looks like I didn't mess up the data.)
Bug: 432742364
Change-Id: I9df6c2c233ec89c439d0c813d9b67f64c36cd951
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/134270
Commit-Queue: Nico Weber <thakis@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Nico Weber <thakis@google.com>
diff --git a/core/fxcodec/fax/faxmodule.cpp b/core/fxcodec/fax/faxmodule.cpp
index c4d1a7b..f6d8c92 100644
--- a/core/fxcodec/fax/faxmodule.cpp
+++ b/core/fxcodec/fax/faxmodule.cpp
@@ -314,6 +314,7 @@
uint8_t* dest_buf,
pdfium::span<const uint8_t> ref_buf,
int columns) {
+ // See TABLE 1/T.6 "Code table" in ITU-T T.6.
int a0 = -1;
bool a0color = true;
while (true) {
@@ -340,8 +341,10 @@
bool bit2 = NextBit(src_buf, bitpos);
if (bit1) {
+ // Mode "Vertical", VR(1), VL(1).
v_delta = bit2 ? 1 : -1;
} else if (bit2) {
+ // Mode "Horizontal".
int run_len1 = 0;
while (true) {
int run = FaxGetRun(
@@ -400,6 +403,7 @@
}
if (NextBit(src_buf, bitpos)) {
+ // Mode "Pass".
if (!a0color) {
FaxFillBits(dest_buf, columns, a0, b2);
}
@@ -423,18 +427,21 @@
bool next_bit2 = NextBit(src_buf, bitpos);
if (next_bit1) {
+ // Mode "Vertical", VR(2), VL(2).
v_delta = next_bit2 ? 2 : -2;
} else if (next_bit2) {
if (*bitpos >= bitsize) {
return;
}
+ // Mode "Vertical", VR(3), VL(3).
v_delta = NextBit(src_buf, bitpos) ? 3 : -3;
} else {
if (*bitpos >= bitsize) {
return;
}
+ // Extension
if (NextBit(src_buf, bitpos)) {
*bitpos += 3;
continue;
@@ -443,6 +450,8 @@
return;
}
}
+ } else {
+ // Mode "Vertical", V(0).
}
a1 = b1 + v_delta;
if (!a0color) {
diff --git a/core/fxcodec/jbig2/JBig2_GrdProc.cpp b/core/fxcodec/jbig2/JBig2_GrdProc.cpp
index ba5a3da..8d68c9f 100644
--- a/core/fxcodec/jbig2/JBig2_GrdProc.cpp
+++ b/core/fxcodec/jbig2/JBig2_GrdProc.cpp
@@ -506,7 +506,12 @@
for (uint32_t i = 0; i < image->stride() * GBH; ++i) {
UNSAFE_TODO(image->data()[i] = ~image->data()[i]);
}
+
progressive_status_ = FXCODEC_STATUS::kDecodeFinished;
+ replace_rect_.left = 0;
+ replace_rect_.right = image->width();
+ replace_rect_.top = 0;
+ replace_rect_.bottom = image->height();
*pImage = std::move(image);
return progressive_status_;
}
diff --git a/testing/resources/pixel/jbig2_mmr.in b/testing/resources/pixel/jbig2_mmr.in
new file mode 100644
index 0000000..2174356
--- /dev/null
+++ b/testing/resources/pixel/jbig2_mmr.in
@@ -0,0 +1,80 @@
+{{header}}
+
+{{object 1 0}} <<
+ /Type /Catalog
+ /Pages 2 0 R
+>>
+endobj
+
+{{object 2 0}} <<
+ /Type /Pages
+ /Kids [3 0 R]
+ /Count 1
+>>
+endobj
+
+{{object 3 0}} <<
+ /Type /Page
+ /Parent 2 0 R
+ /MediaBox [0 0 399 400]
+ /Contents 4 0 R
+ /Resources <<
+ /XObject <<
+ /Im 5 0 R
+ >>
+ >>
+>>
+endobj
+
+{{object 4 0}} <<
+ {{streamlen}}
+>>
+stream
+399 0 0 400 0 0 cm
+/Im Do
+endstream
+endobj
+
+{{object 5 0}} <<
+ /Type /XObject
+ /Subtype /Image
+ /Width 399
+ /Height 400
+ /ColorSpace /DeviceGray
+ /Filter [/ASCIIHexDecode /JBIG2Decode]
+ /BitsPerComponent 1
+ {{streamlen}}
+>>
+stream
+0000 0000 3000 0100 0000 1300 0001 8f00
+0001 9000 0000 0000 0000 0001 0000 0000
+0001 2700 0100 0001 5800 0001 8f00 0001
+9000 0000 0000 0000 0002 01ff ffff ffff
+ffff ffff fcb7 81c2 218d 9a04 1d07 41e1
+d3c3 a0f7 bde1 ef77 ddf0 eddb 8786 e5bd
+034a 1b87 b72b b907 841b 7083 6e9b d30d
+fba6 dc9a 0fe1 069b 7083 de9a b74d 7eaf
+4edb ebd3 56fa dfdb eafd 36fa fd3b b5bf
+09f6 95be 17b4 136e d2bc 3093 7861 05b8
+abd3 b85b 84de 16e1 37ad c220 da3b b841
+6f5b b849 de12 bba0 9dba 0adf 4f74 15b7
+a7ba 56de 13be 15de b7d5 de13 be15 b761
+3f85 6dda 7f0a dbb0 9ded 6dc3 09b6 e185
+f16d bfdb 6fdd b7f7 def7 deef fb4f eed3
+f7b5 dae1 8570 c2e2 fffd dfff f77f ffff
+ffff ffff ffff ffff febe bafa afae abaa
+fad2 f4bd 2f09 5697 a5aa eaba aeab ad50
+5e95 694e e63e 1069 420c 1698 5a60 970b
+4c25 c2d3 0970 9709 70bd 7a5c 2da4 bada
+0970 95a0 82b4 1050 c208 2861 0414 4c82
+814a 1050 40a5 7540 3884 1420 a82a 0b54
+b0a8 2d6b 0b0b 0b0a c2c2 b0b0 ac82 891d
+8286 1432 3917 1fff ffff ffff ffff ffff
+fc >
+endstream
+endobj
+
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/jbig2_mmr_expected.pdf.0.png b/testing/resources/pixel/jbig2_mmr_expected.pdf.0.png
new file mode 100644
index 0000000..80cc33c
--- /dev/null
+++ b/testing/resources/pixel/jbig2_mmr_expected.pdf.0.png
Binary files differ