Reputation: 361
I am trying to turn a PDF which was created using LaTeX with the TikZ and animate packages.
What I get at the moment is a very nice animation in PDF format, but this is not compatible with most other programms like Powerpoint etc. Also a GIF would already be a step forward for me.
I create the animation like this:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,angles}
\usepackage{animate}
\begin{document}
\begin{animateinline}[poster=first, controls, loop, autoplay]{60}
\multiframe{10}{r=0+1}{
\def\valueToChange{\r}
\begin{tikzpicture}
% some parameterized tikz picture
\useasboundingbox(10,5) rectangle (0,-5);
\coordinate (pointBB1) at (\valueToChange,5);
\coordinate (pointBB2) at (10-\valueToChange,-5);
\draw (pointBB1) -- (pointBB2) coordinate [pos=0.5] (pointBBC);
\end{tikzpicture}
}
\end{animateinline}
\end{document}
Upvotes: 2
Views: 999
Reputation: 21
In theory, you can use the snapshot functionality to render each frame of the animation as a single pdf:
...
\begin{tikzpicture}[
make snapshot of = 1.02s
]
...
After doing this for each single frame, you could convert the pdfs with imagemagick to png and finally convert the images to a movie with ffmpeg.
While this would be a really tedious task to do by hand (you have to specify the time value for every frame by hand in the source code and make sure that the height and width of the pictures are divisible by two), this can be conveniently automated with a script. Here is a minimal example in Perl (all used modules are in the core library and should be installed already with perl):
#! /usr/bin/perl
use v5.14;
use strict; use warnings;
use Cwd;
use File::Spec;
use File::Temp;
my $duration = 5.5; # length of your animation (in seconds);
my $fps = 25; # frameratr
my $density = 300; # resolution
my $texcommand = 'lualatex';
my $videolib = 'libx264';
my $dir = getcwd();
my $tempdir = File::Temp->newdir();
my $filename = $ARGV[0] or die "You must specify a LaTex file for input!\n";
$filename =~ s/\.tex//;
# COMMAND NAMES
my @tex = ($texcommand, '-output-directory', $tempdir);
my @convert = ('magick', 'convert', '-background', 'white', '-alpha', 'remove',
'-alpha', 'off', '-density', $density);
my @identify_h = ('magick', 'identify', '-ping', '-format', "'%h'");
my @identify_w = ('magick', 'identify', '-ping', '-format', "'%w'");
my @mogrify_h = ('magick', 'mogrify', '-chop', '0x1');
my @mogrify_w = ('magick', 'mogrify', '-chop', '1x0');
my @ffmpeg = ('ffmpeg', '-y', '-framerate', $fps,
'-pattern_type', 'glob', '-i', '*.png',
'-c:v', $videolib, '-pix_fmt', 'yuv420p');
# get contents of the .tex file, prepare it
my $buffer = '';
while (<>) {
# Skip comments and empty lines
next if m/^\s*%/ or m/^\s*$/;
# Add the snapshot option to the tikzpicture environment
if ( s! \\begin\{tikzpicture\} \s* \[
!$&make snapshot of = ###, !x
) {}
elsif ( s! \\begin\{tikzpicture\}
!$&\[make snapshot of = ###\]!x
) {}
$buffer .= $_;
}
# compute time values, add to @queue
my @queue;
for my $sec (0..int ($duration - 1)) {
for my $frac (0..($fps - 1)) {
my $time = $frac / $fps + $sec;
push @queue, "$time" . "s";
}
}
push @queue, ( int $duration ) . 's';
# make list of output filenames
my $width = length scalar @queue;
my @filenames;
for my $number (0..$#queue) {
my $format = "%0$width" . "d-$filename";
my $name = sprintf $format, $number;
push @filenames, "$name";
}
for my $frm (0..$#queue) {
say STDERR "Rendering frame for: $queue[$frm]";
my $buf = $buffer =~ s/###/$queue[$frm]/gr;
my $texinput = File::Spec->catfile($tempdir, "$filenames[$frm].tex");
open my $tex_fh, '>', $texinput
or die "Cannot open $filenames[$frm].tex for.write: $!\n";
print { $tex_fh } $buf;
close $tex_fh;
!system @tex, $texinput
or die "LATEX ERROR while processing frame $filenames[$frm]!";;
unlink "$filenames[$frm].tex";
# RUN IMAGEMAGICK
my $pdf_file = File::Spec->catfile($tempdir, "$filenames[$frm].pdf");
my $png_file = File::Spec->catfile($tempdir, "$filenames[$frm].png");
# convert pdf to png; die on non-zero exit value
!system @convert, $pdf_file, $png_file
or die "IMAGEMAGICK ERROR while processing frame $filenames[$frm]!";
# chop one row of pixels if the height is odd
my $height = `@identify_h $png_file`;
my $width = `@identify_w $png_file`;
system @mogrify_h, $png_file if $height % 2;
system @mogrify_w, $png_file if $width % 2;
}
chdir $tempdir;
my $output_file = File::Spec->catfile($dir, "$filename.mp4");
system @ffmpeg, $output_file;
unlink glob "*$filename.*";
chdir $dir;
unlink $tempdir;
Make sure to have both imagemagick and ffmpeg installed, put this script in a file (say tikz2mp4) and execute it on your .trx file (say example.tex) with
perl tikz2mp4
A more mature version of this script (with concurrent execution of the conversion and less temporary files) can be found and downloaded on https://github.com/nitardus/tikz2mp4
Here you can see an example output (300dpi, 50fps, source code adapted from the tikz animation documentation)
Upvotes: 0
Reputation: 11
Although your question is a bit older: Maybe you can use the new upcoming animations library that is currently in the development version of TikZ and which can be used to create animated SVGs. Animated SVGs can be rendered by most modern web browsers like Chrome or Firefox. I've never really used but I've already seen one presentation with those animations. And I could create the following small example by looking up the documentation:
\documentclass[dvisvgm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,angles,animations}
\begin{document}
\begin{tikzpicture}[]
% some parameterized tikz picture
\useasboundingbox(10,5) rectangle (0,-5);
\draw[thick] :rotate = {0s="0",10s="90",freeze}
:yshift = {0s="0cm",2s="2cm",freeze} (2,0) -- (8,0);
\end{tikzpicture}
\end{document}
To compile it you just need to run
latex animation.tex && dvisvgm animation
Upvotes: 1