Вычисление ограничительной рамки SVG с использованием PHP относительно кривых
Я недавно нашел этот удивительный класс, расположенный здесь, и попытался использовать его.
Однако он работает только с некоторыми основными функциями, такими как перемещение, горизонтальная линия и вертикальная линия.
-
Я попытался расширить этот существующий класс, добавив дополнительные проверки (и изменив регулярное выражение).
public static function fromPath($pathString) {
preg_match_all('/([mlvhzc][^mlvhzc]*)/i', $pathString, $commands);
$pt = array(0, 0);
$bounds = new self();
foreach ($commands[0] as $command) {
preg_match_all('/((\+|-)?\d+(\.\d+)?(e(\+|-)?\d+)?)/i', $command, $matches);
$i = 0;
while ($i < count($matches[1])) {
switch ($command[0]) {
case 'm' :
case 'l' :
$pt[0] += $matches[1][$i++];
$pt[1] += $matches[1][$i++];
break;
case 'M' :
case 'L' :
$pt[0] = $matches[1][$i++];
$pt[1] = $matches[1][$i++];
$last=$pt;
break;
case 'v' :
$pt[1] += $matches[1][$i++];
break;
case 'V' :
$pt[1] = $matches[1][$i++];
$last[1]=$pt[1];
break;
case 'h' :
$pt[0] += $matches[1][$i++];
break;
case 'H' :
$pt[0] = $matches[1][$i++];
$last[0]=$pt[0];
break;
case 'z' :
case 'Z' :
break;
case 'c':
$pt[0] = $last[0]+$matches[1][4];
$pt[1] = $last[1]+$matches[1][5];
$last=$pt;
$i=count($matches[1]);
break;
default :
throw new RuntimeException("Unhandled path command: " . $command[0]);
}
$bounds->extend($pt[0], $pt[1]);
}
}
return $bounds;
}
Я проверил руководство по SVG и обнаружил, что "c" имеет только 6 параметров, зная, что последние 2 - это то место, где заканчивается кривая, я попытался расширить точки на основе этого...
На данный момент мои тесты основаны на этом:
<svg xmlns="http://www.w3.org/2000/svg" width="109" height="109" viewBox="0 0 109 109">
<g style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;">
<path d="M32.25,41c1.25,0.62,3.12,0.67,5.5,0.5c7.12-0.5,19.12-2.5,24-3c0.99-0.1,2.62-0.25,3.75,0" />
</g>
При запуске в браузере Chrome сообщает, что его отношение ширины к высоте (поскольку я знаю, что svg точно не имеет размеров) составляет около 5-6, однако, когда я нахожу соотношение с помощью своего сценария, оно полностью отключается.
Я хотел бы знать, есть ли другой класс svg, который поддерживает все функции (C,c,Q,q и т. Д.).
Я знаю, что есть способ получить окно, преобразовав его в изображение, но я чувствую, что это неэффективно, также есть getBBox в javascript, но я хотел бы выполнить вычисления на сервере.
Спасибо за прочтение!
2 ответа
Вот пример использования imagick, на самом деле это два примера в одном, поскольку они не могут быть запущены одновременно, раскомментируйте один за раз:
$svg = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="109" height="109" viewBox="0 0 109 109">
<g style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;">
<path d="M32.25,41c1.25,0.62,3.12,0.67,5.5,0.5c7.12-0.5,19.12-2.5,24-3c0.99-0.1,2.62-0.25,3.75,0" />
</g>
</svg>';
$im = new Imagick();
$im->readImageBlob($svg);
$im->trimImage (0);//This trims the unecessary blank space.
//This block gets the dimensions (comment this block before uncommenting the second example bellow)
$dimension = $im->getImageGeometry();
print_r('<pre>');
print_r($dimension);
die();
/*//Uncomment this block to view thw jpeg version of the svg
$im->setImageFormat("jpeg");
header("Content-Type: image/jpeg");
$thumbnail = $im->getImageBlob();
echo $thumbnail;
$im->clear();
$im->destroy();
//*/
Ответ Германа мне очень помог, но на самом деле он не урезал SVG. Ниже первое решение, к которому я пришел, основываясь на его ответе:
function getTrimmedSvg( $filePath )
{
$image = new Imagick();
$image->readImage( $filePath );
$image->trimImage( 0 );
$imagePage = $image->getImagePage();
$dimensions = $image->getImageGeometry();
$minXOut = $imagePage['x'];
$minYOut = $imagePage['y'];
$widthOut = $dimensions["width"];
$heightOut = $dimensions["height"];
$xml = simplexml_load_file( $filePath );
$xml["viewBox"] = "$minXOut $minYOut $widthOut $heightOut";
return $xml->asXML();
}
Хотя это работает большую часть времени, оно не работает все время. После долгих безрезультатных попыток исправить крайние случаи я переключился на использование утилиты командной строки nodejs под названием svg-bounding-box ( GitHub). Это позаботилось обо всех моих крайних случаях. После глобальной установки svg-bounding-box на ваш сервер и / или в среду разработки вы можете использовать его в своем коде следующим образом:
function getTrimmedSvg( $filePath )
{
$xml = simplexml_load_file( $filePath );
$xml["viewBox"] = shell_exec( "cat $filePath | svg-bounding-box" );
return $xml->asXML();
}