Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gradients won't render as gradients in the PDF #5

Closed
wants to merge 3 commits into from
Closed

Gradients won't render as gradients in the PDF #5

wants to merge 3 commits into from

Conversation

henrikskar
Copy link
Contributor

Hi,

SVGs won't render in the PDF with simple gradients.
I added a method to fill the svg node to the first stop color and a test (test19.html) to the test folder.
Is there a way to make the svg2pdf.js render this simple gradient?

Best regards,
Henrik Skar

@TorsteinHonsi
Copy link
Contributor

TorsteinHonsi commented Sep 14, 2016

@henrikskar The bug is probably not related to the gradientTransform attribute as suggested in the pull request.

Two changes makes the gradient work in PDF:

  1. Add x1, x2, y1 and y2 arguments. These are usually added, but perhaps svgtopdf should have the same defaults as SVG.
  2. Set the stop-opacity to 1 on both stops. Seems liks opacity is handled incorrectly if supported at all.

Minimal, working code with current svg2pdf, modified from test19:

        <linearGradient id="MyGradient" x1="0" x2="0" y1="0" y2="1">
          <stop offset="0" stop-color="#7cb5ec" stop-opacity="1"/>
          <stop offset="1" stop-color="#ffffff" stop-opacity="1"/>
        </linearGradient>

@yGuy
Copy link
Member

yGuy commented Sep 15, 2016

Regarding opacity: AFAIK PDF does not support different opacities per gradient stop. A global opacity can be applied to the whole gradient, though. The only workaround is to precalculate the fill as a bitmap, which is costly both in terms of processing, resulting pdf size and quality. So we decided to not support opacity for gradients for now. Pull requests are welcome, of course.

@TorsteinHonsi
Copy link
Contributor

Thanks for your clarification @yGuy, that makes sense. It seems to leave us with some options:

  1. Apply a global opacity to the whole gradient, like svg2pdf.js currently does.
  2. Precalculate the fill as a bitmap. If I remember correctly, Batik uses this approach. In capable browsers, we could probably create an SVG with the filled shape only, draw it on a canvas, serialize it to PNG and add it to the PDF.
  3. Add a gradient only if all stops' opacity is 1. It seems like this is the approach PhantomJS is using when saving to PDF.
  4. If there's a stop with opacity 1, use that as the solid fill. Which would probably work best for our purpose.

If we want to implement this, could we add an option for it? Something in the lines of:

// render the svg element
svg2pdf(svgElement, pdf, {
    xOffset: 0,
    yOffset: 0,
    scale: 1,
    gradientOpacity: 'first-solid' // or 'bitmap', 'average'
});

@yGuy
Copy link
Member

yGuy commented Sep 16, 2016

I like the proposed API - we could discuss whether adding another level in between like this is more future-proof, but I don't really have a strong opinion here, now:

// render the svg element
svg2pdf(svgElement, pdf, {
    xOffset: 0,
    yOffset: 0,
    scale: 1,
    emulation: {
        gradientOpacity: 'first-solid' // or 'bitmap', 'average'
    }
});

... in general I like the idea of making this configurable that way instead of hard-coding a single logic.

@HackbrettXXX HackbrettXXX marked this pull request as draft December 11, 2023 09:13
@HackbrettXXX
Copy link
Member

Closing this, feel free to reopen ;)

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.

None yet

4 participants