Animate PDF files with knitr, which supports more than just Adobe Reader

Knitr

has a pretty neat animation feature that can create animations in Markdown and HTML via FFMPEG and WebM, as well as PDF using the LaTeX animated package. However, PDF support for later versions is limited to Adobe Reader (and possibly PDF XChangeViewer). I'm going to implement my own animation functionality which will generate an MP4 video from a series of plots and use the LaTeX package media9

to embed the video. This has broader support, including Okular and at least one iOS PDF reader. Is there any other way to do this already there or inside Knitr

or in another package? Apparently it will have general applicability if implemented well.

Note. I sent the finished animation example, using rgl

as an answer to this question . It works fine in Adobe Reader but relies on scripting support.

+3


source to share


1 answer


I have something working that converts a range of png to mp4 and then embeds it using the media9 package. It plays fine in Adobe Reader on Windows, but for some reason doesn't work on Okular running Linux Mate. Having said that, nor any other PDFs I've tried with embedded movies, so this seems like a problem on the reader's side.

Here's the .Rnw:



\documentclass{article}
\usepackage{media9}
\usepackage{graphicx, xcolor}

<< label = setup, include = FALSE>>=
library("rgl")
library("car")
library("knitr")
hook_rgl_spin_mp4 <- function(before, options, envir) {
  if (!before) {
    par3d(windowRect = 100 + options$dpi *
          c(0, 0, options$fig.width, 
            options$fig.height))
    if (!is.null(options$spin3d.axis)) {
      spin3d.axis <- options$spin3d.axis
    } else {
      spin3d.axis <- c(0, 0, 1)
    }
    if (!is.null(options$spin3d.rpm)) {
      spin3d.rpm <- options$spin3d.rpm
    } else {
      spin3d.rpm <- c(0, 0, 1)
    }
    spinFunc <- spin3d(axis = spin3d.axis, rpm = spin3d.rpm)
    for(i in 1:options$fig.num) {
      par3d(spinFunc(i * options$interval))
      Sys.sleep(0.05)
      rgl.snapshot(fig_path(".png", number = i), fmt = "png")
    }
    system(paste0('ffmpeg -y -r 10 -i "', sub("-1\\.", "-%d\\.", fig_path(".png", number = 1)),
                  '" -pix_fmt yuv420p "', vid_path <- fig_path(".mp4", number = 1), '"'))
    options$fig.num <- 0
    options$fig.show <- "hide"
    paste0("\\includemedia[width=", options$out.width, ",height=", options$out.height, 
           ",activate=pageopen,addresource=",
           vid_path, ",flashvars={source=", vid_path, "}]{}{VPlayer.swf}")
  }
}
knit_hooks$set(rgl = hook_rgl_spin_mp4)
@ 
  \begin{document}

<< label=rgl1, rgl=TRUE, fig.show='animate', fig.width=5, fig.height=5, out.width='.6\\linewidth', out.height='.6\\linewidth', dev='png', fig.num = 40, interval=0.1, spin3d.axis=c(0, 0, 1), spin3d.rpm=20, results='asis'>>=
  scatter3d(prestige ~ income + education, data=Duncan)
@

  \end{document}

      

Note that it should work results='asis'

, but otherwise everything will be done in the hook.

+1


source







All Articles