Plotting a sequence of images as a gif

Well, I guess this is an attractive feature request :-).
For me, I think it is easy enough to automate this by wrapping APNG Assembler with some OS level calls.

I tried apng assembler but I have been a bit disappointed : it was much longer to run than saving to gif ( about a minute vs a few seconds) and the resulting png was twice bigger than the gif without an obvious quality enhancement…

If your color palette is narrow they should be similar quality wise. Yet APNG should have better compression. As far as I can remember to the least.

I’m trying to create a .gif from several images too. The save function doesn’t work for my array although I feel like this is functionally similar to the example. Any recommendations?

using FileIO, ImageIO, Colors, FixedPointNumbers, Images

folder = 
A = Array{Array{RGB{Normed{UInt8,8}},2},1}()

for i in 1:200
    img_path = "tmp/"*string(i)*".png"
    img = load(img_path)
    push!(A,img)
end

save("test.gif", A)
┌ Warning: Mapping to the storage type failed; perhaps your data had out-of-range values?
│ Try `map(clamp01nan, img)` to clamp values to a valid range.
└ @ ImageMagick ImageMagick\0LwpT\src\ImageMagick.jl:180
Error encountered while saving "test.gif".

Fatal error:
ERROR: LoadError: MethodError: no method matching mapIM(::Array{RGB{Normed{UInt8,8}},2})
Closest candidates are:
  mapIM(::Bool) at \ImageMagick\0LwpT\src\ImageMagick.jl:264
  mapIM(::UInt16) \ImageMagick\0LwpT\src\ImageMagick.jl:262
  mapIM(::UInt32) \ImageMagick\0LwpT\src\ImageMagick.jl:263
  ...

It should be a 3d array (HWT, T = time), not a vector-of-matrices.

Yes. Thank you.

A = cat(A, load(img_path), dims=3)

Actually, if you zoom and open on another tab, you can see it move once.

Thanks for this tip! I think using this format just solved a big problem I’m having with regular GIFs and the headaches that come along with indexed colors.

This is not working for me:

using FileIO, ImageIO, Colors, FixedPointNumbers, Images

folder = "video"
A = Array{Array{RGB{Normed{UInt8,8}},2},1}()

for j in 0:66
    global A
    local img
    img_path = folder*"/"*"img-"*lpad(j,4,"0")*".png"
    img=load(img_path)
    A = cat(A, img, dims=3)
end

save("video/Tether.gif", A)

Error message:

julia> include("src/export_gif.jl")
ERROR: LoadError: DimensionMismatch: mismatch in dimension 1 (expected 0 got 480)
Stacktrace:
  [1] _cs
    @ Base ./abstractarray.jl:1782 [inlined]
  [2] _cshp
    @ Base ./abstractarray.jl:1778 [inlined]
  [3] _cat_size_shape(::Tuple{Bool, Bool, Bool}, ::Tuple{Int64, Int64, Int64}, ::Matrix{RGBA{N0f8}})
    @ Base ./abstractarray.jl:1758
  [4] cat_size_shape
    @ ./abstractarray.jl:1756 [inlined]
  [5] _cat_t
    @ ./abstractarray.jl:1797 [inlined]
  [6] _cat(::Int64, ::Vector{Matrix{RGB{N0f8}}}, ::Matrix{RGBA{N0f8}})
    @ Base ./abstractarray.jl:1793
  [7] #cat#159
    @ Base ./abstractarray.jl:1990 [inlined]
  [8] top-level scope
    @ ~/repos/Tethers.jl/src/export_gif.jl:11
  [9] include(fname::String)
    @ Base.MainInclude ./client.jl:489
 [10] top-level scope
    @ REPL[3]:1
in expression starting at /home/ufechner/repos/Tethers.jl/src/export_gif.jl:6

What am I doing wrong?

OK, this works:

using FileIO, ImageIO, Colors, FixedPointNumbers, Images

folder = "video"
A = Array{Array{RGB{Normed{UInt8,8}},2},1}()

for j in 0:66
    global A
    local img
    img_path = folder*"/"*"img-"*lpad(j,4,"0")*".png"
    img=load(img_path)
    if j==0
        A=img
    else
        A = cat(A, img, dims=3)
    end
end

save(folder * "/Tether.gif", A)

This snippet (which I have used hundreds of times, so useful!) seems to have stopped working.

It now gives a message to the effect of

===========================================
UndefVarError: `libwand` not defined
===========================================

Fatal error:
ERROR: BoundsError: attempt to access 4×32×32×5 reinterpret(UInt8, ::Array{N0f8,4}) at index [1:4, 1:32, 1]
Stacktrace:
  [1] throw_boundserror(A::Base.ReinterpretArray{…}, I::Tuple{…})
    @ Base ./abstractarray.jl:734
  [2] checkbounds
    @ ./abstractarray.jl:699 [inlined]
  [3] _getindex
    @ ./multidimensional.jl:888 [inlined]
  [4] getindex
    @ ./abstractarray.jl:1288 [inlined]
  [5] save_(f::FileIO.File{…}, img::Array{…}; permute_horizontal::Bool, mapi::typeof(identity))
    @ QuartzImageIO ~/.julia/packages/QuartzImageIO/4Fkqk/src/QuartzImageIO.jl:310

Is this a QuartzImageIO.jl, ImageMagick.jl, or FileIO.jl issue, do we think?

This issue seems relevant to libwand error.

It’s both ImageMagick (the source of the libwand error) and QuartzImageIO (the source of the BoundsError). I’m guessing the ImageMagick_jll version may have changed, you could try pinning it perhaps.

Fundamentally, ImageMagick has been a never-ending source of trouble. You might try GitHub - JuliaIO/GIFImages.jl: Provides Gif support in Julia using LibGif and see if that works better.

2 Likes

Is there a _jll for APNG Assembler?