Correctly handle image transparency in path objects
When displaying an embedded image in a path object, the image's alpha
value needs to be multiplied with the alpha value defined in the path
object to ensure transparency is rendered correctly.
Bug: pdfium:2106
Change-Id: Ibaa8786b8a4e522c258590aed26a6779712d921d
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/118830
Reviewed-by: Lei Zhang <thestig@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
Commit-Queue: Thomas Sepez <tsepez@google.com>
diff --git a/AUTHORS b/AUTHORS
index 6e4b6e4..47c7538 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -38,6 +38,7 @@
Stefan Ziegler <sz5000@gmx.de>
Stephan Hartmann <stha09@googlemail.com>
Tibor Dusnoki <tdusnoki@inf.u-szeged.hu>
+Wang Chuan <jdyaomo@gmail.com>
Wang Qing <wangqing-hf@loongson.cn>
Zhuo Qingliang <zhuo.dev@gmail.com>
# END individuals section.
diff --git a/core/fpdfapi/render/cpdf_renderstatus.cpp b/core/fpdfapi/render/cpdf_renderstatus.cpp
index 9c2dd94..8e4d72f 100644
--- a/core/fpdfapi/render/cpdf_renderstatus.cpp
+++ b/core/fpdfapi/render/cpdf_renderstatus.cpp
@@ -584,6 +584,7 @@
}
RetainPtr<const CPDF_Dictionary> pFormResource;
float group_alpha = 1.0f;
+ float initial_alpha = 1.0f;
CPDF_Transparency transparency = m_Transparency;
bool bGroupTransparent = false;
const CPDF_FormObject* pFormObj = pPageObj->AsForm();
@@ -592,13 +593,14 @@
transparency = pFormObj->form()->GetTransparency();
bGroupTransparent = transparency.IsIsolated();
pFormResource = pFormObj->form()->GetDict()->GetDictFor("Resources");
+ initial_alpha = m_InitialStates.general_state().GetFillAlpha();
}
bool bTextClip =
(pPageObj->clip_path().HasRef() &&
pPageObj->clip_path().GetTextCount() > 0 && !m_bPrint &&
!(m_pDevice->GetDeviceCaps(FXDC_RENDER_CAPS) & FXRC_SOFT_CLIP));
if (!pSMaskDict && group_alpha == 1.0f && blend_type == BlendMode::kNormal &&
- !bTextClip && !bGroupTransparent) {
+ !bTextClip && !bGroupTransparent && initial_alpha == 1.0f) {
return false;
}
if (m_bPrint) {
@@ -693,6 +695,9 @@
bitmap_device.MultiplyAlpha(group_alpha);
}
transparency = m_Transparency;
+ if (initial_alpha != 1.0f) {
+ bitmap_device.MultiplyAlpha(initial_alpha);
+ }
if (pPageObj->IsForm()) {
transparency.SetGroup();
}
diff --git a/core/fpdfapi/render/cpdf_rendertiling.cpp b/core/fpdfapi/render/cpdf_rendertiling.cpp
index 90a963d..6b50893 100644
--- a/core/fpdfapi/render/cpdf_rendertiling.cpp
+++ b/core/fpdfapi/render/cpdf_rendertiling.cpp
@@ -122,9 +122,15 @@
if (width > clip_box.Width() || height > clip_box.Height() ||
width * height > clip_box.Width() * clip_box.Height()) {
std::unique_ptr<CPDF_GraphicStates> pStates;
- if (!pPattern->colored())
+ if (!pPattern->colored()) {
pStates = CPDF_RenderStatus::CloneObjStates(&pPageObj->graphic_states(),
bStroke);
+ } else if (pPageObj->AsPath()) {
+ pStates = std::make_unique<CPDF_GraphicStates>();
+ pStates->SetDefaultStates();
+ pStates->mutable_general_state().SetFillAlpha(
+ pPageObj->general_state().GetFillAlpha());
+ }
RetainPtr<const CPDF_Dictionary> pFormResource =
pPatternForm->GetDict()->GetDictFor("Resources");
diff --git a/testing/resources/pixel/bug_2106.in b/testing/resources/pixel/bug_2106.in
new file mode 100644
index 0000000..ad9bc35
--- /dev/null
+++ b/testing/resources/pixel/bug_2106.in
@@ -0,0 +1,110 @@
+{{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 200 200]
+ /Resources <<
+ /ExtGState <<
+ /GS0 6 0 R
+ >>
+ /Pattern <<
+ /Pa0 7 0 R
+ >>
+ >>
+>>
+endobj
+{{object 4 0}} <<
+ {{streamlen}}
+>>
+stream
+q /Pattern cs /Pa0 scn /GS0 gs 0 0 20 20 re f* Q
+endstream
+endobj
+{{object 5 0}} <<
+ /Type /ExtGState
+ /ca 1
+>>
+endobj
+{{object 6 0}} <<
+ /Type /ExtGState
+ /ca 0.5
+>>
+endobj
+{{object 7 0}} <<
+ /Type /Pattern
+ /Subtype /Form
+ /BBox [0 0 30 30]
+ {{streamlen}}
+ /PaintType 1
+ /PatternType 1
+ /Resources <<
+ /ExtGState <<
+ /GS0 5 0 R
+ >>
+ /XObject <<
+ /Fm0 8 0 R
+ >>
+ >>
+ /TilingType 3
+ /XStep 30
+ /YStep 30
+>>
+stream
+q 1 0 0 1 0 0 cm /GS0 gs /Fm0 Do Q
+endstream
+endobj
+{{object 8 0}} <<
+ /Type /Pattern
+ /Subtype /Form
+ /BBox [0 0 30 30]
+ {{streamlen}}
+ /PaintType 1
+ /PatternType 1
+ /Resources <<
+ /ExtGState <<
+ /GS0 5 0 R
+ >>
+ /XObject <<
+ /Fm0 9 0 R
+ >>
+ >>
+ /TilingType 3
+ /XStep 30
+ /YStep 30
+>>
+stream
+q 20 0 0 20 0 0 cm /GS0 gs /Fm0 Do Q
+endstream
+endobj
+{{object 9 0}} <<
+ /Type /XObject
+ /Subtype /Image
+ /ColorSpace /DeviceGray
+ /Width 20 /BitsPerComponent 8
+ {{streamlen}}
+ /Height 20
+ /Filter [/ASCII85Decode /DCTDecode]
+ /DecodeParms <</ColorTransform 0>>
+>>
+stream
+s4IA0!"_al8O`[\!<<*#!!*'"s4[N@!!<9(!WiE*!WiE*!s8W."p>&3"9\u7"pG2;#RUnF#RLeE$kEaR
+$P!ON#n7IU%M'*^&J,9X&eblh'+YWc&HBNG$O?_H!#,G7&HMjL!#5J7!<<*"zzz$3.pD'G(9Fzzz!!!$
+!g&MBZ!<<*a!0oeL&-(;~>
+endstream
+endobj
+{{xref}}
+{{trailer}}
+{{startxref}}
+%%EOF
diff --git a/testing/resources/pixel/bug_2106_expected.pdf.0.png b/testing/resources/pixel/bug_2106_expected.pdf.0.png
new file mode 100644
index 0000000..9117219
--- /dev/null
+++ b/testing/resources/pixel/bug_2106_expected.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_2106_expected_gdi_skia.pdf.0.png b/testing/resources/pixel/bug_2106_expected_gdi_skia.pdf.0.png
new file mode 100644
index 0000000..3d2e154
--- /dev/null
+++ b/testing/resources/pixel/bug_2106_expected_gdi_skia.pdf.0.png
Binary files differ
diff --git a/testing/resources/pixel/bug_2106_expected_skia.pdf.0.png b/testing/resources/pixel/bug_2106_expected_skia.pdf.0.png
new file mode 100644
index 0000000..3d2e154
--- /dev/null
+++ b/testing/resources/pixel/bug_2106_expected_skia.pdf.0.png
Binary files differ