Я прочитал ряд Вопросов и веб-статей, но, кажется, столкнулся с кирпичной стеной. Я сократил свою проблему до очень простого файла 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
быть file://
URL с абсолютным путем, т.е. xlink:href="file:///home/myuser/public_html/test/svg-problem/image.jpg"
xlink:href
быть file://
URL с указанием относительно пути к текущему каталогу, т.е. xlink:href="file://./image.jpg"
xlink:href
быть file://
URL без пути, т.е. xlink:href="file://image.jpg"
$im->setFormat('RSVG')
.. это исключение с Unable to set format
, Я не понимаю почему.Поскольку преобразование через PHP завершается без вызова setFormat
и приведенный выше список форматов говорит, что он будет использовать RSVG по умолчанию, я думаю, что он использует RSVG, хотя моя попытка форсировать формат RSVG не удалась.
Я прочитал, что вы можете перекомпилировать библиотеку rsvg, чтобы показать больше ошибок при загрузке файла, но на моем производственном сервере, управляемом cPanel, я очень не хочу пытаться перекомпилировать что-либо.
Есть идеи, что попробовать дальше? Вытаскивая мои волосы здесь 🙂
Проблема в том, что я не знаю, как ImageMagick подробно использует интерфейс librsvg. Но несколько вещей выделяются в последнем librsvg doc. Хотя параграфы были добавлены только в версии v2.42, я думаю, что они применимы и к более старым версиям, в соответствии с тем, что я наблюдал в системах Gnome.
При обработке SVG librsvg будет загружать ссылочные файлы только в том случае, если они находятся в том же каталоге, что и базовый файл, или в его подкаталоге … Это делается для того, чтобы вредоносные файлы SVG не могли включать файлы, которые находятся в каталоге выше.
Если у вас уже есть данные SVG в памяти, вы можете создать входной поток памяти … Обратите внимание, что в этом случае важно указать base_file для данных SVG в памяти. Librsvg использует base_file для разрешения ссылок на внешний контент, например растровые изображения.
В зависимости от реализации ImageMagick это приводит к двум возможным решениям:
Загрузите SVG напрямую из файла с
$im->readImage('src.svg');
Используйте строку, но установите второй аргумент файла в
$im->readImageBlob('<?xml version="1.0"?>' . $svg, 'src.svg')
Только в стороне, $im->setFormat('RSVG')
не имеет никакого смысла, так как «RSVG» — это только название библиотеки, а не формат файла.
Других решений пока нет …