diff --git a/Project.toml b/Project.toml index db46a709..d283debb 100644 --- a/Project.toml +++ b/Project.toml @@ -9,7 +9,6 @@ Cairo = "159f3aea-2a34-519c-b102-8c37f9878175" Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" Juno = "e5e0dc1b-0480-54bc-9374-aad01c23163d" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" @@ -17,19 +16,21 @@ MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Rsvg = "c4c386cf-5103-5370-be45-f3a111cca3b8" +FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" [weakdeps] +FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" [extensions] +LuxorExtFFMPEG = ["FFMPEG"] LuxorExtLatex = ["LaTeXStrings", "MathTeXEngine"] [compat] Cairo = "0.7, 0.8, 1.0" Colors = "0.9, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 1.0" DataStructures = "0.18" -FFMPEG = "0.4" FileIO = "1" Juno = "0.7, 0.8" LaTeXStrings = "1.1, 1.2, 1.3" @@ -38,10 +39,11 @@ Rsvg = "1.0" julia = "1.9" [extras] +FFMPEG = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" ImageIO = "82e4d734-157c-48bb-816b-45c225c6df19" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" MathTeXEngine = "0a4f8689-d25c-4efe-a92b-7142dfc1aa53" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["ImageIO", "Test", "MathTeXEngine", "LaTeXStrings"] +test = ["ImageIO", "Test", "MathTeXEngine", "LaTeXStrings", "FFMPEG"] diff --git a/ext/LuxorExtFFMPEG.jl b/ext/LuxorExtFFMPEG.jl new file mode 100644 index 00000000..c3366f5b --- /dev/null +++ b/ext/LuxorExtFFMPEG.jl @@ -0,0 +1,10 @@ +""" +This extension is loaded and used by Luxor if FFMPEG is loaded. + +The functions are accessed through Luxor as usual. +""" +module LuxorExtFFMPEG + +include("creategif.jl") + +end # module diff --git a/ext/creategif.jl b/ext/creategif.jl new file mode 100644 index 00000000..0234eacf --- /dev/null +++ b/ext/creategif.jl @@ -0,0 +1,23 @@ +# Functionality that requires FFMPEG. +# Normally invoked by setting argument `create_gif` to `animate` to true. +# Argument checking is considered sufficiently done in `animate` +using FFMEG +import Luxor +import Luxor: create_gif_newer_version, create_gif_older_version + +function create_gif_older_version(directory::String, title::String, framerate) + # version of ffmpeg up to 2.1.3 + # these two commands create a palette and then an animated GIF from the resulting images using the palette + FFMPEG.ffmpeg_exe(`-loglevel panic -f image2 -i $(directory)/%10d.png -vf palettegen -y $(directory)/$(title)-palette.png`) + FFMPEG.ffmpeg_exe(`-loglevel panic -framerate $(framerate) -f image2 -i $(directory)/%10d.png -i $(directory)/$(title)-palette.png -lavfi paletteuse -y $(directory)/$(title).gif`) +end +function create_gif_newer_version(directory::String, title::String, framerate) + @debug "we're running bundled FFMPEG", FFMPEG.exe("-version") + # the FFMPEG commands create a palette and then create an animated GIF from the resulting images + FFMPEG.ffmpeg_exe(`-framerate $(framerate) -f image2 -i $(directory)/%10d.png -filter_complex "[0:v] split [a][b]; [a] palettegen=stats_mode=full:reserve_transparent=on:transparency_color=FFFFFF [p]; [b][p] paletteuse=new=1:alpha_threshold=128" -y $(directory)/$(title).gif`) +end +function create_gif_newer_version_reduced_verbosity(directory::String, title::String, framerate) + @debug "we're running bundled FFMPEG", FFMPEG.exe("-version") + # the FFMPEG commands create a palette and then create an animated GIF from the resulting images + FFMPEG.ffmpeg_exe(`-framerate $(framerate) -f image2 -i $(directory)/%10d.png -filter_complex "[0:v] split [a][b]; [a] palettegen=stats_mode=full:reserve_transparent=on:transparency_color=FFFFFF [p]; [b][p] paletteuse=new=1:alpha_threshold=128" -y $(directory)/$(title).gif`) +end diff --git a/src/animate.jl b/src/animate.jl index 97a2d595..42b01a39 100644 --- a/src/animate.jl +++ b/src/animate.jl @@ -218,23 +218,17 @@ function animate(movie::Movie, scenelist::Array{Scene, 1}; if creategif == false return true # we're done end - # the FFMPEG commands create a palette and then create an animated GIF from the resulting images if !usenewffmpeg - # old version of ffmpeg up to 2.1.3 - # these two commands create a palette and then an animated GIF from the resulting images using the palette - FFMPEG.ffmpeg_exe(`-loglevel panic -f image2 -i $(tempdirectory)/%10d.png -vf palettegen -y $(tempdirectory)/$(movie.movietitle)-palette.png`) - FFMPEG.ffmpeg_exe(`-loglevel panic -framerate $(framerate) -f image2 -i $(tempdirectory)/%10d.png -i $(tempdirectory)/$(movie.movietitle)-palette.png -lavfi paletteuse -y $(tempdirectory)/$(movie.movietitle).gif`) + create_gif_older_version(tempdirectory, movie.movietitle, framerate) else - @debug "we're running bundled FFMPEG", FFMPEG.exe("-version") # the latest version of ffmpeg uses built-in palettes and allegedly does transparency using complex filters ¯\\\_(ツ)_/¯ if debug @info "$(framerate)" @info "$(tempdirectory)" @info "$(tempdirectory)/$(movie.movietitle).gif" - FFMPEG.ffmpeg_exe(`-framerate $(framerate) -f image2 -i $(tempdirectory)/%10d.png -filter_complex "[0:v] split [a][b]; [a] palettegen=stats_mode=full:reserve_transparent=on:transparency_color=FFFFFF [p]; [b][p] paletteuse=new=1:alpha_threshold=128" -y $(tempdirectory)/$(movie.movietitle).gif`) + create_gif_newer_version(tempdirectory, movie.movietitle, framerate) else - # reduce verbosity ! - FFMPEG.ffmpeg_exe(`-loglevel panic -framerate $(framerate) -f image2 -i $(tempdirectory)/%10d.png -filter_complex "[0:v] split [a][b]; [a] palettegen=stats_mode=full:reserve_transparent=on:transparency_color=FFFFFF [p]; [b][p] paletteuse=new=1:alpha_threshold=128" -y $(tempdirectory)/$(movie.movietitle).gif`) + create_gif_newer_version_reduced_verbosity(tempdirectory, movie.movietitle, framerate) end end diff --git a/src/placeholders_for_extensions.jl b/src/placeholders_for_extensions.jl index 5a18e334..9efd6ce9 100644 --- a/src/placeholders_for_extensions.jl +++ b/src/placeholders_for_extensions.jl @@ -6,20 +6,45 @@ function latextextsize(catch_all) if Base.get_extension(Luxor, :LuxorExtLatex) isa Module throw(MethodError(latextextsize, catch_all)) else - throw(ErrorException("Modules LaTeXStrings and MathTeXEngine are not loaded.")) + throw(ErrorException("Modules LaTeXStrings and MathTeXEngine are not loaded. Try `using LaTeXStrings, MathTeXEngine`!")) end end function latexboundingbox(catch_all; kwargs...) if Base.get_extension(Luxor, :LuxorExtLatex) isa Module throw(MethodError(latexboundingbox, catch_all)) else - throw(ErrorException("Modules LaTeXStrings and MathTeXEngine are not loaded.")) + throw(ErrorException("Modules LaTeXStrings and MathTeXEngine are not loaded. Try `using LaTeXStrings, MathTeXEngine`!")) end end function rawlatexboundingbox(catch_all) if Base.get_extension(Luxor, :LuxorExtLatex) isa Module throw(MethodError(rawlatexboundingbox, catch_all)) else - throw(ErrorException("Modules LaTeXStrings and MathTeXEngine are not loaded.")) + throw(ErrorException("Modules LaTeXStrings and MathTeXEngine are not loaded. Try `using LaTeXStrings, MathTeXEngine`!")) end end +# Placeholders for animation functions. +# Since there are so many similar placeholders, we could use a small macro definition and call. +# During initial testing, we use more verbose and conceptually simple code instead: + +function create_gif_older_version(catch_all, catch_2, catch_3) + if Base.get_extension(Luxor, :LuxorExtFFMPEG) isa Module + throw(MethodError(create_gif_older_version, catch_all)) + else + throw(ErrorException("Module FFMPEG is not loaded. Try `using FFMPEG`!")) + end +end +function create_gif_newer_version(catch_all, catch_2, catch_3) + if Base.get_extension(Luxor, :LuxorExtFFMPEG) isa Module + throw(MethodError(create_gif_newer_version, catch_all)) + else + throw(ErrorException("Module FFMPEG is not loaded. Try `using FFMPEG`!")) + end +end +function create_gif_newer_version_reduced_verbosity(catch_all, catch_2, catch_3) + if Base.get_extension(Luxor, :LuxorExtFFMPEG) isa Module + throw(MethodError(create_gif_newer_version, catch_all)) + else + throw(ErrorException("Module FFMPEG is not loaded. Try `using FFMPEG`!")) + end +end \ No newline at end of file