SVG to RGB: How to save a series of svg images to video?

My code generates a series of svg images as text. Now I want to save them as an animated video.
Here is a MWE.

svgtxt = 
"""
<svg width="100%" height="100%" viewBox="30 57 1102 582">
<g style="stroke:#f00; stroke-width:5;">
<path fill="#D7DDDF" d="M476,257 L135,257 L411,57 Z"/>
<path fill="#D2DFE4" d="M857,381 L751,57 L1027,257 Z"/>
<path fill="#D9E0E1" d="M240,581 L135,257 L30,581 Z"/>
<path fill="#B7B9B9" d="M476,257 L751,57 L411,57 Z"/>
<path fill="#D0DEE2" d="M856,381 L1132,581 L1027,257 Z"/>
</g>
</svg>
"""
display("image/svg+xml", svgtxt)

output_1_0

Now I want to save this svg to a video as frames. (Based on this post.)
(In reality I will have a yielding function that will keep returning different svgs at each call.)

open(`ffmpeg -loglevel warning -y -f rawvideo -pix_fmt rgb24 -s:v 1200x1200 -r 30 -i pipe:0 -vf "transpose=0" -pix_fmt yuv420p test.mp4`, "w") do out
        for i = 1:300
            write(out, svgtxt) # How to change svgtxt to a valid RGB buffer?
        end
    end

gives

pipe:0: corrupt input packet in stream 0
[rawvideo @ 0x55d5ac91e040] Invalid buffer size, packet size 115200 < expected frame_size 4320000
Error while decoding stream #0:0: Invalid argument
failed process: Process(`ffmpeg -loglevel warning -y -f rawvideo -pix_fmt rgb24 -s:v 1200x1200 -r 30 -i pipe:0 -vf transpose=0 -pix_fmt yuv420p test.mp4`, ProcessExited(69)) [69]

Either Ffmpeg support for svg rasterization - Stack Overflow or rasterize the SVGs before sending to ffmpeg. Something like How to convert an svg file to png with fixed pixel size/resolution

ffmpeg has to be compiled with svg support, I believe, and there’s probably a way of telling whether the version you’re using was or wasn’t.

As a workaround, you could use Luxor to build an animation from SVG images like this:

using Luxor

function make_an_svg()
    cols = ["#389826", "#cb3c33", "#9558b2"]
    return """
    <svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 512 512">
    <circle fill="$(cols[rand(1:end)])" cx="256" cy="137" r="83"/>
    <circle fill="$(cols[rand(1:end)])" cx="145" cy="329" r="83"/>
    <circle fill="$(cols[rand(1:end)])" cx="367" cy="329" r="83"/></svg>"""
end 
function frame(scene, framenumber)
    background("black")
    placeimage(readsvg(make_an_svg()), O, centered=true)
end
movie = Movie(400, 400, "svg movie")
animate(movie, [Scene(movie, frame, 1:20)], 
    framerate=4, creategif=true)

which generates a frame for each SVG string returned by make_an_svg().

jc

2 Likes