Skip to content

Add SVG mix-blend-mode support + fix gradient rendering#140

Merged
nicolaasuni merged 1 commit intotecnickcom:mainfrom
rcoenen:feature/svg-mix-blend-mode
Feb 25, 2026
Merged

Add SVG mix-blend-mode support + fix gradient rendering#140
nicolaasuni merged 1 commit intotecnickcom:mainfrom
rcoenen:feature/svg-mix-blend-mode

Conversation

@rcoenen
Copy link
Contributor

@rcoenen rcoenen commented Feb 24, 2026

Summary

Add SVG mix-blend-mode support and fix gradient rendering when exporting SVG → PDF.

Before (PDF render) After (PDF render)

Closes #139.

  • SVG mix-blend-mode support: Parse the CSS property from SVG style attributes and map all 16 CSS blend modes to their PDF /BM operator equivalents via the existing getAlpha() infrastructure.
  • Gradient stop color normalization: Named SVG colors (white, red, etc.) resolve to CMYK while hex colors (#FFFFFF, #00C147) resolve to RGB. When mixed in gradient stops, the PDF gradient breaks silently. All stop colors are now normalized to hex RGB.
  • Gradient forward reference pre-scan: Figma (and other tools) place <defs> at the end of the SVG. The single-pass parser couldn't resolve forward gradient references. A lightweight prescanSVGGradients() pre-parse now collects all gradient definitions before the main render pass.
  • Blend modes work on gradient fills: Moved blend mode detection before the gradient early return in parseSVGStyleFill() so /BM applies to gradient-filled elements too.

Test Input

Original SVG used for reproduction (exported from Figma): BlendModeTest.svg

Changes

  • src/SVG.php — all source changes (blend mode parsing, stop color fix, prescan method)
  • test/SvgBlendModeTest.php — 26 integration tests covering all blend modes, inheritance, gradient combinations
  • test/visual/BlendModeTest.svg + test/visual/blend-mode-smoke.php — visual smoke test with real Figma export

Test plan

  • All 26 unit/integration tests pass (vendor/bin/phpunit --no-coverage)
  • Visual smoke PDF matches reference SVG (blend modes + gradient rendering)
  • Unmodified Figma SVG export renders correctly (forward refs + named colors)

🤖 Generated with Claude Code

@rcoenen rcoenen requested a review from nicolaasuni as a code owner February 24, 2026 21:30
@CLAassistant
Copy link

CLAassistant commented Feb 24, 2026

CLA assistant check
All committers have signed the CLA.

- Parse mix-blend-mode CSS property from SVG style attributes and map all 16 CSS blend modes to PDF /BM operator equivalents via getAlpha()\n- Normalize gradient stop colors to hex RGB to prevent CMYK/RGB color space mismatch when mixing named and hex colors in gradient stops\n- Add prescanSVGGradients() to collect gradient definitions before the main render pass, fixing forward references in Figma SVG exports\n- Move blend mode detection before gradient early return so /BM applies to gradient-filled elements too\n- Preserve and combine opacity/fill-opacity/stroke-opacity when mix-blend-mode is enabled (avoid alpha clobbering from repeated ExtGState writes)\n- Add regression tests for blend mode + opacity combinations and keep prescan callbacks PHPMD/PHPStan clean\n- Add visual smoke test
@rcoenen rcoenen force-pushed the feature/svg-mix-blend-mode branch from 8fd246d to aa94d2f Compare February 24, 2026 22:11
@rcoenen
Copy link
Contributor Author

rcoenen commented Feb 24, 2026

Follow-up fix pushed: preserves effective SVG opacity when mix-blend-mode is enabled (previously repeated ExtGState writes could overwrite opacity / fill-opacity / stroke-opacity).

Also added regression tests for blend mode + opacity combinations and cleaned up prescanSVGGradients() callback typing/naming (PHPMD/PHPStan clean on touched files).

Validated locally:

  • phpunit test/SvgBlendModeTest.php ✅ (28 tests, 36 assertions)
  • targeted PHPStan on src/SVG.php + test/SvgBlendModeTest.php
  • visual smoke test regenerated ✅

@nicolaasuni nicolaasuni merged commit aa94d2f into tecnickcom:main Feb 25, 2026
1 check passed
@nicolaasuni
Copy link
Member

Thank you for your contribution.
I manually merged this after refactoring few parts.

@nicolaasuni
Copy link
Member

nicolaasuni commented Feb 25, 2026

I had to remove the SvgBlendModeTest.php as it is failing.
Tests in the test folder executed by phpunit should be pure unit tests. I plan to add them when the HTML part is complete.
Other tests, like the functional ones, should be separated and be able to run automatically in the current workflow.

@rcoenen rcoenen deleted the feature/svg-mix-blend-mode branch February 25, 2026 17:32
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.

SVG: add mix-blend-mode support + fix gradient rendering

3 participants