LaTeX 插圖時對副檔名的處理
這是一篇簡單的記錄,緣起與有人在 XeLaTeX 中插入.png
格式的圖片,但提示no boundingbox
。這與我的認知不同:這一錯誤通常只在 LaTeX 方式編譯時才會出現,而且加上bmpsize
巨集包結合xDVIPDFMx
驅動就能解決。但這次問題出現在XeLaTeX
下,我感到很奇怪,也引起了我的興趣。
MWE
最小工作示例如下:
% compile with XeLaTeX \documentclass{article} \usepackage{graphicx} \begin{document} \includegraphics{foo.bar.png}% reports error (no boundingbox) \end{document}
報錯如下:
! LaTeX Error: Cannot determine size of graphic in foo.bar.png (no BoundingBox) . See the LaTeX manual or LaTeX Companion for explanation. TypeH <return>for immediate help. ... l.5\includegraphics{foo.bar.png} % reports error (no boundingbox) ?
分析
如前所述,這就很奇怪了。我第一反應是圖片本身有什麼問題。但多方檢查都沒發現有什麼問題。考慮到同樣的程式碼在 pdfLaTeX 下編譯理應也能通過並順利輸出,故執行命令pdflatex test.tex
,並觀察現象。
! LaTeX Error: Unknown graphics extension: .bar.png. See the LaTeX manual or LaTeX Companion for explanation. TypeH <return>for immediate help. ... l.5\includegraphics{foo.bar.png} % reports error (no boundingbox) ?
出乎意料,本該順利通過的程式碼,在 pdfLaTeX 下也報錯了。不過,這次報錯的問題和使用 XeLaTeX 時還不太一樣。pdfLaTeX 提示說不認識名為.bar.png
的圖片副檔名。
這給了我新的提示。顯然 pdfLaTeX 在處理圖片時,以第一個.
作為分割,之後的部分都是副檔名;而後根據圖片檔案的副檔名去處理。推測 XeLaTeX 也會做類似的操作,只是細節上有所不同,XeLaTeX 沒有在遇見.bar.png
這個副檔名的第一時間報錯,而是延遲到了計算邊界框尺寸時發現沒有匹配該副檔名(.bar.png
)時才報錯。如果確實如此,那麼在graphicx.sty
當中應該有所體現。追溯到graphicx.sty
依賴的graphics.sty
當中:
\def\Ginclude@graphics#1{% \begingroup \let\input@path\Ginput@path \filename@parse{#1}% \ifx\filename@ext\relax % ...
顯然,\filename@parse
是在解析圖片檔案的檔名。這是一個定義在 LaTeX2e 中的底層命令,根據其文件,它會將解析結果儲存在\filename@area
,\filename@base
,\filename@ext
三個巨集當中。在\filename@parse
的定義中,解析副檔名是通過利用 TeX 的巨集定義式的技巧來實現的:
\def\filename@simple#1.#2
在呼叫\filename@simple
時,會將遇到的第一個.
之前的內容當做#1
而把.
之後的內容當做#2
。這個#2
最後被儲存在了\filename@ext
當中,作為副檔名。
解決辦法
瞭解了問題的根源,解決起來就容易了。
最簡單的繞過辦法,是保持圖片檔案的檔名當中只有一個句點,用於區分檔名及其副檔名。這樣 TeX 就不會被誤導了。例如,將 MWE 中的檔名從foo.bar.png
改為foo_bar.png
,再嘗試於 LaTeX 當中插入。
如果不想修改檔名,那麼可以利用 TeX 的分組,將真實的檔名包裹在一對分組花括號當中。也就是寫成形如這樣的程式碼{foo.bar}.png
。這樣,在\filename@simple
處理引數的過程中,由於foo.bar
被放在一個分組當中,整個被當成是一個 token,因而不會被打散,也因而能解析到正確的副檔名png
。