tcpdf中的SVG渲染器是否不支持00FF以上的UTF-8字符?

时间:2019-05-07 14:32:20

标签: php svg tcpdf

我正尝试从前端的javascript的highcharts SVG输出中,将包含希腊语和拉丁语字符的公式打印到php后端的TCPDF中。

这是SVG文件的相关部分:

β(ϴᶜ)m-¹ sr-¹

当渲染到pdf时,其打印如下:

?(??)m-1 sr-1

我也将这些字符渲染为pdf页面上的文本,并且效果很好。

这是初始化代码:

parent::__construct('P', 'mm','Letter', true, 'UTF-8', false, true); 

我正在使用自定义的TTF字体:

$this->documentFont = \TCPDF_FONTS::addTTFfont($ttfFont, 'TrueTypeUnicode', 
'', 96);

调用打印单元格的代码,可以正确地将扩展的UTF-8字符集呈现在00FF以上:

$this->WriteHTMLCell($x, $y, $this->text);

这是渲染highcharts SVG的调用,它不能正确渲染00FF以上的字符:

$this->ImageSVG('@'.$image, $x, $y, $width, $height);

要变通,我发现了与UTF-8的00FF子集中所需的字符类似的字符:

ß(Øc)m-¹ sr-¹

这不是完美的,但是作为一种变通方法,它可以起作用,直到我弄清楚为什么SVG渲染不能正确打印00FF以上的Unicode字符。

我尝试在00FF以上的unicode范围内向Highchart轴添加字符。这就是我发现这似乎是SV​​G渲染器将打印内容的上限的方式。

我还尝试确保在PDF渲染器的前端和后端使用相同的字体。 PDF渲染器中使用的自定义TTF字体与我指定用于前端,CSS和HighCharts配置的字体相同。

正如下面的代码所示,我还尝试使用unescape()从HighCharts包围SVG渲染器。

HighCharts渲染:

/**
 * inserts a highchart line chart into the HTML document at specified point
 * @param {HTMLElement} chartContainer where this chart is rendered to
 * @param {object} chartConfig config object with chart options.
 * @param {array} seriesData two dimensional array to plot
 * @param {string} seriesName name of series being plotted
 * @return {Highcharts} highcharts object to be inserted - allows later referencing
 */
function addChart(chartContainer, chartConfig, seriesData, seriesName) 
{
    return new Highcharts.Chart({
        chart: {
            animation: false,
            type: 'line',
            renderTo: chartContainer,
            zoomType: 'y'
        },
        title: {
            text: chartConfig.title
        },
        xAxis: {
            title: {
                text: 'DUT DATA - ' + chartConfig.uom
            },
            gridLineDashStyle: 'solid',
            gridLineWidth: 2,
            minorTicks: true,
            minorGridLineDashStyle: 'longdash',
            startOnTick: true,
            endOnTick: true,
            max: chartConfig.xMax,
            min: chartConfig.xMin
        },
        yAxis: {
            title: {
                text: 'Residuals'
            },
            gridLineDashStyle: 'solid',
            gridLineWidth: 2,
            minorTicks: true,
            minorGridLineDashStyle: 'longdash',
            tickWidth: 2,
            lineWidth: 1,
            max: chartConfig.yMax,
            min: chartConfig.yMin
        },
        plotOptions: {
            line: {
                animation: false
            }
        },
        series: [{
            name: seriesName,
            point: {
                events: {
                    click: function () {
                        console.log('Category: ' + this.category + ', value: ' + this.y);
                    }
                }
            },
            animation: false,
            showInLegend: true,
            data: seriesData
        }],
        exporting: {
            enabled: true
        },
        credits: {
            enabled: false
        }
    });
}

SVG创建:

chart[i].svgData = unescape(chart[i].getSVG());

我希望TCPDF SVG渲染器能够打印整个UTF-8范围。看来SVG渲染器无法渲染00FF以上的字符。

1 个答案:

答案 0 :(得分:1)

SVG解析器启动时要做的第一件事就是初始化SVG样式。这样,它将font-family设置为Helvetica。因此,您需要确保在SVG中明确使用自定义字体。

我用Highcharts网站上的折线图进行了测试,并明确在每个font-familytext元素上设置了tspan属性似乎可以解决问题。诚然,这是一个比较直截了当的解决方案,但是您可以使用它来使其更具针对性。我在下面提供了屏幕截图。 (Highcharts有时在style属性中包含一个不同的字体系列,但是font-family属性为我们提供了一种无需解析和更新style属性字符串即可覆盖它的简便方法。)

<?php
$svgdom = new DOMDocument();
//My extract from Highcharts did not include the XML declaration, so I add it.
//TCPDF might assume it's UTF-8, so this may not be needed.
//[Edit: Checked, TCPDF does, but we're working on it before that stage I figure 
//it's best to include the xml declaration if it's not already there.]
$svgdom->loadXML('<?xml version="1.0" encoding="utf-8" ?>'.$image);
$xpath = new DOMXPath($svgdom);
$textitems = $xpath->query('//*[local-name() = "text" or local-name() = "tspan"]');
foreach($textitems as $element) {
  $element->setAttribute('font-family', $font);
}
$image = $svgdom->saveXML();

(我在下面的示例中使用了Dejavusans,只是将标题替换为测试文本。)

Demonstration screenshot