如何使用Imagick/ImageMagick调整SVG的大小

gor*_*dyr 12 php imagemagick imagick

我正在向服务器发送SVG文件的字符串表示,并使用Imagick以下列方式将其转换为jpeg:

$image = stripslashes($_POST['json']);
$filename = $_POST['filename'];
$unique = time();

$im = new Imagick();
$im->readImageBlob($image);
$im->setImageFormat("jpeg");
$im->writeImage('../photos/' . $type . '/humourised_' . $unique . $filename);
$im->clear();
$im->destroy();
Run Code Online (Sandbox Code Playgroud)

但是,我希望在光栅化之前调整SVG的大小,以使得生成的图像大于SVG文件中指定的尺寸.

我将我的代码修改为以下内容:

$image = stripslashes($_POST['json']);
$filename = $_POST['filename'];
$unique = time();

$im = new Imagick();
$im->readImageBlob($image);
$res = $im->getImageResolution();
$x_ratio = $res['x'] / $im->getImageWidth();
$y_ratio = $res['y'] / $im->getImageHeight();
$im->removeImage();
$im->setResolution($width_in_pixels * $x_ratio, $height_in_pixels * $y_ratio);

$im->readImageBlob($image);
$im->setImageFormat("jpeg");
$im->writeImage('../photos/' . $type . '/humourised_' . $unique . $filename);
$im->clear();
$im->destroy();
Run Code Online (Sandbox Code Playgroud)

此代码应解决分辨率并相应地调整SVG的大小.如果SVG画布及其元素具有基于"百分比"的宽度,则它可以完美地工作,但是它似乎不适用于"px"中定义的元素.不幸的是,这是一项要求.

将发送到服务器的典型SVG字符串如下所示:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/SVG/DTD/svg10.dtd">
<svg id="tempsvg" style="overflow: hidden; position: relative;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="333" version="1.1" height="444">
   <image transform="matrix(1,0,0,1,0,0)" preserveAspectRatio="none" x="0" y="0" width="333" height="444" xlink:href="http://www.songbanc.com/assets/embed/photos/full/133578615720079914224f9e7aad9ac871.jpg"></image>
   <image transform="matrix(1,0,0,1,0,0)" preserveAspectRatio="none" x="85.5" y="114" width="50" height="38" xlink:href="http://www.songbanc.com/assets/embed/humourise/elements/thumb/thumb_lips4.png"></image>
   <path transform="matrix(1,0,0,1,0,0)" fill="none" stroke="#000" d="M110.5,133L140.5,133" stroke-dasharray="- " opacity="0.5"></path>
   <circle transform="matrix(1,0,0,1,0,0)" cx="140.5" cy="133" r="5" fill="#000" stroke="#000"></circle>
   <path transform="matrix(1,0,0,1,0,0)" fill="none" stroke="#000" d="M110.5,133L110.5,155.8" stroke-dasharray="- " opacity="0.5"></path>
   <circle transform="matrix(1,0,0,1,0,0)" cx="110.5" cy="155.8" r="5" fill="#000" stroke="#000"></circle>
   <circle transform="matrix(1,0,0,1,0,0)" cx="110.5" cy="133" r="5" fill="#000" stroke="#000"></circle>
</svg>
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,构成此SVG的元素具有像素定义宽度和高度(遗憾的是,使用百分比不是此应用程序的选项)

有没有办法解决?或者将SVG转换为png并以给定大小呈现它而不会降低质量的任何其他方法.

谢谢.

编辑:虽然我从未真正设法找到一个完美的解决方案.相反,我结束了以json的形式发送SVG数据,在服务器端循环并将像素缩放到预期的高度.

然后,经过多次试验和错误后,我意识到imagemagick与标准SVG转换/旋转命令有问题,将任何被操纵的元素抛出.我最终切换'inkscape'来将生成的SVG渲染为栅格化图像.一切都很好.我仍在深入挖掘潜在的公式化解决方案,以抵消imagemagick所带来的差异.如果我有任何成功,我会再次更新这个问题.

psy*_*brm 13

作为php_imagick错误的解决方法,您可以扩展svg的width =".."和height ="..":

function svgScaleHack($svg, $minWidth, $minHeight)
{
    $reW = '/(.*<svg[^>]* width=")([\d.]+px)(.*)/si';
    $reH = '/(.*<svg[^>]* height=")([\d.]+px)(.*)/si';
    preg_match($reW, $svg, $mw);
    preg_match($reH, $svg, $mh);
    $width = floatval($mw[2]);
    $height = floatval($mh[2]);
    if (!$width || !$height) return false;

    // scale to make width and height big enough
    $scale = 1;
    if ($width < $minWidth)
        $scale = $minWidth/$width;
    if ($height < $minHeight)
        $scale = max($scale, ($minHeight/$height));

    $width *= $scale*2;
    $height *= $scale*2;

    $svg = preg_replace($reW, "\${1}{$width}px\${3}", $svg);
    $svg = preg_replace($reH, "\${1}{$height}px\${3}", $svg);

    return $svg;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以轻松创建漂亮透明的PNG!

createThumbnail('a.svg', 'a.png');

function createThumbnail($filename, $thname, $size=50)
{
    $im = new Imagick();
    $svgdata = file_get_contents($filename);
    $svgdata = svgScaleHack($svgdata, $size, $size);

    $im->setBackgroundColor(new ImagickPixel('transparent'));
    $im->readImageBlob($svgdata);

    $im->setImageFormat("png32");
    $im->resizeImage($size, $size, imagick::FILTER_LANCZOS, 1);

    file_put_contents($thname, $im->getImageBlob());
    $im->clear();
    $im->destroy();
}
Run Code Online (Sandbox Code Playgroud)

注意:我一直在寻找一种解决方案,如何从最初的小尺寸重新调整SVG.然而,似乎imagick :: setResolution已被打破.但是,ImageMagick库本身正在工作,因此您可以使用exec('convert ...')(出于安全原因可能会被托管提供商禁用).

因此,要从较小的svg创建缩略图50x50,您可以:

convert -density 500 -resize 50 50 -background transparent a.svg PNG32:a.png
Run Code Online (Sandbox Code Playgroud)