kyamagu / skia-python

Python binding to Skia Graphics Library
https://kyamagu.github.io/skia-python/
BSD 3-Clause "New" or "Revised" License
245 stars 43 forks source link

(Question) Rendering SVGs to bitmap? #145

Open Spooghetti420 opened 3 years ago

Spooghetti420 commented 3 years ago

I had heard that skia was used in browsers in order to rasterise SVGs; is there a way to load an SVG image like you can bitmap images, and draw that to a canvas, and then export it as a PNG, for instance? I'm currently trying:

surface = skia.Surface(678, 960)
with surface as canv:
    svg =  skia.Image.open("0001.svg")
    canv.drawImage(svg, 0, 0)
image = surface.makeImageSnapshot()
image.save("0001.png", skia.kPNG)

...but this doesn't work: RuntimeError: Failed to decode an image. Thanks for creating this library, by the way; it's much appreciated. :)

kyamagu commented 3 years ago

See the tutorial https://kyamagu.github.io/skia-python/tutorial/canvas.html#svg

kyamagu commented 3 years ago

For rasterization, there is the experimental SVGDOM api.

0lru commented 2 years ago

I've tried that. Works very well: https://github.com/0lru/p3ui/blob/main/demos/canvas/svg.py. Also rendered material icons locally, reading binaries from a ZipFile. Example:

        bytes = someZipFile.read(icon.path.as_posix())
        stream = skia.MemoryStream(bytes, True) # True means "copy", False means "move"
        dom = skia.SVGDOM.MakeFromStream(stream

md

You can render to any backend. I'm using OpenGL..

animanathome commented 2 years ago

This is working end to end example:

import skia

stream = skia.FILEStream.MakeFromFile('./input.svg')
dom = skia.SVGDOM.MakeFromStream(stream)
# is there a way to query the bounding box from the loaded SVG?

dom.setContainerSize(skia.Size(128, 128))
surface = skia.Surface(512, 512)
with surface as canvas:
    canvas.scale(10, 10)
    dom.render(canvas)

image = surface.makeImageSnapshot()
image.save('/output.png', skia.kPNG)

By default the SVG is tiny. I would want to automatically want to fill it to the entire surface. I've found I can use scale for that. However, I'm sure by how much I need to scale it. @kyamagu is there a way to get the bounds or dimensions from the loaded SVG?

kyamagu commented 2 years ago

@animanathome Please check if there is a relevant API in the documentation. skia-python is merely a wrapper

HinTak commented 1 year ago

You use to SetContainerSize() method for the SVGDOM class to set the svg's containerize to the same as the surface you want to out it to, if you want to fill it.

HinTak commented 1 year ago

The containSize() method supposedly returns the "default" (designed) size of the SVG.