Latex中也能展示動態圖?

2022-09-21 12:00:50

技術背景

在學術領域,很多檔案是用Latex做的,甚至有很多人用Latex Beamer來做PPT簡報。雖然在易用性和美觀等角度來說,Latex Beamer很大程度上不如PowerPoint,但是Beamer這種濃厚的學術色彩還是受到了很多人的喜好。但是我們知道Latex生成的檔案一般是用pdf格式來儲存的,如果放一個gif動態圖進去,就可能會變成一個靜態圖,那就沒辦法展示整個動態的過程了。幸運的是,Latex還有一種比較麻煩的方法,對動態圖也做了一定的支援。本文所使用的案例,是一個比較熱門的猴痘病毒蛋白的鬆弛過程。礙於動態圖比較大,在部落格里面放不下,故只能用這種連結索引+靜態圖展示的方案。

圖片拆分

第一步,我們需要使用工具將一個Gif圖片拆解成一系列的png圖片。在Windows下有很多拆解工具可以使用,需要的童鞋可以自行搜尋。但是對於一個Coder而言,用Python來進行拆解,可能是最方便的操作,也是這裡我們比較推薦的方案——pillow。我們可以先用pip安裝更新一下原生的pillow:

$ python3 -m pip install pillow --upgrade
Requirement already satisfied: pillow in /home/dechin/miniconda3/lib/python3.9/site-packages (8.4.0)
Collecting pillow
  Downloading Pillow-9.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (3.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━ 3.1/3.1 MB 2.2 MB/s eta 0:00:00
Installing collected packages: pillow
  Attempting uninstall: pillow
    Found existing installation: Pillow 8.4.0
    Uninstalling Pillow-8.4.0:
      Successfully uninstalled Pillow-8.4.0
Successfully installed pillow-9.2.0

安裝完成後,直接在Ipython或者普通python的終端命令列呼叫即可,如果確實需要比較複雜操作的話,也可以寫成指令碼來執行:

In [1]: from PIL import Image

In [2]: import os

In [3]: gif_name = 'Q8V4Y0.gif'

In [4]: img = Image.open(gif_name)

In [5]: os.mkdir('pngs')

In [6]: !ls -l
total 15836
-rwxr-xr-x 1 dechin dechin 16211906 Sep 21 10:11 Q8V4Y0.gif
drwxr-xr-x 2 dechin dechin     4096 Sep 21 10:17 pngs

In [7]: while True:
   ...:     current = img.tell()
   ...:     img.save('pngs/'+str(current)+'.png')
   ...:     img.seek(current+1)
   ...:
-----------------------------------------------------------
EOFError                  Traceback (most recent call last)
~/miniconda3/lib/python3.9/site-packages/PIL/GifImagePlugin.py in seek(self, frame)
    151             try:
--> 152                 self._seek(f)
    153             except EOFError as e:

~/miniconda3/lib/python3.9/site-packages/PIL/GifImagePlugin.py in _seek(self, frame, update_image)
    185         if not s or s == b";":
--> 186             raise EOFError
    187

EOFError:

The above exception was the direct cause of the following exception:

EOFError                  Traceback (most recent call last)
<ipython-input-7-45000e59c5e9> in <module>
      2     current = img.tell()
      3     img.save('pngs/'+str(current)+'.png')
----> 4     img.seek(current+1)
      5

~/miniconda3/lib/python3.9/site-packages/PIL/GifImagePlugin.py in seek(self, frame)
    153             except EOFError as e:
    154                 self.seek(last_frame)
--> 155                 raise EOFError("no more images in GIF file") from e
    156
    157     def _seek(self, frame, update_image=True):

EOFError: no more images in GIF file

In [8]: !ls -l pngs/
total 37276
-rw-r--r-- 1 dechin dechin 277605 Sep 21 10:18 0.png
-rw-r--r-- 1 dechin dechin 766892 Sep 21 10:18 1.png
-rw-r--r-- 1 dechin dechin 770417 Sep 21 10:18 10.png
-rw-r--r-- 1 dechin dechin 773093 Sep 21 10:18 11.png
-rw-r--r-- 1 dechin dechin 773101 Sep 21 10:18 12.png
-rw-r--r-- 1 dechin dechin 768060 Sep 21 10:18 13.png
-rw-r--r-- 1 dechin dechin 772558 Sep 21 10:18 14.png
-rw-r--r-- 1 dechin dechin 767242 Sep 21 10:18 15.png
-rw-r--r-- 1 dechin dechin 768024 Sep 21 10:18 16.png
-rw-r--r-- 1 dechin dechin 766089 Sep 21 10:18 17.png
-rw-r--r-- 1 dechin dechin 771081 Sep 21 10:18 18.png
-rw-r--r-- 1 dechin dechin 768937 Sep 21 10:18 19.png
-rw-r--r-- 1 dechin dechin 771098 Sep 21 10:18 2.png
-rw-r--r-- 1 dechin dechin 768942 Sep 21 10:18 20.png
-rw-r--r-- 1 dechin dechin 774666 Sep 21 10:18 21.png
-rw-r--r-- 1 dechin dechin 769060 Sep 21 10:18 22.png
-rw-r--r-- 1 dechin dechin 768860 Sep 21 10:18 23.png
-rw-r--r-- 1 dechin dechin 774749 Sep 21 10:18 24.png
-rw-r--r-- 1 dechin dechin 769303 Sep 21 10:18 25.png
-rw-r--r-- 1 dechin dechin 770692 Sep 21 10:18 26.png
-rw-r--r-- 1 dechin dechin 773657 Sep 21 10:18 27.png
-rw-r--r-- 1 dechin dechin 772078 Sep 21 10:18 28.png
-rw-r--r-- 1 dechin dechin 769908 Sep 21 10:18 29.png
-rw-r--r-- 1 dechin dechin 771034 Sep 21 10:18 3.png
-rw-r--r-- 1 dechin dechin 771412 Sep 21 10:18 30.png
-rw-r--r-- 1 dechin dechin 771772 Sep 21 10:18 31.png
-rw-r--r-- 1 dechin dechin 771312 Sep 21 10:18 32.png
-rw-r--r-- 1 dechin dechin 771232 Sep 21 10:18 33.png
-rw-r--r-- 1 dechin dechin 768273 Sep 21 10:18 34.png
-rw-r--r-- 1 dechin dechin 772945 Sep 21 10:18 35.png
-rw-r--r-- 1 dechin dechin 775270 Sep 21 10:18 36.png
-rw-r--r-- 1 dechin dechin 772346 Sep 21 10:18 37.png
-rw-r--r-- 1 dechin dechin 770087 Sep 21 10:18 38.png
-rw-r--r-- 1 dechin dechin 768827 Sep 21 10:18 39.png
-rw-r--r-- 1 dechin dechin 771078 Sep 21 10:18 4.png
-rw-r--r-- 1 dechin dechin 771802 Sep 21 10:18 40.png
-rw-r--r-- 1 dechin dechin 773822 Sep 21 10:18 41.png
-rw-r--r-- 1 dechin dechin 770597 Sep 21 10:18 42.png
-rw-r--r-- 1 dechin dechin 771889 Sep 21 10:18 43.png
-rw-r--r-- 1 dechin dechin 774457 Sep 21 10:18 44.png
-rw-r--r-- 1 dechin dechin 771072 Sep 21 10:18 45.png
-rw-r--r-- 1 dechin dechin 773136 Sep 21 10:18 46.png
-rw-r--r-- 1 dechin dechin 771072 Sep 21 10:18 47.png
-rw-r--r-- 1 dechin dechin 771411 Sep 21 10:18 48.png
-rw-r--r-- 1 dechin dechin 773853 Sep 21 10:18 49.png
-rw-r--r-- 1 dechin dechin 771607 Sep 21 10:18 5.png
-rw-r--r-- 1 dechin dechin 771951 Sep 21 10:18 6.png
-rw-r--r-- 1 dechin dechin 774519 Sep 21 10:18 7.png
-rw-r--r-- 1 dechin dechin 768478 Sep 21 10:18 8.png
-rw-r--r-- 1 dechin dechin 769771 Sep 21 10:18 9.png

這個執行的過程中有一處報錯,但是可以不用在意,有條件的童鞋可以加一個try-except即可。而這裡我們最終是在指定路徑下成功生成了一系列的png圖片檔案,接下來可以考慮放到Latex裡面去。

Latex載入動態圖

先看一下載入這個動態圖的Latex案例,其實非常簡單,就是用animate來載入一系列帶數位的png圖片,用來動態展示:

\documentclass{beamer}
\usepackage{graphicx} % Allows including images
\usepackage{animate}

\begin{document}
\animategraphics[width=0.5\linewidth, autoplay=True]{24}{imgs/}{0}{49}
\end{document}

其中imgs/需要替換為你自己的圖片儲存路徑,{0}{49}是圖片字尾編號,我這裡Gif拆完之後是有50張,width=0.5\linewidth是用來調整圖片大小的,一般調節這幾個引數就夠了。不過,為了避免Latex使用中可能出現的各種環境依賴問題,推薦測試的時候使用Overleaf自帶的環境,這樣可以避免很多的麻煩:

這裡還有一個問題是,不是所有的pdf閱讀器都支援這樣的外掛,即使是生成了動態圖,在一部分的閱讀器下可能也無法正常播放,推薦使用Adobe Acrobat Reader DC,具體的安裝方法這裡就不過多的介紹,大家可以自行搜尋。

開啟之後是可以正常播放的,這裡還是放了一個截圖用來展示功能。還有一個比較酷的功能是,Latex的animate還可以附帶一些控制元件:

\documentclass{beamer}
\usepackage{graphicx} % Allows including images
\usepackage{animate}

\begin{document}
\animategraphics[width=0.5\linewidth, autoplay=True, loop, controls]{24}{imgs/}{0}{49}
\end{document}

加上控制元件之後,不僅可以迴圈播放,還可以暫停、逐幀控制、加速、慢放、回放等等,依然是先用Overleaf的環境進行編譯:

然後下載到本地使用Acrobat Reader開啟:

雖然比PowerPoint麻煩了許多,但是Latex也能夠實現這樣的功能,還是很讓人欣慰的。

總結概要

本文介紹了一個可以在Latex生成的PDF中展示動態圖的解決方案,該方案依賴於三個東西:Python+Pillow的環境(或者其他可以將Gif拆分成眾多png圖片的工具/網站)、Overleaf的賬號(或者具備animate的Latex環境)以及Acrobat Reader閱讀器(或者其他可以支援pdf中的動態演示功能的閱讀器)。雖然一系列的操作下來非常的麻煩,但是最終我們還是可以在Latex生成的PDF中成功的進行了動態展示。

版權宣告

本文首發連結為:https://www.cnblogs.com/dechinphy/p/latex-gif.html

作者ID:DechinPhy

更多原著文章請參考:https://www.cnblogs.com/dechinphy/

打賞專用連結:https://www.cnblogs.com/dechinphy/gallery/image/379634.html

騰訊雲專欄同步:https://cloud.tencent.com/developer/column/91958

CSDN同步連結:https://blog.csdn.net/baidu_37157624?spm=1008.2028.3001.5343

51CTO同步連結:https://blog.51cto.com/u_15561675

參考連結

  1. https://www.cnblogs.com/easyidea/p/10520354.html
  2. https://liam.page/2017/08/10/importing-animate-in-LaTeX/