本文介绍了如何使用Imagick / ImageMagick调整SVG的大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am sending a string representation of an SVG file to the server and using Imagick to turn this into a jpeg in the following manner:

$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();

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

However I wish to resize the SVG prior to rasterizing it so the the resulting image is larger than the dimensions specified within the SVG file.

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

I modified my code to the following:

$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();

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

This code should work out the resolution and resize the SVG accordingly. It works perfectly if the SVG canvas and it's elements have 'percentage' based widths, however it doesn't appear to work with elements defined in 'px'. Which is unfortunately a requirement.

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

A typical SVG string that will be sent to the server looks like this:

<?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>

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

As you can see the elements that make up this SVG has pixel definition widths and heights (using percentages is unfortunately not an option for this application)

有什么方法可以解决这个问题吗?或者将SVG转换为png并以给定大小渲染而不会降低质量的任何其他方法。

Is there any way around this? Or any other method of converting an SVG to png and rendering it at a given size without loss of quality.

谢谢。

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

Although I never actually managed to find a perfect solution. Instead I ended sending the SVG data as json, looping through it server side and scaling the pixels to the intended height.

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

Then, after much trial and error I realised that imagemagick had issues wih the standard SVG transform/rotate commands, throwing any manipulated elements out of whack. I ended up switching too 'inkscape' to render the resulting SVG as a rasterised image. And all is well. I'm still digging into a potential formulatic solution to offset the differences that imagemagick makes. If I have any success I will update this question again.

推荐答案

作为,你可以缩放svg的width =..和height =..:

As a workaround of php_imagick's bug, you can scale svg's width=".." and 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;
}

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

Then you can easily create nice transparent 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();
}

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

Note:I've been searching for a solution how to rescale SVG from its initial small size. However it seems that imagick::setResolution is broken. However, ImageMagick library itself is working, so you can use exec('convert...') (might be disabled for security reasons by hosting provider).

所以要从较小的svg创建缩略图50x50:

So to create thumbnail 50x50 from smaller svg you would do:

convert -density 500 -resize 50 50 -background transparent a.svg PNG32:a.png

这篇关于如何使用Imagick / ImageMagick调整SVG的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 15:08