1

I have created a .gif animation from a series of .png images using the following code:

gif <- function(name, imgDir, format, fps, delete) {


  require(magick)
  require(gtools)

  imgs <- mixedsort(list.files(path = imgDir, pattern = paste("*.", format, sep = "")))
  image <- image_read(paste(imgDir, "/", imgs, sep = ""))
  animation <- image_animate(image, fps = fps)
  image_write(animation, paste(name, ".gif", sep = ""))

  if (delete) unlink(paste(imgDir, "/*", sep = ""))


}



gif("animation", "tmp", "png", 10, TRUE)

The animated .gif repeats continuously. I want to add a delay of x seconds after each loop. Is there a parameter for image_animate() or something for the purpose?

  • I don't know any `R`, but one way may be to repeat the final frame N times to get a greater delay. – Mark Setchell Nov 27 '18 at 22:29
  • @MarkSetchell I thought about that too, just wanted to avoid that. –  Nov 27 '18 at 22:37
  • If the implementation is any good, it will not lead to an increase in the GIF size... IF :-) – Mark Setchell Nov 27 '18 at 22:40
  • @jenesaisquoi good point. I've implemented that in my code :) –  Nov 27 '18 at 22:42
  • in that case you can use `full.names=TRUE` in `list.files` and just `unlink(imgs)` probably – Rorschach Nov 27 '18 at 22:58
  • I don't see how to set options for timing the image sequence in that package, but you could consider making a `system` call to convert via command line, eg https://stackoverflow.com/questions/33508486/create-a-gif-from-a-series-of-leaflet-maps-in-r/33516902#33516902 – Rorschach Nov 27 '18 at 23:01

1 Answers1

0

Use the index of individual frames from the .gif to construct a new .gif with a "pause". You create the effect of pausing by repeating the same frame. Use rep() to replicate the "pause" frame N number of times to control length of the pause.

From your example, if you want to linger on the last frame of the gif, you would want something like this:

gif <- function(name, imgDir, format, fps, delete) {
  require(magick)
  require(gtools)
  imgs <- mixedsort(list.files(path = imgDir, pattern = paste("*.", format, sep = "")))
  image <- image_read(paste(imgDir, "/", imgs, sep = ""))
  animation <- image_animate(image, fps = fps)
  #Pause on the last frame for 1 second
  #Use c() to combine image frames from one or more magick gif objects  
  gif_with_pause<-c(animation, rep(animation[length(animation)],10))
  image_write(gif_with_pause, paste(name, ".gif", sep = ""))
}
gif("animation_with_pause", "tmp", "png", 10, TRUE)

For anyone else interested in making a .gif as an image gallery, you might want to check out magick::image_morph() which can add nice transitions between images. It's also possible to extend time an individual frame appears. You can also make the GIF smoothly loop by combining your gif with a 2nd gif (showing the last frame smoothly transitioning to the first frame). Let me provide a working example of a two image gif slideshow that smoothly loops and also pauses on each image:

library(magick)
library(dplyr)
#read in some images
i1<-image_read("https://upload.wikimedia.org/wikipedia/commons/thumb/f/fd/Ghostscript_Tiger.svg/512px-Ghostscript_Tiger.svg.png")                                                     
i2<-image_read("https://jeroen.github.io/images/frink.png")

#make a gif image
initial_gif<-image_resize(c(i1, i2), '200x200!') %>%
  image_background('white') %>%
  image_morph( frames = 10) %>%
  image_animate(optimize = TRUE, fps = 10)

#make another gif with the last image moving to the first image
last_img_to_1st_gif<-image_resize(c(i2,i1), '200x200!') %>%
  image_background('white') %>%
  image_morph( frames = 10) %>%
  image_animate(optimize = TRUE, fps = 10)

#use rep() to linger on the first image, cycle the gif, linger on the second image, 
#then show a transition back to the first image.
new_gif<-c(rep(initial_gif[1],10),
             initial_gif,
             rep(initial_gif[length(initial_gif)],10),
             last_img_to_1st_gif)

Here is the result: example of gif as image gallery

SEAnalyst
  • 1,077
  • 8
  • 15