Skip to content

feat(exporters): css, style rules for one export - #559

Closed
jackskip22 wants to merge 1 commit into
zumerlab:mainfrom
jackskip22:export-css
Closed

jackskip22 wants to merge 1 commit into
zumerlab:mainfrom
jackskip22:export-css

Conversation

@jackskip22

Copy link
Copy Markdown
Contributor

An export can now take css, alongside crop: style rules for that export only. The capture is not touched.

await result.toPng({ css: '.hit{outline:3px solid #f0f!important}' })

The rules go in a cascade layer declared first in the engine's <style> so a rule needs !important and then wins over the page's style sheets. Plugins can add rules in beforeExport or draw a styled copy with ctx.exports.canvas({ ...opts, css }). A raster capture rejects it, like it does for a crop.

A plugin cannot do this from ctx.export.url which holds the capture's downsampled images, while exports larger than the capture draw the restored originals. It would also have to redo the exporter's crop and Safari's shadow fix.

Happy to change anything! This came from working on capture upgrades for rapier-jxl 8.4.0 and finding that screenshots with text on top of photos come out ~12% smaller when the encoder knows exactly where the text is. The 8.4.0 plugin draws the capture a second time with the text transparent to find it. This CSS option would also be handy for export-only styling without touching the live page like hiding controls, highlights, watermarks, dark versions.

One related fix added: Safari's shadow rewrite now keeps a $ pattern in a style rule. Adds api.exports.css.test.js and the type pins.

Every exporter now takes `css`: style rules for that export only, in a
cascade layer declared first in the engine's <style>, so `!important`
wins over the page's style sheets. Without it nothing changes, and a
raster html-in-canvas capture rejects it as it rejects a crop. The
Safari shadow rewrite now keeps a `$` pattern in a style rule. Adds
api.exports.css.test.js and the type pins.
@tinchox5

Copy link
Copy Markdown
Member

Great Let me review it!

@tinchox5

Copy link
Copy Markdown
Member

Thanks Jack, really nice work, and the 12% on text over photos is a great find.

I'd rather not add a public export option for this, though. The plugin can get there on its own with one mask draw instead of a second full copy: insert this right after the first <style> tag of ctx.export.url, draw it at the export's size, and the alpha is your text map.

@layer snapdom-mask{*{color:#fff!important;-webkit-text-fill-color:#fff!important;background:none!important;
border-color:transparent!important;box-shadow:none!important;text-shadow:none!important;outline:none!important}
img,video,canvas,iframe,foreignObject svg{visibility:hidden!important}}

I tried it on your stripes scene in Chromium, Firefox and WebKit at 1x, dpr 2, width 400, scale 3 and with a crop. It covers every pixel your two-draw diff finds, and it also catches gradient text and white-on-white text, which a diff can't see. The compressed images don't matter because they're hidden, and the crop is a source rect in drawImage. Two things to watch: on WebKit, when the page has a box-shadow the regular export is resampled, so dilate the mask by a pixel or two; and in real Safari a fresh SVG can come back blank on its first draw (WebKit #219770), so check the mask isn't empty and draw again.

The $ fix in the shadow rewrite is a real bug on its own. Could you send it as a separate PR? I'll merge that right away.

@jackskip22

Copy link
Copy Markdown
Contributor Author

Thanks so much for taking the time to test that and I should have gone with that from the start! I tried it early but didn't test it properly and thought it wouldn't work. Your mask is now in the plugin along with the Safari tips and I'll open a PR for that in the next couple of days when it moves to npm jpegxl with 8.4.0. I'll close this one and open the $ fix now

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.

2 participants