【问题标题】:XSL-FO: How to prevent Instream foreign object from being trimmed?XSL-FO:如何防止 Instream 异物被修剪?
【发布时间】:2014-07-06 15:19:52
【问题描述】:

我正在使用 Apache FOP 生成一个 PDF,其中包含一个内容为 svg 文档的 instream-foreign-object 元素。我遇到了一个问题,最左边的边缘似乎像这样被修剪掉了:

这些图像被放置在一个表格中。每个包含表格单元格的大小由 SVG 中的宽度和高度属性设置。我尝试修改宽度值并将溢出属性显式设置为“可见”。这些都不起作用。我应该说,当应用程序在 Windows 机器上运行时,不会发生这种剪辑,但在 Linux 上会出现这种情况。我不知道这是否是一个问题,因为 W3C 文档提到溢出可以根据操作系统进行不同的处理。

包括来自流元素的 XSL 的相关部分以及将 svg 应用于模板的模板。有人可以帮忙吗?

<fo:page-sequence id="chartsPage" master-reference="landscape">
                    <fo:static-content flow-name="xsl-region-after">
                        <xsl:apply-templates select="exports/export" />
                    </fo:static-content>
                    <fo:flow flow-name="xsl-region-body">
                        <fo:block id="headersBlock" margin-top="0.5in" font-family="arial, helvetica, sans-serif" color="#5c068c" font-weight="bold" text-align="center">
                            <xsl:apply-templates select="exports/export/headers"/>
                        </fo:block>
                        <fo:block id="chartBlock" text-align="center">
                            <fo:table>
                                <fo:table-body>
                                    <fo:table-row>
                                        <xsl:apply-templates select="exports/export/charts/chart" />
                                    </fo:table-row>
                                </fo:table-body>
                            </fo:table>
                        </fo:block>...</fo:flow>

这是图表模板元素。每个输入图表元素都包含一个 svg 文档:

<xsl:template match="chart">
    <fo:table-cell>
        <fo:block width="{svg:svg/@width}px">
            <fo:instream-foreign-object width="80%" content-width="scale-to-fit" content-height="100%" scaling="uniform">
                <svg:svg width="{svg:svg/@width}" height="{svg:svg/@height}">
                    <xsl:copy-of select="svg:svg"/>
                </svg:svg>
            </fo:instream-foreign-object>
        </fo:block>
    </fo:table-cell>
</xsl:template>

这是上图的 svg。请注意这篇文章中包含的图像剪掉了图表标题和其他一些文本。它们在所有情况下都正确显示。我只附上了问题点。

<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" width="800" height="400">
<defs>
    <clipPath id="highcharts-59">
        <rect rx="0" ry="0" fill="none" x="0" y="0" width="9999" height="400" stroke-width="0.000001"/>
    </clipPath>
    <clipPath id="highcharts-60">
        <rect fill="none" x="0" y="0" width="757" height="210"/>
    </clipPath>
</defs>
<rect rx="5" ry="5" fill="#FFFFFF" x="0" y="0" width="800" height="400" stroke-width="0.000001"/>
<g class="highcharts-grid" />
<g class="highcharts-grid" >
    <path fill="none" d="M 33 215.5 L 790 215.5" stroke="#C0C0C0" stroke-width="1" />
    <path fill="none" d="M 33 145.5 L 790 145.5" stroke="#C0C0C0" stroke-width="1" />
    <path fill="none" d="M 33 75.5 L 790 75.5" stroke="#C0C0C0" stroke-width="1" />
    <path fill="none" d="M 33 285.5 L 790 285.5" stroke="#C0C0C0" stroke-width="1" />
</g><g class="highcharts-axis" >
    <path fill="none" d="M 789.5 285 L 789.5 290" stroke="#C0D0E0" stroke-width="1"/>
    <path fill="none" d="M 33 285.5 L 790 285.5" stroke="#C0D0E0" stroke-width="1"  visibility="visible"/>
</g><g class="highcharts-axis" />
<g class="highcharts-series-group" >
    <g class="highcharts-series" visibility="visible"  transform="translate(33,75)" clip-path="url(#highcharts-60)">
        <rect fill="#00569b" x="151" y="41" width="228" height="169" stroke-width="0.000001" stroke="#FFFFFF" rx="0" ry="0"/>
    </g><g class="highcharts-markers" visibility="visible"  transform="translate(33,75)" clip-path="none"/>
    <g class="highcharts-series" visibility="visible"  transform="translate(33,75)" clip-path="url(#highcharts-60)">
        <rect fill="#80abcd" x="378" y="31" width="228" height="179" stroke-width="0.000001" stroke="#FFFFFF" rx="0" ry="0"/>
    </g><g class="highcharts-markers" visibility="visible"  transform="translate(33,75)" clip-path="none"/>
    <g class="highcharts-series" visibility="visible"  transform="translate(33,75)" clip-path="url(#highcharts-60)">
        <path fill="none" d="M 0 0" stroke="black" stroke-width="5"   stroke-opacity="0.049999999999999996" transform="translate(1, 1)"/>
        <path fill="none" d="M 0 0" stroke="black" stroke-width="3"   stroke-opacity="0.09999999999999999" transform="translate(1, 1)"/>
        <path fill="none" d="M 0 0" stroke="black" stroke-width="1"   stroke-opacity="0.15" transform="translate(1, 1)"/>
        <path fill="none" d="M 0 0" stroke="#000000" stroke-width="2" />
    </g><g class="highcharts-markers" visibility="visible"  transform="translate(33,75)" clip-path="none">
        <path fill="#000000" d="M 378.50000000000006 67.1 C 383.82800000000003 67.1 383.82800000000003 75.1 378.50000000000006 75.1 C 373.1720000000001 75.1 373.1720000000001 67.1 378.50000000000006 67.1 Z" stroke="#FFFFFF" stroke-width="0.000001"/>
    </g>
</g>
<text x="395" y="25" style="font-family:arial,helvetica,sans-serif;font-size:12px;color:#3e576f;font-weight:bold;fill:#3e576f;" text-anchor="middle" class="highcharts-title" >
    <tspan x="395">XXXXXXXX XXXXXX</tspan>
</text>
<path fill="none" d="M 33 146 L 790 146" stroke="#000000" stroke-width="2" />
<g class="highcharts-legend"  transform="translate(353,295)">
    <g  clip-path="url(#highcharts-59)">
        <g>
            <g class="highcharts-legend-item"  transform="translate(8,3)">
                <path fill="none" d="M 0 11 L 16 11" stroke-width="2" stroke="#000000"/>
                <path fill="#000000" d="M 8 7 C 13.328 7 13.328 15 8 15 C 2.6719999999999997 15 2.6719999999999997 7 8 7 Z" stroke="#FFFFFF" stroke-width="0.000001"/>
                <text x="21" y="15" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:12px;cursor:pointer;color:#3e576f;font-weight:normal;padding-bottom:10;fill:#3e576f;" text-anchor="start" >
                    <tspan x="21">U.S. Total</tspan>
                </text>
            </g><g class="highcharts-legend-item"  transform="translate(8,32)">
                <text x="21" y="15" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:12px;cursor:pointer;color:#3e576f;font-weight:normal;padding-bottom:10;fill:#3e576f;" text-anchor="start" >
                    <tspan x="21">Current</tspan>
                </text>
                <rect rx="2" ry="2" fill="#80abcd" x="0" y="4" width="16" height="12" stroke-width="0.000001"  stroke="#80abcd"/>
            </g><g class="highcharts-legend-item"  transform="translate(8,61)">
                <text x="21" y="15" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:12px;cursor:pointer;color:#3e576f;font-weight:normal;padding-bottom:10;fill:#3e576f;" text-anchor="start" >
                    <tspan x="21">Previous</tspan>
                </text>
                <rect rx="2" ry="2" fill="#00569b" x="0" y="4" width="16" height="12" stroke-width="0.000001"  stroke="#00569b"/>
            </g>
        </g>
    </g>
</g><g class="highcharts-axis-labels" >
    <text x="411.5" y="299" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:11px;width:737px;color:#666;line-height:14px;fill:#666;" text-anchor="middle"/>
</g><g class="highcharts-axis-labels" >
    <text x="33" y="290" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:8.6px;width:359px;color:#666;line-height:14px;fill:#666;" text-anchor="end">
        <tspan x="33">0.00%</tspan>
    </text>
    <text x="33" y="220" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:8.6px;width:359px;color:#666;line-height:14px;fill:#666;" text-anchor="end">
        <tspan x="33">20.00%</tspan>
    </text>
    <text x="33" y="150" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:8.6px;width:359px;color:#666;line-height:14px;fill:#666;" text-anchor="end">
        <tspan x="33">40.00%</tspan>
    </text>
    <text x="33" y="80" style="font-family:'lucida grande', 'lucida sans unicode', verdana, arial, helvetica, sans-serif;font-size:8.6px;width:359px;color:#666;line-height:14px;fill:#666;" text-anchor="end">
        <tspan x="33">60.00%</tspan>
    </text>
</g><g class="highcharts-tracker" >
    <g visibility="visible"  transform="translate(33,75)" clip-path="url(#highcharts-60)">
        <rect fill="rgb(192,192,192)" x="151" y="41" width="228" height="169" isTracker="1404735525027" fill-opacity="0.0001" visibility="visible" style=""/>
    </g><g visibility="visible"  transform="translate(33,75)" clip-path="url(#highcharts-60)">
        <rect fill="rgb(192,192,192)" x="378" y="31" width="228" height="179" isTracker="1404735525028" fill-opacity="0.0001" visibility="visible" style=""/>
    </g><g visibility="visible"  transform="translate(33,75)" clip-path="url(#highcharts-60)">
        <path fill="none" d="M 368.50000000000006 71.1 L 388.50000000000006 71.1" isTracker="true" stroke-linejoin="round" visibility="visible" stroke-opacity="0.0001" stroke="rgb(192,192,192)" stroke-width="22" style=""/>
    </g>
</g>

谢谢,

布兰特

【问题讨论】:

  • 如果操作系统之间存在差异,请检查您在每个操作系统上使用的 XSLT 处理器。是一样的吗?您确定通过了相同的 FO 吗?如果 java 匹配,Xslt 匹配,FOP 版本匹配,应该没有区别。
  • svg 有视图框吗?也许您也应该发布一个示例 svg。我在一些图表 svg 中看到了这一点,因为视图框设置不正确,并且 svg 在 y 轴上有右对齐标签
  • @KevinBrown 我已附上上图的 svg。我在 svg 文档中没有看到任何 viewBox 元素。我们使用带有 FOP 的默认 XSLT 处理器:Xalan。

标签: xslt svg xsl-fo apache-fop


【解决方案1】:

我相信我知道这个问题,它可能解释了操作系统的明显差异。 Highcharts 可能根据来自实际使用的字体的字体大小计算所有位置。 x 轴标签位于 33 锚定右侧。您正在格式化在两个不同的 FOP 实例中,一个使用相同的字体 Highcharts 或一个相似的字体。一种字体较大,但仍与文本上的字体选择相匹配(请参阅 SVG 中的字体列表)。较大的会导致文本跨度稍长,大于 33。

我根据字体列表的猜测是 Windows 使用 Verdana 而 Linux 使用 Helvetica。检查此项并确保您在所有平台上使用相同的字体,或者在 svg 中设置一个视图框,该视图框略大,带有 neg x。

在测试我的猜测时,这是您的 SVG 在同一输出中的两次。我只更改了 SVG 中的字体选择以强制使用不同的字体。你可以看到区别。您的“裁剪”环境中的字体可能比用于确定 SVG 中间距的字体大。

为了在下面的 cmets 中证明这一点,使用精确的 SVG 我只是添加了更多字符(模拟更大的字体宽度)。你看,我输入了“CUTOFFF”这个词,它被切断了。它不会在 Highchart 计算“之后”发生变化,并且您在 FO 中进行的任何缩放都是没有意义的。文本位于 SVG 之外。

【讨论】:

  • 您对字体的猜测可能是正确的。如果我在 Linux 服务器上将字体更改为 Verdana,则标签实际上适合。最让我困惑的是,在设置了包含 svg 的块的大小之后,“缩放以适应”是否应该确保 instream-foreign-object 内的 svg 适合单元格内?
  • 不。这是因为 SVG 是在您使用该字体渲染时计算的。使用错误的(更大的)字体不会改变 SVG 说“将此文本放在 X = 33,右锚定”的事实。那些字体错误的标签可能是 34 或 35 宽,因此在 SVG 之外 (x=-1)。由于您没有视口,因此假定从 0,0 到宽度、高度。因此,该文本的边缘被剪裁。这就是为什么当我这样做时,我总是在 SVG 中插入一个 viewBox,给它一点空间(比如 -5、-5、width+5、height+5)。
  • 我会注意到,如果上面的图片符合您的想法,它会有所不同。左侧将对齐,文本左对齐相同。第二张图片使用比第一张更小的字体(相同的字体大小,但字形更小)。 “%”符号的右侧在每个中的完全相同的位置。只有文本会根据字形大小向左变长,并且最初用于计算 SVG 的文本比用于在 FOP 中呈现的文本要小。因此,它被切断了。
  • 感谢您的精彩解释和示例。这些图表显示在表格单元格中的事实是否会增加任何混淆效果?我的猜测是不应该。
  • 无。它超出了渲染 SVG 的范围。您可以“猜测”您需要多少空间并执行我之前所说的操作(viewBox)。例如,将您的 SVG 截断并将其添加到 svg 标签中:viewBox="-5, -5, 805, 405" ... 因为您的 SVG 是 800 宽 x 400 高。这基本上具有使视口周围变大 5px 的效果。因此,现在适合稍微超长(小于 5 像素)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2020-07-14
  • 2010-10-11
相关资源
最近更新 更多