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