Skip to content

Fix/23953 transparency group blank conversion#17

Open
antobinary wants to merge 1 commit into
v3.0.x-developfrom
fix/23953-transparency-group-blank-conversion
Open

Fix/23953 transparency group blank conversion#17
antobinary wants to merge 1 commit into
v3.0.x-developfrom
fix/23953-transparency-group-blank-conversion

Conversation

@antobinary

Copy link
Copy Markdown
Owner

fix(presentation): render PDF transparency-group soft-mask images (bigbluebutton#23953)

Fixes #23953"[3.0] some specific embedded images in PDF are not converted".

What

Certain PDFs contain a figure (in the report: a black rectangle with a blurred/feathered edge, taken from default.pdf's icon-shadow artwork) that is silently dropped during presentation conversion. The slide uploads "successfully" but renders completely blank. Reproduces across browsers and BBB versions.

Why (root cause)

The figure lives inside a PDF transparency group (/Group /S /Transparency) as an image with a soft mask (/SMask) + an ICCBased colorspace. poppler's cairo backend fails to composite this construct and emits nothing for it.

BBB uses pdftocairo (cairo backend) for both conversion paths, so both fail:

  • Primary pdftocairo -svg: produces a well-formed SVG that renders blank in the browser (cairo represents the group as a nested <mask> + <filter> alpha→luminance construct that browsers evaluate to fully transparent).
  • Raster fallback pdftocairo -png: also blank — and it never even triggers here, because the blank SVG passes every existing threshold (image=3, path=5, use=5).

Verified with the exact file from the report:

Renderer Result
pdftocairo -svg (BBB primary) blank
pdftocairo -png (BBB raster fallback) blank
pdftoppm (poppler splash backend) renders correctly ✅
gs (Ghostscript) renders correctly ✅

So the bug is specific to poppler's cairo backend; the splash backend renders it correctly.

How (the fix)

Two-part fix in bbb-common-web:

  1. Trigger the raster fallback when the generated SVG contains a cairo transparency-group soft mask. We gate on the <filter> count, not <mask>:

    • cairo emits a <filter> (feColorMatrix alpha→luminance) only for the blanking transparency-group construct.
    • plain alpha images (e.g. a normal transparent PNG) emit <mask> with zero <filter> and render fine — gating on <mask> would needlessly rasterize them (measured: it broke the moderator-new-presentation snapshot; the <filter> gate does not).
    File <mask> <filter> Renders
    uploadTest.png (alpha PNG) 1 0 fine (stays vector)
    blurimage2.pdf (the bug) 2 2 was blank → now rasterized ✅
  2. Rasterize the fallback with pdftoppm (splash backend) instead of pdftocairo -png (cairo). -singlefile writes <root>.png, matching the existing temp-file handling — no other caller changes needed.

A configurable filterTagThreshold (default 0 = rasterize any slide with such a group) is wired through doc-conversion.xml / bigbluebutton.properties; the Java field defaults to 0 so behaviour is correct even without the XML wiring.

History / how it was found & verified

  1. Downloaded blurimage2.pdf from the issue; pdfimages showed an image + smask + ICCBased colorspace.
  2. Ran BBB's exact commands locally and on the dev server (poppler 22.02 and 24.02): pdftocairo -svg and -png both blank; gs and pdftoppm correct.
  3. Reproduced end-to-end on the dev server via the create API (base64-embedded doc) and confirmed in bbb-web.log: conversion reported "1 of 1 pages successfully converted" while the generated slide1.svg rendered blank.
  4. Added a Playwright regression test → confirmed it fails on the unmodified build (0 dark pixels; blank Slide 1 screenshot).
  5. Applied the fix, hot-deployed to the dev server, re-ran the test → passes; visually confirmed the black rectangle now renders.
  6. Regression check: default-presentation navigation tests pass; the two upload-snapshot tests fail identically on the original unmodified jar (pre-existing environmental snapshot drift — these screenshots are already CI-skipped), so they are unrelated to this change; tsc + eslint clean.

Test

bigbluebutton-tests/playwright/presentation/presentation.spec.ts"Upload PDF with embedded soft-masked image renders (not blank)"

  • Fixture: bigbluebutton-tests/playwright/core/media/blurImage.pdf (the file from the report)
  • Helper getCurrentSlideDarkPixelRatio() fetches the slide SVG through the authenticated context, rasterizes it in-page via a same-origin blob URL onto a canvas (avoids canvas tainting), and asserts the near-black-pixel ratio > 0.02. Blank slide → 0 (fail); fixed → ~0.1 (pass).
npx playwright test -g "embedded soft-masked image" --project=chromium

Files changed

  • bbb-common-web/.../presentation/imp/SvgImageCreatorImp.java<filter> trigger + createRasterizationProcess() (pdftoppm)
  • bbb-common-web/.../presentation/handlers/SvgConversionHandler.javanumberOfFilterTags()
  • bigbluebutton-web/grails-app/conf/spring/doc-conversion.xml — wire filterTagThreshold
  • bigbluebutton-web/grails-app/conf/bigbluebutton.propertiesfilterTagThreshold=0 (documented)
  • bigbluebutton-tests/playwright/presentation/{presentation.spec.ts,presentation.ts,util.ts} — regression test + helper
  • bigbluebutton-tests/playwright/core/elements.ts — fixture filename constant
  • bigbluebutton-tests/playwright/core/media/blurImage.pdf — test fixture (new)

Notes for reviewers

  • filterTagThreshold=0 converts affected slides from vector to raster (only those containing the transparency-group soft mask). This is intended and safe (BBB already rasterizes for Type-3 fonts / high tag counts) and tunable.
  • default.pdf page 1 (the icon-shadow group) was also affected by this bug and now renders correctly.

TODO — remaining (same root cause, out of scope of this commit)

The identical cairo-blank bug affects two other call sites that still use pdftocairo -png. They produce a blank image for this PDF too and should be switched to pdftoppm:

  • bbb-common-web/.../presentation/imp/PngCreatorImp.java — the downloadable slide PNG
  • bbb-common-web/.../presentation/imp/ThumbnailCreatorImp.java — the slide thumbnail
  • (optional) add regression coverage for the download-PNG / thumbnail paths

…gbluebutton#23953)

Some PDFs embed a figure inside a transparency group whose image uses a
soft mask (SMask) with an ICCBased colorspace. poppler's cairo backend
fails to composite this construct, so both the primary `pdftocairo -svg`
conversion and the existing `pdftocairo -png` raster fallback produce a
blank result. The client reports the conversion as successful, so the
slide silently shows nothing (e.g. a black rectangle that never appears).

Fix, in bbb-common-web:

- Trigger the raster fallback when the generated SVG contains a cairo
  transparency-group soft mask. The blank SVG otherwise passes all
  existing thresholds (image/path/use counts). We gate on the <filter>
  count rather than <mask>: cairo emits a <filter> (alpha->luminance
  feColorMatrix) only for the blanking transparency-group construct,
  whereas plain alpha images emit <mask> with no <filter> and render
  fine -- so gating on <mask> would needlessly rasterize normal images.

- Rasterize the fallback with pdftoppm (poppler splash backend) instead
  of pdftocairo -png (cairo backend); splash composites the construct
  correctly. `-singlefile` writes "<root>.png", matching the existing
  temp-file handling.

Adds a configurable `filterTagThreshold` (default 0) wired in
doc-conversion.xml / bigbluebutton.properties.

Also adds a Playwright regression test that uploads the reported PDF and
asserts the rendered slide is not blank (dark-pixel ratio of the slide
image rasterized onto a canvas).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@antobinary
antobinary force-pushed the fix/23953-transparency-group-blank-conversion branch from e86d741 to ebb462f Compare July 18, 2026 01:59
@github-actions

Copy link
Copy Markdown

🚨 Automated tests failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[3.0] some specific embedded images in PDF are not converted

1 participant