Advertisement
Tamlyn

SVG bounding box

Nov 23rd, 2012
1,072
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 2.26 KB | None | 0 0
  1. <?php
  2.    
  3. /**
  4.  * Calculate smallest bounding rectangle for given SVG path string.
  5.  *
  6.  * Only handles paths composed of straight lines. Bezier and arc commands throw an exception.
  7.  * Returns an object with top left (x1, y1) bottom right (x2, x2) and size (width, height).
  8.  *
  9.  * Example usage:
  10.  *   $bounds = svgBounds('M 100 100L300 100 200 300z');
  11.  *   echo $bounds->width; //200
  12.  *
  13.  * @param string $pathString SVG path command
  14.  * @return stdClass
  15.  * @author Tamlyn Rhodes <http://tamlyn.org>
  16.  * @license http://creativecommons.org/publicdomain/mark/1.0/ Public Domain
  17.  */
  18. function svgBounds($pathString) {
  19.     //match each command sequence starting with a letter
  20.     preg_match_all('/([mlvhz][^mlvhz]*)/i', $pathString, $commands);
  21.  
  22.     //handle initial move command
  23.     $firstMove = array_shift($commands[0]);
  24.     preg_match_all('/(-?[0-9.]+)/', $firstMove, $matches);
  25.     $pt = $matches[1];
  26.     $bounds = (object) array('x1' => $pt[0], 'y1' => $pt[1], 'x2' => $pt[0], 'y2' => $pt[1]);
  27.  
  28.     //loop through successive command sequences
  29.     foreach ($commands[0] as $command) {
  30.  
  31.         //match numbers in string
  32.         preg_match_all('/(-?[0-9.]+)/', $command, $matches);
  33.  
  34.         //loop through numbers and move point according to command
  35.         $i=0;
  36.         while ($i < count($matches[1])) {
  37.  
  38.             //update current position
  39.             switch ($command[0]) {
  40.                 case 'm' :
  41.                 case 'l' :
  42.                     $pt[0] += $matches[1][$i++];
  43.                     $pt[1] += $matches[1][$i++];
  44.                     break;
  45.                 case 'M' :
  46.                 case 'L' :
  47.                     $pt[0] = $matches[1][$i++];
  48.                     $pt[1] = $matches[1][$i++];
  49.                     break;
  50.                 case 'v' :
  51.                     $pt[1] += $matches[1][$i++];
  52.                     break;
  53.                 case 'V' :
  54.                     $pt[1] = $matches[1][$i++];
  55.                     break;
  56.                 case 'h' :
  57.                     $pt[0] += $matches[1][$i++];
  58.                     break;
  59.                 case 'H' :
  60.                     $pt[0] = $matches[1][$i++];
  61.                     break;
  62.                 case 'z' :
  63.                 case 'Z' :
  64.                     break;
  65.                 default :
  66.                     throw new RuntimeException("Unhandled path command: ".$command[0]);
  67.             }
  68.  
  69.             //expand bounds
  70.             $bounds->x1 = min($bounds->x1, $pt[0]);
  71.             $bounds->y1 = min($bounds->y1, $pt[1]);
  72.             $bounds->x2 = max($bounds->x2, $pt[0]);
  73.             $bounds->y2 = max($bounds->y2, $pt[1]);
  74.         }
  75.  
  76.     }
  77.  
  78.     //calculate width and height
  79.     $bounds->width = $bounds->x2 - $bounds->x1;
  80.     $bounds->height = $bounds->y2 - $bounds->y1;
  81.  
  82.     return $bounds;
  83. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement