12

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

ただし、ラスタライズする前に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();

このコードは解像度を計算し、それに応じて 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>

ご覧のとおり、この SVG を構成する要素にはピクセル定義の幅と高さがあります (残念ながら、このアプリケーションではパーセンテージを使用することはできません)。

これを回避する方法はありますか?または、SVG を png に変換し、品質を損なうことなく特定のサイズでレンダリングするその他の方法。

ありがとう。

編集:私は実際に完璧な解決策を見つけることができませんでしたが。代わりに、SVG データを json として送信することを終了し、サーバー側をループして、ピクセルを意図した高さにスケーリングしました。

その後、多くの試行錯誤の末、imagemagick には標準の SVG 変換/回転コマンドに問題があり、操作された要素を台無しにしていることに気付きました。結果のSVGをラスタライズされた画像としてレンダリングするには、あまりにも「inkscape」に切り替えてしまいました。そして、すべて順調です。imagemagick がもたらす違いを相殺するために、私はまだ潜在的な定式的な解決策を掘り下げています。成功した場合は、この質問を再度更新します。

4

5 に答える 5

15

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;
}

素敵な透過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...') を使用できます (ホスティング プロバイダーによってセキュリティ上の理由から無効にされている可能性があります)。

したがって、小さい svg からサムネイル 50x50 を作成するには、次のようにします。

convert -density 500 -resize 50 50 -background transparent a.svg PNG32:a.png
于 2012-11-21T00:21:35.657 に答える
3

私は解決策を探していましたが、この投稿を読んだ直後にこれを見つけ、魅力のように機能しました:

$im = new Imagick();
$im->readImage("/path/to/image.svg");
$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->readImage("/path/to/image.svg");
// Now you can do anything with the image, such as convert to a raster image and output it to the browser:
$im->setImageFormat("png");
header("Content-Type: image/png");
echo $im;

クレジットは、php マニュアル ページのそのコメントの作成者に送られます。

于 2012-11-29T12:23:18.720 に答える
0

これは、既に文字列に含まれている (たとえば、データベースから) 画像を取得し、サイズを変更し、境界線を追加して、印刷する方法の例です。再販業者のロゴを表示するためにこれを使用します

  // Decode image from base64
  $image=base64_decode($imagedata);

  // Create Imagick object
  $im = new Imagick();

  // Convert image into Imagick
  $im->readimageblob($image);

  // Create thumbnail max of 200x82
  $im->thumbnailImage(200,82,true);

  // Add a subtle border
  $color=new ImagickPixel();
  $color->setColor("rgb(220,220,220)");
  $im->borderImage($color,1,1);

  // Output the image
  $output = $im->getimageblob();
  $outputtype = $im->getFormat();

  header("Content-type: $outputtype");
  echo $output;
于 2012-04-30T12:20:39.503 に答える