用过模板的人可能都有这种经历:以为自己只是往 LaTeX 里“贴”一张图片,结果图片一会儿跑到下一章开头,一会儿跟正文叠在一起,位置永远不在你心里预期的位置。过去几年里我都在用 LaTeX 写论文、做课程报告、整理技术文档,图片插入这块,几乎每一次排版都能遇到新问题。这篇就把我踩过的坑、总结出来的规矩一次性讲清楚,从最基本的单图插入,到浮动体原理、子图排版、交叉引用,再到最后的问题排查,争取让刚上手的人少走点弯路。
其实 LaTeX 的图片排版不是“插入一张图”这么简单,背后是一整套浮动体机制。如果不理解这个机制,你大概率会在“图片为什么自己乱跑”这个问题上纠结一整晚。这篇内容是基于我长期实战总结的经验,会有大量可直接复制运行的示例、对照参数和排错技巧。适合用 LaTeX 写论文、做报告、搭技术文档的读者,不管是刚入门的小白,还是被图片位置折磨得想摔键盘的老手,应该都能从中找到对自己有用的东西。
1. 先搞清楚环境:graphicx 和编译模式
1.1 只需要一个宏包:graphicx
不管你是用哪种 LaTeX 发行版,插图的第一步都是从\usepackage{graphicx}开始。这个宏包提供了\includegraphics命令,是整个图片排版的基石。
很多人会问,不是还有个graphics宏包吗?两者有什么区别?简单说,graphics是基础版,graphicx是增强版,后者的参数走key=value风格,写起来更直观。比如\includegraphics[width=0.8\linewidth]{fig}这种写法,在graphicx里顺理成章。除非你的模板明确用了graphics,否则我建议一律用graphicx。
注意一点:很多现成的论文模板已经在导言区加载过graphicx了。你自己再写一遍也不算错,但最好先翻一下模板文件,确认有没有、有没有带什么可选参数,免得和模板内部配置冲突。我遇到过一位同学,模板里用的是老版本语法,他自己又加了[dvips]选项,结果在pdflatex下编译直接报一堆奇怪错误,折腾了半小时才发现是选项问题。
如果后面要用到浮动体固定位置、子图、图文绕排,我会另外推荐float、subcaption、wrapfig这几个宏包。它们不是必须一次性全装,按需加载就好。
1.2 编译方式决定图片格式选型
很多新手忽略了一个关键因素:你用的编译方式,直接决定了哪种图片格式能用得舒心。这地方如果没搞清楚,后面全是坑。
常见的编译链有三类:
pdflatex:直接产出 PDF,原生支持 PDF、PNG、JPG、TIFF 等格式。缺点是老式的 EPS 图不能直接用,除非挂epstopdf宏包让它在编译时自动转成 PDF。xelatex:同样产出 PDF,支持中文字体配置,图片格式支持和pdflatex大致相同,处理 EPS 也更灵活一些。latex + dvipdf:这是老古董组合,配合 PS 体系下的 EPS 图最顺,但插 PNG/JPG 反而麻烦。
我的建议很明确:新项目直接上pdflatex或xelatex,图片优先使用 PDF 矢量图。为什么?因为矢量图无论怎么缩放都不失真,文字、线条永远清晰,论文里的流程图、实验曲线、架构示意图,都应该尽量用矢量格式保存。截图这类位图素材,用 PNG 就行,除非是摄影照片才考虑 JPG,否则 JPG 的压缩痕迹会在文字边缘特别明显,印刷出来尤其难看。
位图还有一个分辨率要求:如果是准备投稿或者打印,至少 300 dpi;如果只是电子版阅读,150 dpi 勉强能看。比如用 MATLAB 或 Python 绘图,保存的时候直接选 PDF 格式,比导出 PNG 再放大要省心得多。
1.3 图片路径怎么组织最省心
默认情况下\includegraphics{fig}只会去当前目录找图片。项目一复杂,图片全堆在根目录会乱成一锅粥。这时候可以用\graphicspath指定图片目录:
\graphicspath{{figures/}{figs/}}这个命令写在导言区,接受多个相对路径,每个路径必须用大括号包起来,而且必须以斜杠结尾。设置好之后,正文里写\includegraphics{fig1}就会自动去figures和figs目录里找,非常省事。
我有几条亲测有效的经验:
- 尽量用相对路径,不用绝对路径。绝对路径换个机器就要改,相对路径整个项目目录拷走就能编译。
- 文件名不要带空格、中文和奇怪符号。虽然
xelatex现在对中文文件名的兼容性好了不少,但跨平台、换编辑器的时候仍然可能出幺蛾子。统一用fig1、fig_test_01这种命名最稳。 - 如果图片文件名带下划线,在
\includegraphics参数里直接用没问题,不用转义。 - 同一个图片最好只保留一种格式,不要 PDF、PNG、JPG 三份同时放在目录里,否则不加扩展名时 LaTeX 的自动匹配顺序可能会让你意外。
2. 单图插入:命令细节与大小控制
2.1 最基本也是最高频的插入命令
单张图的插入标准写法是这样的:
\begin{figure}[htbp] \centering \includegraphics[width=0.8\linewidth]{fig_example} \caption{这是一个示例图} \label{fig:example} \end{figure}逐行拆开讲一下。
\begin{figure}[htbp]是浮动体环境,htbp是位置参数,后面第 3 节会详细说。\centering让图片水平居中。\includegraphics是插图命令,width=0.8\linewidth表示图片宽度占当前行宽的 80%。\caption生成图的标题和自动编号,\label则给这张图一个引用标签,方便正文中“如图 X 所示”。
这里最容易忽略的是\caption和\label的顺序。正确做法是先写\caption再写\label,因为\label默认引用的是最近一个计数器的值。如果你把\label放在\caption前面,引用的时候会拿到上一个图的编号,这个错误平时不明显,等图多了才发现,特别恼火。
还有一个细节:\includegraphics的文件名我没写扩展名。这是故意的,LaTeX 会自动为你选择合适的格式,同时就算你后来把图片从 PDF 换成 PNG,源码也不用改。但前提是目录里同一个图片只保留一种格式,否则可能选中意外的那份。
2.2 图片大小控制的三个维度
控制图片大小主要看三个参数:width、height、scale,外加一个辅助参数keepaspectratio。
width是最常用的,指定图片最终宽度。height指定高度。scale是一个倍数系数,1 表示原始尺寸,0.5 表示缩小一半。
我最推荐的是width=0.8\linewidth这种相对尺寸写法,而不是scale=0.5。原因很简单:不同图片的原始尺寸千差万别,scale需要一张张去试,而相对宽度一眼就能判断图片会不会超出版心、和旁边文字的比例是否协调。比如双栏论文里,一幅单栏图用width=\linewidth,跨栏图用width=2\linewidth,控制起来非常清晰。
只用width不加height时,LaTeX 会按图片原始比例自动缩放,这是最稳妥的。如果同时指定width和height,等于强制把图片拉伸到指定宽高,可能造成比例变形,必须加keepaspectratio=true来避免。
一个很实用的组合是:
\includegraphics[width=0.7\linewidth, height=0.4\textheight, keepaspectratio]{fig}意思是:优先保证宽度 70%,但如果按这个宽度缩放后高度超过页面可用高度的 40%,那就反过来以高度为准,并且始终保持图片原始比例。处理长图、大图时这个组合几乎是万能解。
2.3 选对图片格式:矢量优先,位图备用
图片格式这件事,值得专门花点篇幅讲。很多 LaTeX 排版怪问题的根源,其实都能追溯到图片格式上。
图片分两大类。矢量图包含的是几何描述,放大缩小不损失质量,PDF、EPS、SVG 都算。位图就是像素点阵,PNG、JPG、TIFF 都属于这类,放大到一定程度就会模糊。
做论文排版,示意图、绘图、流程图这些能生成矢量图的,就绝对不要用位图。我自己用 Python 的 matplotlib 画完图,保存时一定选 PDF 格式;画流程图的工具支持导出 PDF 也用它。如果项目图是别人给的位图,尽量让源头方重新导一次 PDF,拿不到高分素材就只能在 LaTeX 端控制分辨率了。
位图的原生分辨率不足,是很多“图片模糊”问题的真正元凶。打印或者投期刊,位图至少 300 dpi;只是电子版浏览,150 dpi 也能凑合。用像素除以英寸可以简单估算:一张 1500×1200 像素的图,按 300 dpi 输出,大约能印刷 5 英寸宽,如果排出来超过这个宽度就会发虚。
还有一点经验之谈:如果图上有中文文字、注释,导出 PDF 后最好亲自打开检查一遍。有些工具导出的 PDF 文字字体没嵌入,在别的设备上打开可能显示异常,而在 LaTeX 里加载时也可能出现怪异的警告。
3. 浮动体机制:图片为什么总是不听你的话
3.1 先理解 LaTeX 的“浮动”逻辑
这是所有图片排版问题的核心。我可以负责任地说:绝大多数“图片乱跑”的抱怨,根源都是没理解浮动体机制。
LaTeX 不是 Word,它不会把图片当作“嵌入在某个位置的对象”老老实实放好。对 LaTeX 来说,图片是一个浮动体对象,可以延迟放置到最合适的位置,以保证页面整体美观。这个设计对长文档排版非常有利:LaTeX 可以在当前页放不下图的时候,把它顺延到下一页的顶部或底部,避免页面出现大段空白。
生活化类比:浮动体有点像排队上车的旅客。正文文本是固定座位,图片这个旅客不用严格按照票面座位走,调度员会看哪节车厢松快、哪个位置放图不影响人流,就给安排在哪。所以,你写了\begin{figure}之后,图片出现在后面的某个位置,实际上是很正常的事,并非 bug。
想要用好 LaTeX,第一步就是接受“浮动体需要交给 LaTeX 调度”这个理念。强行要求所有图片固定在一处,反而是和 LaTeX 的设计原则对着干。
3.2 位置参数详解:h、t、b、p 到底是什么意思
figure环境后面的方括号参数,就是允许这个浮动体出现的候选位置。最常写的是[htbp],逐个说:
h:here,表示当前位置,也就是图片代码所在的地方,可以理解为“优先放这儿”。t:top,页面顶部。b:bottom,页面底部。p:page,单独开一页来放这些浮动体。
这些字母可以自由组合。[h]就是只允许当前位置,[htbp]是允许任何位置,LaTeX 会按 h、t、b、p 的顺序尝试。
注意,[h]并不保证一定成功,LaTeX 如果觉得当前位置放不下、会影响版面,它会自己往后顺延,哪怕你只给了h。所以初学者写[h]发现图还是跑了,就是这么来的。
加一个感叹号[!htbp]会提高请求的紧迫程度,让 LaTeX 尽量满足,但依然不是“强制命令”,只是加强了语气。真正要强制固定位置,需要看下一节。
这里还要补充一个被忽略的事实:如果你写\begin{figure}不指定任何位置参数,很多文档类的默认行为等价于[tbp],也就是“优先顶部”。所以你以为没写参数就表示“放在这里”,实际 LaTeX 听到的却是“尽量放页面顶部”。
浮动体同一页的数量也有限制。LaTeX 默认不允许一整页全放图,也不希望某页被浮动体塞满。控制这些行为的是\topfraction、\bottomfraction、\textfraction这些内部参数,正式排版时如果对浮动位置特别挑剔,可以微调它们,但新手阶段不建议碰。
一个我自己整理的实用表格:
| 参数写法 | 实际效果 | 适用场景 |
|---|---|---|
| 空 | 默认等价于 tbp | 不推荐,容易违背预期 |
[h] | 尽量在当前位置,不保证 | 字数少的短文档 |
[htbp] | 四位置任意选,最灵活 | 论文、长文档主流选择 |
[!htbp] | 加强请求,尽量满足 | 图片位置比较重要时 |
[H] | 完全固定在当前位置 | 严格图文对应,如操作步骤 |
3.3 强制定位的三种实用方案
有些场景真的需要图片固定于某个位置,比如操作步骤中的配图、程序代码和运行截图对照,浮动体拆开步骤会让人读起来很难受。这时有三条路可走。
方案一:使用[H]参数。导言区加\usepackage{float},然后把figure环境写成\begin{figure}[H]。注意是大写的 H,表示 Here 的强制版。[h]只是建议,[H]是命令。图片会老老实实呆在代码位置,不再浮动。
方案二:完全不用figure环境,只写\includegraphics,然后配合caption宏包的\captionof命令手动加标题和编号。
\centering \includegraphics[width=0.8\linewidth]{fig} \captionof{figure}{这张图不浮动,放在当前位置} \label{fig:fixed}方案三:用minipage盒子包住图片,标题同样用\captionof。这种方式在需要严格排布、并排、对齐的场景更灵活。
我的经验是:正式论文、书稿,尽量少用[H]。强制固定位置很容易在页面底部留下大块空白,使得版面松散。我自己写课程报告时曾经把所有图都挂[H],结果每一页底部都空出一大截,后来改成大部分[htbp],整个版面瞬间清爽了。[H]适合课程报告、实验记录、内部技术文档这类对排版美观度要求没那么高、但要求图文紧密对应的文档。
4. 进阶排版:子图、并排与图文绕排
4.1 子图排版:subcaption 宏包的正确用法
理工科论文里,经常需要把两张或多张相关性很强的图合成一个主图,每个子图编号为 (a)、(b),共用“图1”这个主编号。这个需求用subcaption宏包实现最标准。
导言区加上\usepackage{subcaption},然后这样写:
\begin{figure}[htbp] \centering \begin{subfigure}[b]{0.45\linewidth} \centering \includegraphics[width=\linewidth]{fig_a} \caption{第一个子图} \label{fig:suba} \end{subfigure} \hfill \begin{subfigure}[b]{0.45\linewidth} \centering \includegraphics[width=\linewidth]{fig_b} \caption{第二个子图} \label{fig:subb} \end{subfigure} \caption{整体子图标题} \label{fig:subtotal} \end{figure}编译出来的效果是:两张图并排,主图编号为“图1”,子图编号分别为 (a)、(b)。正文里引用\ref{fig:suba}得到的是 “1a” 这种格式,非常自然。
有几个坑必须提醒:
第一,subcaption宏包和老的subfigure、subfig宏包互不兼容,导言区绝对不能同时加载。我接过一个别人的模板,里面用的subfigure,我自己又加了subcaption,编译报错怎么也查不出来,最后把模板宏包列表翻了一遍才找到冲突。所以你动手之前,先确认模板加载了什么。
第二,子图宽度通常写成0.45\linewidth而不是0.5\linewidth。因为两个子图之间还要留一点空隙,写 0.5 加上\hfill,很可能挤不下导致自动换行,出来的排版就乱了。
第三,如果子图本身有内容需要特别说明,在主标题里做概括,子图标题里写细节,不要全堆在主标题里。
4.2 并排插入两张独立图的两种方式
不是所有并排图都是子图关系。有时候你只是希望两张独立的图并排放着,各自拥有独立的“图1”“图2”编号。这时候可以用minipage实现。
\begin{figure}[htbp] \centering \begin{minipage}[t]{0.48\linewidth} \centering \includegraphics[width=\linewidth]{fig1} \caption{第一张独立图} \label{fig:one} \end{minipage} \hfill \begin{minipage}[t]{0.48\linewidth} \centering \includegraphics[width=\linewidth]{fig2} \caption{第二张独立图} \label{fig:two} \end{minipage} \end{figure}这里的0.48\linewidth同样是为了留出两列之间的空隙。\hfill会把两个 minipage 推到左右两端。如果你想控制间隔宽度,可以把\hfill换成\hspace{2em}。
两种并排方式的区别在于:subcaption是“大图套小图”,主图只有一个编号,子图是附属编号;minipage方式是“两张图各自独立”,各编各号。使用场景完全不同,但是代码结构很相似。
在实际排版里,如果两张图有明显因果关联、需要放在一起对比,我推荐用子图方式,因为主图编号可以作为一个整体被正文引用,表述上简洁很多。如果两张图只是碰巧挨在一起,没有整体语义,那就用独立figure环境里的 minipage 更合适。
4.3 文字环绕图片:wrapfig 的使用与禁忌
排版讲义、博客长文或者非正式文档时,经常会想把图塞在段落侧边,让文字绕过去。LaTeX 里最常用的宏包是wrapfig。
\usepackage{wrapfig}正文中使用:
\begin{wrapfigure}{r}{0.4\textwidth} \centering \includegraphics[width=0.38\textwidth]{fig} \caption{绕排图标题} \label{fig:wrap} \end{wrapfigure}这里的{r}表示图在右侧,文字绕左侧;换成{l}则图在左侧。第二个参数0.4\textwidth是绕排图占用的宽度。
wrapfig是出了名的娇气,使用限制很多:
- 它前面必须有已经写完的普通正文段落,不能刚从
\section标题出来就用。 - 不要在
itemize、enumerate列表内部使用。 - 不要在两个相邻的
wrapfigure之间连续使用。 - 图片高度如果超过页面可绕排区域的 70%,排版很容易错乱。
- 如果绕排出来的文字和图片重叠了,优先缩小图片宽度试试。
我的个人经验是:学术论文里很少用wrapfig,因为有些期刊模板要求图表独立成块,绕排不符合出版规范。但在课程讲义、PPT 素材、个人技术笔记这些场合,它确实能让版面显得灵活不少。注意加\caption后,编号依然会加入图计数器,如果你后续交叉引用到了这张图,位置移动也不影响引用。
5. 图片标题与交叉引用:论文的体面
5.1 标题写得好,阅读体验差不了
\caption{}里的文字是图片的正式标题,不需要长篇大论,但也不能太敷衍。一个好标题应该让读者不读正文也能猜到图里讲了什么。
子图多的场景,我习惯写成概括式的主标题,比如“系统整体架构与关键模块交互示意”,然后在每个子图的\caption里写具体内容,比如“(a) 用户登录模块;(b) 权限控制模块”。这样正文引用主图时可以用一句话带过整个组图。
还有几个规范要记住:
\caption写在\label之前,这是引用正确编号的前提。- 标题里的标点符号、断句按正常书写来,不需要刻意加空格。
- 如果图片本身没有任何说明意义,纯装饰性,可以考虑不加
\caption,用\includegraphics加\centering直接放在figure环境里就行。不过多数正式文档不建议无标题图。
插图编号的格式在设备类文章里默认是全文连续编号(图1、图2),在 report/book 里默认是章内编号(图1.1、图1.2)。这些由文档类决定,没有必要去改计数器。只有导师明确要求统一编号时,再去动\counterwithout这类命令。
5.2 交叉引用:让“如图 X 所示”全部自动更新
图片最多的工作是供正文引用。LaTeX 里引用图片编号的正确姿势,是在图片里加\label,然后在正文用\ref或者\autoref。
常见写法:
如图~\ref{fig:example} 所示,系统的整体行为可以分成三个阶段。编译后自动变成“如图 1 所示”。这里的~很关键,它表示不换行空格,防止“图”和“1”被分到两行。同样,写表格、公式引用时也建议用~。
如果希望自动生成“图 1”中的“图”字,可以用\autoref{fig:example},前提是导言区加载hyperref宏包。\autoref会根据标签类型自动判断是图、表还是公式,很省事。再进一步,用cleveref宏包的\cref{fig:example}效果更细腻,连续引用多个标签时格式也智能很多。
\usepackage{hyperref} \usepackage{cleveref}注意cleveref最好放在导言区比较靠后的位置,不要被其他宏包覆盖它的设置。
交叉引用正常工作的前提是编译两遍甚至三遍。第一遍生成.aux辅助文件,第二遍读取编号。如果正文里显示的是“??”,多半就是只编了一遍,或者.aux文件损坏。用 Overleaf 或常见编辑器时,只要启用了自动编译两次,基本不用关心。但如果你在命令行手工编译,一定要记住编两遍再检查引用。
有一类低级失误值得提醒:同一张图的\label被复制到了两张不同图片后面,导致引用结果都是同一编号。排查方法是在文档中搜索\label{fig:,看看是否有重复定义。如果用了cleveref,重复标签在编译日志里通常会有 warning,留意一下。
6. 踩坑实录:常见问题与排查技巧
6.1 图片显示不出来的原因清单
遇到图片不显示、编译报错,先对照这张排查表走一遍:
| 症状 | 可能原因 | 处理办法 |
|---|---|---|
| File `xxx' not found | 文件名写错、路径没配置 | 核对\includegraphics文件名大小写,检查\graphicspath |
| Cannot determine size of graphic | 图片格式与编译器不匹配,常见 EPS 在 pdflatex 下 | 转换成 PDF 或加epstopdf宏包 |
| 图片空白但编译正常 | 图片文件损坏、上传不完整 | 重新导出图片或重新上传 |
| 图片位置和预期差距巨大 | 浮动体机制生效 | 见第 3 节,调整位置参数或使用[H] |
| 引用显示 ?? | 只编译了一遍 | 重新编译两遍以上 |
文件名的坑要单独拎出来说:LaTeX 在 Linux 环境下对文件名大小写敏感,Windows 不敏感。所以在本机 Windows 上能编译的文档,传到 Linux 服务器或 Overleaf 上可能因为Fig.png和fig.png不一致而报错。稳妥做法是全部统一成小写字母,全程保持一致。
还有一个隐蔽问题:当图片文件名中包含多个点时,LaTeX 可能会把最右边的点当成扩展名。比如图片叫fig.v2.png,写\includegraphics{fig.v2}实际上会去找fig.v2.png?不一定,有些版本会解析错误。碰到这种名字,直接换成无点文件名最省事。
6.2 位置失控的几种具体场景与对策
最典型的情况是:图片在当前段落位置出现了,但是排版效果不好,它跑到了页面底部或下一页。这是浮动体在发挥调度作用,是正常现象。
如果你真的需要“图尽量靠近第一次被引用的位置”,有一种经验做法:把figure环境的代码写在正文引用段落的紧后面,而不要集中把所有图放在章节末尾。LaTeX 浮动体定位至少可以参考代码顺序,你让它尽早出现,它就更有可能靠近引用处。
还有一种情况是两张图颠倒了顺序。LaTeX 通常保持同类型浮动体的相对顺序,但如果两个figure中间隔着大量文本和页面边界,且位置参数写得太死,可能出现前图排到后图后面的情况。只要两张图关系紧密,就合成一个figure环境用子图,最保险。
如果整个文档图片很多,但某一章空白特别多,可以看看是不是图片尺寸太大,导致 LaTeX 找不到合适的插放位置。把图片统一限制在width=0.85\linewidth左右,会让浮动体调度的自由度大很多。
6.3 图片溢出页面:谁都可能遇到的“巨图灾难”
图片比页面还宽、超出页边距甚至被截断,是另一个高频问题。直接对策是把宽度限制在\linewidth以内:
\includegraphics[width=\linewidth, keepaspectratio]{big_fig}如果图片不仅宽,还特别高,加上height=0.8\textheight保底:
\includegraphics[width=0.9\linewidth, height=0.7\textheight, keepaspectratio]{big_fig}这个写法能保证图在宽、高两个方向都不过界,而且不变形。
还有一个容易被忽视的“假溢出”:图片来源文件自带大片空白边。有些工具导出的 PDF 每一页都是完整页面尺寸,但实际内容只占中间一小块,视觉上你会发现图片很小却占了很大浮动空间。用pdfcrop这类工具把白边裁掉,再放进 LaTeX 里就正常了。流程是在命令行执行pdfcrop input.pdf output.pdf,然后把output.pdf用作插图。
另外,如果你用了\scalebox{0.5}{...}这类缩放命令来强行缩小图片,要小心它会把图连同文字一起缩放,导致图中文字和正文文字大小不协调。图片里自带的文字,在缩放后比例会变得很怪,所以最好还是在源软件里按最终比例导出,而不是在 LaTeX 端硬缩放。
7. 最后再分享一点个人体会
这些经验总结下来,核心其实就是几件事:统一图片格式、用相对尺寸控制大小、理解浮动体机制、规范交叉引用。一旦把这几条变成肌肉记忆,图片插入就再也不会让你半夜对着屏幕叹气。
我自己在近百篇文档里反复折腾之后,最大的感受是:好图片是“做”出来的,不是“调”出来的。写 LaTeX 之前先把图片裁剪干净、格式统一、分辨率搞定,整个排版过程会顺利很多。与其在scale参数里反复微调,不如回到绘图工具把画布尺寸、字号、线条粗细一次调好。很多排版阶段的奇怪问题,追根溯源都出在图片本身的准备环节。
如果你也遇到过“同样的图片在别人文档里好好的,在我这儿就乱跑”的困惑,多半就是浮动体参数或者宏包冲突的问题。把这篇里的检查清单对着查一遍,基本能解决八成以上。下一篇文章我打算把表格这块的大坑也梳理一遍,里面同样有大量让人挠头的细节。