Imagick, конвертирующий SVG через rsvg, выводит изображение пустым из PHP, но нормально из командной строки - PullRequest
0 голосов
/ 21 мая 2018

Я прочитал ряд Вопросов и веб-статей, но, кажется, столкнулся с кирпичной стеной.Я сократил свою проблему до очень простого файла SVG, содержащего одно изображение.При преобразовании из PHP через imagick изображение отображается пустым, но из командной строки, используя тот же движок rsvg, оно прекрасно воспроизводится.

Этот проект сработал как чудо на моей локальной машине разработки Fedora, только при перемещениик производству на Centos я имел эту проблему.

Среда: сервер Centos 6.2, PHP 5.6.36 с использованием php-fpm, модуль Imagick версии 3.4.3 с использованием библиотеки ImageMagick версии 6.7.8-9 2016-06-16

Примечание : мой сервер apache вообще не ставит в тюрьму или не выполняет хромирование файловой системы, поэтому все нормальные ссылки на пути должны работать нормально, например, запись в файл журнала в корневом веб-каталоге с использованиемабсолютный путь без проблем.

$ identify -list format | grep -i svg
     MSVG  SVG       rw+   ImageMagick's own SVG internal renderer
      SVG  SVG       rw+   Scalable Vector Graphics (RSVG 2.39.0)
     SVGZ  SVG       rw+   Compressed Scalable Vector Graphics (RSVG 2.39.0)


$ identify -list delegate | grep -i svg
        cdr =>          "uniconvertor" "%i" "%o.svg"; mv "%o.svg" "%o"
        dot =>          "dot" -Tsvg "%i" -o "%o"
        svg =>          "rsvg-convert" -o "%o" "%i"

Поэтому я считаю, что формат 'SVG' указывает, что он будет использовать RSVG для преобразования из PHP.

Мой SVG (сохраненный из Inkscape):

<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="620mm" height="640mm" viewBox="0 0 620 640" version="1.1" id="svg28" inkscape:version="0.92.3 (2405546, 2018-03-11)" sodipodi:docname="radcover-620x640b.svg">
  <defs id="defs22"/>
  <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.24748737" inkscape:cx="1386.1321" inkscape:cy="1147.0763" inkscape:document-units="mm" inkscape:current-layer="layer1" showgrid="false" inkscape:window-width="1920" inkscape:window-height="1016" inkscape:window-x="2048" inkscape:window-y="27" inkscape:window-maximized="1" inkscape:snap-global="false"/>
  <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(0,343)">
  <image fill-opacity="0" stroke="none" stroke-opacity="0" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" x="54.336063385009766" y="-280.25213623046875" width="280.0984802246094" height="175.3288116455078" preserveAspectRatio="none" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="image.jpg" data-number="1" transform="matrix(0.98887052,-0.14877865,0.14877865,0.98887052,0.00000000,0.00000000)"/>
  </g>
</svg>

Мой код PHP:

<?php
$widthPx = 500;
$heightPx = 500;
$outFilename = 'out.png';

$svg = file_get_contents('src.svg');

$im = new Imagick();
$im->readImageBlob('<?xml version="1.0"?>' . $svg);
$im->setImageFormat('png24');

$im->resizeImage($widthPx, $heightPx, imagick::FILTER_LANCZOS, 1);

$im->writeImage($outFilename);

echo "Done.\n";

Та же попытка из командной строки:

convert rsvg:src.svg cli.jpg

То же самое с использованием rsvg-convert (как указано в выводе делегатов выше):

rsvg-convert src.svg -o rsvg-convert.jpg

Результат: Обе попытки командной строки, cli.jpg и rsvg-convert.jpg, показывают изображение очень хорошо.Попытка из PHP показывает пустой вывод, т.е. элемент <image> не рендерится.

Не выдается ни исключение, ни вывод ошибок, которые я могу найти.

Я пробовал:

  • Сделать xlink:href URL-адресом file:// с абсолютным путем, т.е. xlink:href="file:///home/myuser/public_html/test/svg-problem/image.jpg"
  • Сделать xlink:href URL-адресом file:// относительно пути к текущему каталогу, т.е.xlink:href="file://./image.jpg"
  • Сделать xlink:href URL-адресом file:// без пути, то есть xlink:href="file://image.jpg"
  • Принудительно использовать 'RSVG' с $im->setFormat('RSVG') .. он вызывает исключение с Unable to set format.Я не могу понять, почему.

Поскольку преобразование через PHP завершается без вызова setFormat, а приведенный выше список форматов говорит, что он будет использовать RSVG по умолчанию, я думаю, что он использует RSVG, хотя моя попытказаставить принудительно завершить формат RSVG.

Я прочитал, что вы можете перекомпилировать библиотеку rsvg, чтобы показать больше ошибок при загрузке файла, но на моем производственном сервере, управляемом cPanel, я очень не хочу пытаться что-либо перекомпилировать.

Есть идеи, что попробовать дальше?Потянув меня за волосы здесь:)

1 Ответ

0 голосов
/ 22 мая 2018

Проблема в том, что я не знаю, как ImageMagick подробно использует интерфейс librsvg.Но кое-что выделяется в последнем librsvg doc .Хотя абзацы были добавлены только в версии v2.42, я думаю, что они применимы и к более старым версиям, в соответствии с тем, что я наблюдал в системах Gnome.

При обработке SVG librsvg будет загружать толькоссылочные файлы, если они находятся в том же каталоге, что и базовый файл, или в его подкаталоге ... Это так, что вредоносные файлы SVG не могут включать файлы, которые находятся в каталоге выше.

Если у вас уже естьДанные SVG в памяти, вы можете создать поток ввода памяти ... Обратите внимание, что в этом случае важно указать base_file для данных SVG в памяти.Librsvg использует base_file для разрешения ссылок на внешний контент, например растровые изображения.

В зависимости от реализации ImageMagick, это приводит к двум возможным решениям:

  1. ЗагрузитьSVG непосредственно из файла с

    $im->readImage('src.svg');
    
  2. Использовать строку, но установить второй аргумент файла в

    $im->readImageBlob('<?xml version="1.0"?>' . $svg, 'src.svg')
    

Только каккроме того, $im->setFormat('RSVG') не имеет никакого смысла, так как «RSVG» - это только название библиотеки, а не формат файла.

...