虽然这不是纯粹的 XSL FO,但我已经使用 RenderX 的软件实现了类似的解决方案。该解决方案涉及将页面格式化为区域树,这是一种 XML 结构,包含页面的所有详细信息,包括文本位置。使用特殊扩展(即 rx:pinpoint 元素),源 XSL FO 将这些标记包含在您希望羽化内容的任何位置。
原始文档使用放置在流和页脚区域中的颜色来计算页面上的可用空间。
然后,所有这些信息都在区域树中可用。使用 XSL 修改区域树,可以“测量”可用的空白空间,除以羽化点的数量,然后修改区域树以“移动”内容发布组合但在最终输出之前。大多数格式化程序都允许您修改序列化区域树,然后将其返回给软件以进行最终输出。
下面的关键是了解 xep:translate 元素,该元素可用于将区域树中的所有后续内容向下移动。因此,要“轻推”所有区域,只需在每个允许的“轻推”点插入其中一个,以将内容向下移动(可用空白/轻推点数)。
我不知道您使用的是什么格式化程序,但如果不是 RenderX,也许您可以修改以下内容以满足您的需要。这实际上在几个应用程序中使用,其目的是“羽化”所有页面,以便页面的文本内容始终在页面末尾结束。
样品链接:
http://www.tandesa.com/Public/Nudge/sf-orig.pdf(这是如果不应用轻推将创建的原始文件)
http://www.tandesa.com/Public/Nudge/sf-nofeather.pdf(这显示了如果在轻推之前输出区域树会是什么样子,通常没有完成,但它显示了如何使用红色/蓝色区域用于计算可用微调区域)
http://www.tandesa.com/Public/Nudge/sf-nudged.pdf(轻推的结果)
http://www.tandesa.com/Public/Nudge/nudge.xsl(以下文件为完整性)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xep="http://www.renderx.com/XEP/xep" xmlns:math="http://exslt.org/math"
extension-element-prefixes="math" version="1.0">
<xsl:param name="max-feather-percent">40</xsl:param>
<xsl:param name="body-color" select="'1.0'"/>
<xsl:param name="footer-color" select="'1.0'"/>
<xsl:template match="xep:document">
<xsl:copy>
<xsl:apply-templates select="@*" mode="identity-copy"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="xep:internal-bookmark">
<xep:internal-bookmark>
<xsl:apply-templates select="@*" mode="identity-copy"/>
</xep:internal-bookmark>
</xsl:template>
<xsl:template match="xep:page">
<xep:page>
<xsl:apply-templates select="@*" mode="identity-copy"/>
<!--
1) Figure out white space
a) Extract the y-till of the footer-color rectangle
b) Find the smallest y-till of the body-color rectangle
c) (b) - (a) is white space
-->
<xsl:variable name="headertop"
select="number(xep:rectangle[preceding-sibling::xep:rgb-color[1][@red=$footer-color]]/@y-till)"/>
<xsl:variable name="pagebottom"
select="math:min(xep:rectangle[preceding-sibling::xep:rgb-color[1][@red=$body-color]]/@y-from)"/>
<xsl:variable name="whitespace" select="$pagebottom - $headertop"/>
<!--
2) Count the nudge areas
The nudge areas are all the pinpoints that start with "feather" *except* the first one on the page
and possibly the last one (need to determine it a nudge ends the page then exclude it also)
<xep:pinpoint x="90000" y="966000" value="feathersection"/>
Current implementation only ignores the first one and not the last
-->
<xsl:variable name="nudgepoints"
select="count(xep:pinpoint[starts-with(@value,'feather')]) - 1"/>
<!--
3) Calculate the nudge factor for each
-->
<xsl:variable name="nudgefactor" select="$whitespace div $nudgepoints"/>
<!--
4) Determine whether the page should be feathered at all
a) No nudgepoints
b) Space to compensate for is greater than max-feather-percent
-->
<xsl:variable name="apply-nudge">
<xsl:choose>
<xsl:when test="$nudgepoints = 0">
<xsl:text>false</xsl:text>
</xsl:when>
<xsl:when test="($whitespace div @height) > ($max-feather-percent div 100)">
<xsl:text>false</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>true</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:comment>
headertop: <xsl:value-of select="$headertop"/>
pagebottom: <xsl:value-of select="$pagebottom"/>
nudgepoints: <xsl:value-of select="$nudgepoints"/>
nudgefactor: <xsl:value-of select="$nudgefactor"/>
headertop: <xsl:value-of select="$headertop"/>
pagebottom: <xsl:value-of select="$pagebottom"/>
applynudge: <xsl:value-of select="$apply-nudge"/>
</xsl:comment>
<xsl:apply-templates select="*" mode="identity-copy">
<xsl:with-param name="nudgepoints" select="$nudgepoints"/>
<xsl:with-param name="nudgefactor" select="$nudgefactor"/>
<xsl:with-param name="apply-nudge" select="$apply-nudge"/>
</xsl:apply-templates>
</xep:page>
</xsl:template>
<!-- Replace proper pinpoints with xep:transform -->
<xsl:template match="xep:pinpoint[starts-with(@value,'feather')]" mode="identity-copy">
<xsl:param name="nudgepoints"/>
<xsl:param name="nudgefactor"/>
<xsl:param name="apply-nudge"/>
<xsl:if test="count(preceding-sibling::xep:pinpoint[starts-with(@value,'feather')]) > 0 and $apply-nudge = 'true'">
<xep:translate x="0">
<xsl:attribute name="y">
<xsl:value-of select="-1 * $nudgefactor"/>
</xsl:attribute>
</xep:translate>
</xsl:if>
</xsl:template>
<xsl:template match="xep:pinpoint[starts-with(@value,'dontfeather')]" mode="identity-copy">
<xsl:param name="nudgepoints"/>
<xsl:param name="nudgefactor"/>
<xsl:param name="apply-nudge"/>
<xsl:if test="count(preceding-sibling::xep:pinpoint[starts-with(@value,'dontfeather')]) = 0 and $apply-nudge = 'true'">
<xep:translate x="0">
<xsl:attribute name="y">
<xsl:value-of select="$nudgepoints * $nudgefactor"/>
</xsl:attribute>
</xep:translate>
</xsl:if>
</xsl:template>
<!-- Strip out the colored boxes -->
<xsl:template match="xep:rgb-color[@red='{$body-color}']" mode="identity-copy"/>
<xsl:template match="xep:rgb-color[@blue='{$footer-color}']" mode="identity-copy"/>
<xsl:template match="xep:rectangle[preceding-sibling::xep:rgb-color[1][@red='{$body-color}']]" mode="identity-copy"/>
<xsl:template match="xep:rectangle[preceding-sibling::xep:rgb-color[1][@blue='{$footer-color}']]" mode="identity-copy"/>
<!-- identity copy rules -->
<xsl:template match="node() | @*" mode="identity-copy">
<xsl:copy>
<xsl:apply-templates select="@*" mode="identity-copy"/>
<xsl:apply-templates select="node()" mode="identity-copy"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>