Basic manipulation of GIF frames with magick

The magick package is a really powerful package for image processing in R. The official vignette is a great place to start learning how to use the package.

I’ve been playing around with using magick for manipulating GIFs and found some tips and tricks that don’t seem to be documented anywhere. Since the NBA restart is upon us, I’ll illustrate these tips with a GIF featuring one of the greatest of all time:

library(magick)

img_path <- paste0("https://media3.giphy.com/media/3o72F9VC4WjFDCPTag/",
                   "giphy.gif?cid=ecf05e470ceb6cd8542e8c243d0e0a2282c3390e5c",
                   "72fd17&rid=giphy.gif")
img <- magick::image_read(img_path)
img

If you print img, you will see that the GIF is represented as a tibble, with each row representing a single frame in the GIF:

print(img)
# # A tibble: 44 x 7
#    format width height colorspace matte filesize density
#    <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
#  1 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  2 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  3 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  4 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  5 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  6 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  7 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  8 GIF      480    266 sRGB       TRUE   2617620 72x72  
#  9 GIF      480    266 sRGB       TRUE   2617620 72x72  
# 10 GIF      480    266 sRGB       TRUE   2617620 72x72  
# # … with 34 more rows

Use the length() function to determine how many frames there are in the GIF:

length(img)
# [1] 44

You can index GIFs as you would with a vector. For example, img[12] returns the 12th frame of the GIF:

You can, of course, put more than one frame index in the square brackets. For example, img[44:1] will run the GIF in reverse (this can also be achieved with rev(img)):

This is a little more elaborate:

img[c(1:44, rep(c(rep(44, times = 5), 43:30, 
                  rep(30, times = 5), 31:43), 
                times = 2))]

Slowing down the dunk action:

img[c(1:30, rep(31:44, each = 3))]

We can replace a single frame with a different image too:

logo <- image_read("https://jeroen.github.io/images/Rlogo.png") %>%
  image_resize("480x266!")
img[25] <- logo
img

I don’t know if there is a clean way to insert the R logo as the 25th frame and push the original 25-44th frames down one frame (that would be a neat functionality to have). The below is a workaround but it feels inelegant:

img <- img[c(1:25, 25:44)]
img[25] <- logo

2 thoughts on “Basic manipulation of GIF frames with magick

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s