在XSL-FO样式表里插入图片,靠的是fo:external-graphic这个元素。它属于内联级对象,通常放在fo:block或表格单元格里,根据src属性加载外部文件。和HTML的<img>标签类似,但它没有alt属性,尺寸控制、缩放策略以及对分页区域的处理都更接近印刷排版。

下面的内容会从元素语法、路径加载机制、缩放与对齐、常见故障四个方向展开。如果你已经能写出FO模板但图片一直空白,可以直接跳到路径解析和排查部分。
一、基本语法与核心属性
fo:external-graphic在XML结构上是一个空元素,不能包含文本或子节点,必须放在可以容纳内联内容的容器中。最简单的用法如下:
<fo:block font-size="10pt">
<fo:external-graphic src="url(images/logo.png)"
content-width="120pt"
content-height="40pt"
scaling="uniform"/>
</fo:block>
src接收一个URI规范,常见写法是url(images/logo.png)或直接写images/logo.png。使用url()时,圆括号里可以带引号,也可以不带,但如果路径中包含空格、中文或特殊符号,建议进行URL编码。属性content-width和content-height用来指定图片在目标区域中的尺寸,单位可以是pt、mm、cm、in等绝对单位,也可以使用百分比。
下面是一个更完整的FO文档结构,展示了fo:external-graphic在页面流中的位置:
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4" page-width="210mm" page-height="297mm">
<fo:region-body margin="20mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:external-graphic src="url(images/photo.png)"
content-width="160mm"
scaling="uniform"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
这个模板中只指定了content-width="160mm",没有指定content-height。对于大多数FO处理器,图片会根据自身的固有宽高比自动计算高度。这种写法比较稳健,适合不清楚原图精确像素尺寸的场景。
二、路径解析与图片加载规则
很多图片无法显示的问题,最终定位出来都不是元素写错,而是相对路径的基准目录没有搞清。在FOP这样的常见处理器中,src里的相对路径通常以FO文件所在目录作为基准,而不是以执行命令时的工作目录为基准。也就是说,如果FO文件位于/opt/app/fo/目录,图片位于/opt/app/fo/images/logo.png,那么直接写url(images/logo.png)就能找到。但如果FO文件与图片不在同一层级,就需要通过../或绝对路径来定位。
如果需要统一改变相对路径的基准,可以在fo:root上使用xml:base属性。例如:
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
xml:base="file:///opt/app/resources/">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4" page-width="210mm" page-height="297mm">
<fo:region-body margin="20mm"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4">
<fo:flow flow-name="xsl-region-body">
<fo:block>
<fo:external-graphic src="url(images/logo.png)"/>
</fo:block>
</fo:flow>
</fo:page-sequence>
</fo:root>
此时图片的实际加载地址会成为file:///opt/app/resources/images/logo.png。FOP命令行还提供-base参数来指定基准目录,例如:
fop -xml article.fo -pdf output.pdf -base /opt/app/resources
图片格式方面,Apache FOP对PNG、JPEG、SVG、GIF、BMP等格式都有基本支持,但在实际生产环境中PNG和JPEG兼容性最好。如果使用SVG,通常需要确保FOP能够正确调用Batik库。对于打印场景,建议使用较高分辨率的PNG图片,避免在缩放后出现锯齿或模糊。
三、缩放与对齐的深入处理
scaling属性有两个常用取值:uniform和non-uniform。uniform表示等比缩放,图片会保持原始宽高比,不会产生变形;non-uniform则允许宽度和高度分别匹配指定的content-width和content-height,代价是可能拉伸或压缩图片。打印文档中一般优先使用uniform。
如果同时指定了content-width="120pt"和content-height="40pt",但原图比例并不是3:1,使用scaling="uniform"时图片会等比缩放后放入区域,多余空间会留白。如果希望图片完全填满区域且不介意变形,才可以改为scaling="non-uniform"。更常见的做法是只指定宽度,让处理器自动计算高度,这样既能满足版式宽度,又不会破坏比例。
对齐方面,图片在fo:block内默认是基线对齐,如果要实现水平居中,可以给外层块设置text-align="center"。垂直方向可以通过display-align或调整line-height来控制。例如:
<fo:block text-align="center" line-height="12pt">
<fo:external-graphic src="url(images/icon.png)"
content-width="32pt"
content-height="32pt"
scaling="non-uniform"/>
</fo:block>
如果图片高度与行高不一致,还可能出现周围空白偏大的情况。此时可以减小line-height或直接使用display-align="center"配合固定容器高度来处理。
四、常见问题排查与最小验证
遇到图片无法显示时,先检查src路径。推荐先用一个最小FO模板单独测试图片加载,避免页面布局、分页或其他元素干扰判断。如果图片文件确实存在但页面仍然空白,可以查看FO处理器的控制台输出,通常会有资源加载失败或格式不支持的提示。
- 图片区域空白:检查相对路径基准是否正确,文件名大小写是否一致,文件权限是否可读。可以把
src改为绝对URI测试,例如file:///opt/app/images/logo.png。 - 图片变形:确认
scaling取值。若不需要精确填满区域,应使用uniform,并且尽量只指定content-width或content-height中的一项。 - 路径包含空格或中文:使用URL编码,空格替换为
%20,中文按UTF-8编码处理。也可以将图片文件名改为纯英文小写,减少编码问题。 - 格式不支持或颜色异常:将图片统一转换为PNG或JPEG。印刷输出通常使用sRGB颜色空间,CMYK的JPEG图片在部分处理器中可能显示异常。
- 高分辨率图片过大:如果位图尺寸远大于版式区域,不仅浪费内存,还可能导致PDF体积膨胀。可以预先将图片缩放到合适的像素尺寸,再通过FO属性做细调。
排查问题最有效的方法是建立一个只包含fo:external-graphic的最小FO文件,逐步调整路径和属性。每次修改只变动一个条件,观察输出结果,通常很快就能定位到具体原因。
掌握了src路径规则、scaling缩放策略以及常见处理器的差异,XSL-FO插入图片就会变得相当稳定。相比HTML中的图片加载,FO更依赖对路径基准和打印尺寸的理解,而这些规则一旦清晰,图片丢失、变形和空白页问题大多可以提前避免。
XSL-FOfo:external-graphic插入图片修改时间:2026-09-27 10:44:32