Search code examples
phpsvgbounding

Calculating SVG bounding box using PHP with respect to curves


I recently found this amazing class located here, and tried using it.

However, it only works with some of the basic functions such as move, horizontal line, and vertical line.

--

I have tried extending this existing class by adding additional checks (and changing the regex).

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

I checked out the SVG manual and found out that 'c' only has 6 parameters, knowing that the last 2 is where the curve will end up at, I tried to extend the points based on that...

For the moment, my tests are based around this:

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

When run in the browser, Chrome reports that it's width to height ratio (because I know svg doesn't exactly have sizes), is around 5 to 6, however, when I find the ratio with my script, it's completely off.

I'd like to know if there's another svg class built that supports all the functions (C,c,Q,q,etc).

I know that there's a way to get the box by converting it into an image, but I feel that is inefficient, also there's getBBox in javascript, but I'd like to perform the calculations on the server.

Thanks for Reading!


Solution

  • Here is an example using imagick, it is actually two example in one since they cannot be run at the same time, uncomment one at the time:

    $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();
    //*/