【问题标题】:ImageMagick - render PNG from SVG file with content off the "page"ImageMagick - 从 SVG 文件渲染 PNG,内容脱离“页面”
【发布时间】:2012-10-22 02:09:37
【问题描述】:

我已经编写了一个将 SVG 转换为 PNG 的脚本,该脚本运行良好,直到 SVG 中的内容“脱离页面”。

例如:

黑线将被很好地转换,但绿框被完全忽略。一些 SVG 文件的内容完全脱离页面并呈现一个空的 PNG 文件。

我当前的命令:

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

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

编辑 这是example file 的链接。实际绘图与左侧页面底部对齐。

【问题讨论】:

  • 您能否提供(指向)包含“页外”内容部分的 SVG 示例?
  • 添加了示例文件的链接。

标签: php imagemagick imagemagick-convert


【解决方案1】:

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

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

有两个选项供您探索。两者的效果是您会将实际页面大小更改为更大的:

  1. 您也许可以通过将 SVG 渲染到更大的 PNG 画布来获取 PNG 中的“页外”内容,然后之后自动修剪多余的边缘。 (由于缺少示例文件,我无法自己尝试。)

  2. 您可以尝试通过 2 步或 3 步的过程来达到预期的效果:

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

【讨论】:

    【解决方案2】:

    所以我终于得到了这个工作。似乎无法直接使用 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 - -10 或0 - 10

    我所有的文件都没有属性,所以我只是简单地将&lt;g&gt; 替换为&lt;g transform="translate($widthOffset, $heightOffset)"&gt;

    同时设置viewbox大小:

    $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 并将新数据保存回文件中。

    【讨论】:

      猜你喜欢
      • 2022-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-06
      • 2013-12-03
      相关资源
      最近更新 更多