[英]Imagick converting SVG via rsvg renders image blank from PHP, but ok from command line
我已經閱讀了一系列問題和網絡文章,但似乎遇到了障礙。 我已將我的問題簡化為一個非常簡單的 SVG 文件,其中包含一個圖像。 當通過 imagick 從 PHP 轉換時,圖像呈現為空白,但從使用相同的 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 服務器根本不會監獄或 chroot 文件系統,所以所有正常的路徑引用都應該可以正常工作,例如它使用絕對路徑名寫入 web 根目錄中的日志文件沒有問題。
$ 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')
強制使用$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 數據,則可以創建一個內存輸入流...注意,在這種情況下,為內存中的 SVG 數據指定 base_file 很重要。 Librsvg 使用 base_file 來解析指向外部內容的鏈接,例如光柵圖像。
根據 ImageMagick 的實現,這會導致兩種可能的解決方案:
直接從文件加載 SVG
$im->readImage('src.svg');
使用字符串,但在中設置第二個文件參數
$im->readImageBlob('<?xml version="1.0"?>' . $svg, 'src.svg')
$im->setFormat('RSVG')
, $im->setFormat('RSVG')
沒有任何意義,因為“RSVG”只是庫的名稱而不是文件格式。
我無法通過 IMagick PHP 庫使其工作,但使用proc_open
會導致與從命令行調用時完全相同的結果:
$imgPath = '/path/to/image.svg';
$svg = file_get_contents($imgPath);
// ... manipulate svg content here if needed
$descriptorSpec = array(
0 => array("pipe", "r"), // STDIN
1 => array("pipe", "w"), // STDOUT
2 => array("pipe", "w"), // STDERR
);
// fd:0 - STDIN, fd:1: STDOUT,
// svg: and png: tell ImageMagick input/output formats
$cmd = "convert svg:fd:0 png:fd:1";
$proc = proc_open($cmd, $descriptorSpec, $pipes, null, null);
if (!is_resource($proc)) {
throw new RuntimeException("Failed to proc_open: $cmd");
}
fwrite($pipes[0], $svg);
fclose($pipes[0]);
$png = stream_get_contents($pipes[1]);
fclose($pipes[1]);
if (!$png) {
throw new RuntimeException("Command returned no output: $cmd");
}
$stdErr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
if ($stdErr) {
throw new RuntimeException("Command $cmd returned error: $stdErr");
}
$exitStatus = proc_close($proc);
if ($exitStatus) {
throw new RuntimeException("Command returned $exitStatus: $cmd");
}
// Render PNG with appropriate headers, or save to file, or return etc
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.