ImageMagick 的 SVG 输出出现格式错误
SVG output of ImageMagick appears malformed
我有一个 php 脚本可以生成图标,并使用 ImageMagick return 将它们转换为各种格式。 JPG、PNG 甚至 ICO 等位图格式工作起来很有魅力,但 SVG 输出会做一些奇怪的事情。这是说明案例的最小脚本:
<?php
$format = 'jpg';
$im = new Imagick;
$im->newImage(300, 300, new ImagickPixel('#ffffff'));
$im->setImageFormat($format);
$draw = new ImagickDraw();
$draw->setStrokeWidth(0);
$draw->setFillColor(new ImagickPixel('#ff0000'));
$draw->setFillOpacity(.5);
$draw->rectangle(50, 50, 249, 249);
$im->drawImage($draw);
header('Content-Type: ' . $im->getImageMimeType());
echo $im->getImageBlob();
示例输出:
如果我将 $format
的值更改为 png
或 ico
,图像仍然可以正常工作,并以正确的 MIME 类型 header 发送。当我将格式切换为 svg
时,发送了正确的 MIME 类型 header,并且它确实是 return some 之类的 SVG,但它出现畸形。这是上面示例脚本的输出:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="300" height="300">
stroke-width:0;fill:#FFFF00000000;fill-opacity:0.5; <rect x="50" y="50" width="199" height="199"/>
</svg>
值得注意的是,svg
元素上的 xmlns
属性丢失了。也许更奇怪的是,矩形属性实际上并未应用于矩形,而是作为某种内联 CSS 转储(没有适当的上下文来执行此操作)。
可行的输出(也是我所期望的)将是:
<?xml version="1.0" standalone="no"?>
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="199" height="199" stroke-width="0" fill="#FF0000" fill-opacity="0.5"/>
</svg>
此外,尺寸正确的 viewBox
属性 会很好,但那不是 deal-breaker。
我错过了什么吗?也许在渲染为矢量格式之前需要应用一些操作?也许这是一个错误?我找不到任何关于它的信息,任何正确方向的指示将不胜感激。
更新2019-11-25
剧情转折。我以前没有注意到这一点,但是当我在示例中省略 drawImage
步骤时,我得到了完全不同的输出:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve"> <image id="image0" width="300" height="300" x="0" y="0"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABRBrPYAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAd2KE6QAAAA+SURB
VGje7coxAQAACAOg9U9rA1dBf7jJXkw0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdO0
fytHkUx5BCDW7AAAAABJRU5ErkJggg==" />
</svg>
它现在创建了一个 PNG 背景图像,它出于某种原因内联解析,但它也引入了以前缺失的方面;特别是 xmlns
和 viewBox
.
整个标记看起来与 Inkscape 生成的内容相同。这可能是有道理的,正如我在某处读到的那样,这是 ImageMagick 可用于渲染 SVG 的库之一。
这几乎就像 drawImage
方法破坏了 Inkscape 解析器,它退回到了一些劣质引擎或其他东西。我希望这会缩小解决方案的路径。
根据这个 ImageMagic 板,导出到 SVG 是相当有问题的,因为该库适用于光栅图像,而不是矢量图形。据我了解,SVG 输出将始终是带有 base64 编码二进制数据的图像标签。满足您要求的解决方法可能如下所示:
$im = new Imagick;
$im->newImage(300, 300, new ImagickPixel('#ffffff'));
$im->setImageFormat('svg');
$im1 = new Imagick();
$im1->newImage(300, 300, new ImagickPixel('#ffffff'));
$im1->setImageFormat('png');
$fillColor = new ImagickPixel('#ff0000');
$draw = new ImagickDraw();
$draw->setFillColor($fillColor);
$draw->setStrokeWidth(0);
$draw->setFillOpacity(.5);
$draw->rectangle(50, 50, 249, 249);
$im1->drawImage($draw);
$im->compositeImage($im1->getimage(), Imagick::COMPOSITE_COPY, 0, 0);
header('Content-Type: image/svg+xml');
echo $im->getImageBlob();
我有一个 php 脚本可以生成图标,并使用 ImageMagick return 将它们转换为各种格式。 JPG、PNG 甚至 ICO 等位图格式工作起来很有魅力,但 SVG 输出会做一些奇怪的事情。这是说明案例的最小脚本:
<?php
$format = 'jpg';
$im = new Imagick;
$im->newImage(300, 300, new ImagickPixel('#ffffff'));
$im->setImageFormat($format);
$draw = new ImagickDraw();
$draw->setStrokeWidth(0);
$draw->setFillColor(new ImagickPixel('#ff0000'));
$draw->setFillOpacity(.5);
$draw->rectangle(50, 50, 249, 249);
$im->drawImage($draw);
header('Content-Type: ' . $im->getImageMimeType());
echo $im->getImageBlob();
示例输出:
如果我将 $format
的值更改为 png
或 ico
,图像仍然可以正常工作,并以正确的 MIME 类型 header 发送。当我将格式切换为 svg
时,发送了正确的 MIME 类型 header,并且它确实是 return some 之类的 SVG,但它出现畸形。这是上面示例脚本的输出:
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg width="300" height="300">
stroke-width:0;fill:#FFFF00000000;fill-opacity:0.5; <rect x="50" y="50" width="199" height="199"/>
</svg>
值得注意的是,svg
元素上的 xmlns
属性丢失了。也许更奇怪的是,矩形属性实际上并未应用于矩形,而是作为某种内联 CSS 转储(没有适当的上下文来执行此操作)。
可行的输出(也是我所期望的)将是:
<?xml version="1.0" standalone="no"?>
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg">
<rect x="50" y="50" width="199" height="199" stroke-width="0" fill="#FF0000" fill-opacity="0.5"/>
</svg>
此外,尺寸正确的 viewBox
属性 会很好,但那不是 deal-breaker。
我错过了什么吗?也许在渲染为矢量格式之前需要应用一些操作?也许这是一个错误?我找不到任何关于它的信息,任何正确方向的指示将不胜感激。
更新2019-11-25
剧情转折。我以前没有注意到这一点,但是当我在示例中省略 drawImage
步骤时,我得到了完全不同的输出:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="300px" height="300px" viewBox="0 0 300 300" enable-background="new 0 0 300 300" xml:space="preserve"> <image id="image0" width="300" height="300" x="0" y="0"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsAQAAAABRBrPYAAAABGdBTUEAALGPC/xhBQAAACBjSFJN
AAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QAAd2KE6QAAAA+SURB
VGje7coxAQAACAOg9U9rA1dBf7jJXkw0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdM0TdO0
fytHkUx5BCDW7AAAAABJRU5ErkJggg==" />
</svg>
它现在创建了一个 PNG 背景图像,它出于某种原因内联解析,但它也引入了以前缺失的方面;特别是 xmlns
和 viewBox
.
整个标记看起来与 Inkscape 生成的内容相同。这可能是有道理的,正如我在某处读到的那样,这是 ImageMagick 可用于渲染 SVG 的库之一。
这几乎就像 drawImage
方法破坏了 Inkscape 解析器,它退回到了一些劣质引擎或其他东西。我希望这会缩小解决方案的路径。
根据这个 ImageMagic 板,导出到 SVG 是相当有问题的,因为该库适用于光栅图像,而不是矢量图形。据我了解,SVG 输出将始终是带有 base64 编码二进制数据的图像标签。满足您要求的解决方法可能如下所示:
$im = new Imagick;
$im->newImage(300, 300, new ImagickPixel('#ffffff'));
$im->setImageFormat('svg');
$im1 = new Imagick();
$im1->newImage(300, 300, new ImagickPixel('#ffffff'));
$im1->setImageFormat('png');
$fillColor = new ImagickPixel('#ff0000');
$draw = new ImagickDraw();
$draw->setFillColor($fillColor);
$draw->setStrokeWidth(0);
$draw->setFillOpacity(.5);
$draw->rectangle(50, 50, 249, 249);
$im1->drawImage($draw);
$im->compositeImage($im1->getimage(), Imagick::COMPOSITE_COPY, 0, 0);
header('Content-Type: image/svg+xml');
echo $im->getImageBlob();