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

Rasterizer doesn't render transparencies inside shapes #28

Closed
ricotheque opened this issue Mar 7, 2017 · 5 comments · Fixed by #136
Closed

Rasterizer doesn't render transparencies inside shapes #28

ricotheque opened this issue Mar 7, 2017 · 5 comments · Fixed by #136
Labels
bug Something isn't working
Milestone

Comments

@ricotheque
Copy link

ricotheque commented Mar 7, 2017

Tried rasterizing this search icon SVG. Ended up with this:

test

require_once( __DIR__ . '/php-svg-master/autoloader.php' );

use SVG\SVG;

$svg = 'source.svg';
$test = SVG::fromFile( $svg );

$raster_image = $test->toRasterImage( 36, 36 );

imagepng( $raster_image, 'test.png', 9 );
imagejpeg( $raster_image, 'test.jpg', 100 );

Is this a limitation of the GD rendering library?

@meyfa
Copy link
Owner

meyfa commented Mar 12, 2017

Thanks for opening this issue, I'm looking into it.

@meyfa
Copy link
Owner

meyfa commented Mar 12, 2017

The problem seems to stem from the fact that the rasterizer treats every subpath as being completely unrelated to the previous ones, without taking into account that SVG imposes certain fill rules for cases where subpaths overlap.

I have no idea yet how to fix this, but it definitely needs attention.

Thanks again for reporting the problem!

@winkbrace
Copy link

winkbrace commented May 10, 2019

Really unfortunate since this is quite an important requirement. It would have been so nice to be able to do this without phantom.js :/

I've tried to come up with a way to calculate the inner space and redraw a transparent layer over it, but that's rather difficult and won't even solve all cases. It's far easier to make the final transformation step with a nodejs tool like svg2png.

@andykirk
Copy link

I came across this issue and though I'd post my solution to rendering the PNG, using Imagick:

// Save the SVG first:
// ($image is the SVG as per docs, $svg_filename is the path and name of file to output)
file_put_contents($svg_filename, $image->toXMLString());

// Create a new Imagick:
$im = new Imagick();
$im->readImageBlob(file_get_contents($svg_filename));

// This is for PNG24, but can be any output Imagick supports:
$im->setImageFormat("png24");

// $png_filename is the file path and name for resultant raster image:
$im->writeImage($png_filename);
$im->clear();
$im->destroy();

Hope that helps someone.

Cheers

@meyfa meyfa mentioned this issue Oct 12, 2020
meyfa added a commit that referenced this issue Feb 19, 2022
Fixes #28. The time has finally come that I understand how scanline
algorithms work and was able to implement this by referencing an
existing implementation in the SerenityOS path renderer.

I did a lot of work to adapt that code to PHP and get it to perform as
well as possible. Note that for some images rendering still takes ages,
but that is not due to PathRenderer, rather the BezierApproximator does
not yet take scale into account and oftentimes generates curves with
waaaaay too many segments. I have done benchmarks and this rendering
algorithm is insanely efficient for what it does. If anything can be
optimized, it is probably the looping over and transforming of each
point during preparation.
@meyfa
Copy link
Owner

meyfa commented Feb 19, 2022

This will probably come as a surprise to everyone involved (myself included), but I finally implemented this. See PR #136.
The icon now renders just fine using the exact same code from above:

search

I'd thank you for your patience, but I doubt this is still useful to any of the original participants of this discussion. Still it will hopefully benefit people that ran into this more recently!

meyfa added a commit that referenced this issue Feb 19, 2022
* feat: Implement path rendering that respects fill-rule! :)

Fixes #28. The time has finally come that I understand how scanline
algorithms work and was able to implement this by referencing an
existing implementation in the SerenityOS path renderer.

I did a lot of work to adapt that code to PHP and get it to perform as
well as possible. Note that for some images rendering still takes ages,
but that is not due to PathRenderer, rather the BezierApproximator does
not yet take scale into account and oftentimes generates curves with
waaaaay too many segments. I have done benchmarks and this rendering
algorithm is insanely efficient for what it does. If anything can be
optimized, it is probably the looping over and transforming of each
point during preparation.

* fix(tests): Fix SVGPathTest still checking for rendering via polygon

* fix(phpcs): Use 'elseif' instead of 'else if'

* fix: Remove vertex special treatment from PathRenderer

This turned out to not be necessary and rather problematic in my tests.
@meyfa meyfa added this to the v0.12.0 milestone Feb 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants