ImageMagick - 从SVG文件渲染PNG,内容不在“页面”

时间:2012-10-22 02:09:38

标签: php imagemagick imagemagick-convert

我已经编写了一个脚本,用于将SVG转换为PNG,该脚本工作得非常好,直到SVG中的内容出现在页面外的#34;。

例如:

SVG with content that is 'off page'

黑线将被正确转换,但绿框完全被忽略。某些SVG文件的内容完全在页面外,并呈现一个空的PNG文件。

我目前的命令:

convert -background none "$file" -trim -geometry $size "$target"

我有2k + SVG文件我正在使用此问题转换至少约500或更多,因此手动将图像移动到页面上并不是一个选项。

修改 这是example file的链接。实际绘图与左侧页面底部一致。

2 个答案:

答案 0 :(得分:0)

当然在PNG中将忽略'off off'的内容。与SVG不同,PNG文件格式不知道“离页”概念。

这类似于在一张纸上打印:打印机也无法显示“关闭页面”内容。

您可以通过两种方式进行探索。两者的结果是您将实际页面大小更改为更大的页面大小:

  1. 可能能够通过将SVG渲染到更大的PNG画布来获取PNG中的“off page”内容,之后 自动修剪多余的边缘。 (由于缺少样本文件,我不能自己尝试。)

  2. 您可以尝试在2个或3个步骤中获得所需的结果:

    • 通过增加画布来修改SVG,使其包含“页面上的所有对象”;
    • 将修改后的SVG转换为PNG;
    • (可选:修剪PNG的边缘)。

答案 1 :(得分:0)

所以我终于有了这个工作。似乎无法直接使用ImageMagick进行操作,因此最终操纵了实际的SVG数据。

首先要找到对象的边界。使用PHP和simpleXml我将SVG数据转换为数组以便于操作/遍历。

似乎所有坐标都是x y的形式,所以这会将坐标分解为数字,并在x / y记录之间切换,如果它高于/低于之前的值。

/** $line is a <g> object */
protected function _position($line, &$position) {
        if(empty($line['@d'])) {
            if(is_array($line)) {
                foreach($line as $l) {
                    self::_position($l, $position);
                }
                return;
            }
        }

        if(empty($position)) {
            $position = array(
                'min' => array(
                    'x' => null,
                    'y' => null
                ),
                'max' => array(
                    'x' => null,
                    'y' => null
                )
            );
        }

        foreach(array_filter(preg_split('/([a-z])/i', $line['@d'])) as $cord) {
            $coordinate = 'x';
            foreach(explode(' ', $cord) as $value) {
                if(empty($value)) {
                    continue;
                }

                if($position['min'][$coordinate] == null || $position['min'][$coordinate] > $value - 1) {
                    $position['min'][$coordinate] = $value;
                }

                if($position['max'][$coordinate] == null || $position['max'][$coordinate] < $value + 1) {
                    $position['max'][$coordinate] = $value;
                }

                $coordinate = ($coordinate != 'x') ? 'x' : 'y';
            }
        }
    }

一旦你得到了最小/最大界限,我找到了一个带有transform的属性translate,它通过指定的x,y移动一个对象。所以只需0 - $min,它就会移到0,因为它可能是0 - -100 - 10

我的所有文件都没有属性,所以我只是用<g>

简单地替换了<g transform="translate($widthOffset, $heightOffset)">

同时设置视图框大小:

$xml['svg']['@viewbox'] = sprintf('%s %s %s %s',
    $position['min']['x'],
    $position['min']['y'],
    ($position['max']['x'] - $position['min']['x']),
    ($position['max']['y'] - $position['min']['y'])
);

最后要做的就是将数组转换回XML并将新数据保存回文件中。