<?php /** * @author Gasper Kozak * @copyright 2007-2011 This file is part of WideImage. WideImage is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. WideImage is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with WideImage; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * @package Internals **/ /** * @package Exceptions */ class WideImage_InvalidCoordinateException extends WideImage_Exception {} /** * A utility class for smart coordinates * * @package Internals **/ class WideImage_Coordinate { static protected $coord_align = array("left", "center", "right", "top", "middle", "bottom"); static protected $coord_numeric = array("[0-9]+", "[0-9]+\.[0-9]+", "[0-9]+%", "[0-9]+\.[0-9]+%"); /** * Parses a numeric or string representation of a corrdinate into a structure * * @param string $coord Smart coordinate * @return array Parsed smart coordinate */ static function parse($c) { $tokens = array(); $operators = array('+', '-'); $flush_operand = false; $flush_operator = false; $current_operand = ''; $current_operator = ''; $coordinate = strval($c); $expr_len = strlen($coordinate); for ($i = 0; $i < $expr_len; $i++) { $char = $coordinate[$i]; if (in_array($char, $operators)) { $flush_operand = true; $flush_operator = true; $current_operator = $char; } else { $current_operand .= $char; if ($i == $expr_len - 1) $flush_operand = true; } if ($flush_operand) { if (trim($current_operand) != '') $tokens[] = array('type' => 'operand', 'value' => trim($current_operand)); $current_operand = ''; $flush_operand = false; } if ($flush_operator) { $tokens[] = array('type' => 'operator', 'value' => $char); $flush_operator = false; } } return $tokens; } /** * Evaluates the $coord relatively to $dim * * @param string $coord A numeric value or percent string * @param int $dim Dimension * @param int $sec_dim Secondary dimension (for align) * @return int Calculated value */ static function evaluate($coord, $dim, $sec_dim = null) { $comp_regex = implode('|', self::$coord_align) . '|' . implode('|', self::$coord_numeric); if (preg_match("/^([+-])?({$comp_regex})$/", $coord, $matches)) { $sign = intval($matches[1] . "1"); $val = $matches[2]; if (in_array($val, self::$coord_align)) { if ($sec_dim === null) { switch ($val) { case 'left': case 'top': return 0; break; case 'center': case 'middle': return $sign * intval($dim / 2); break; case 'right': case 'bottom': return $sign * $dim; break; default: return null; } } else { switch ($val) { case 'left': case 'top': return 0; break; case 'center': case 'middle': return $sign * intval($dim / 2 - $sec_dim / 2); break; case 'right': case 'bottom': return $sign * ($dim - $sec_dim); break; default: return null; } } } elseif (substr($val, -1) === '%') return intval(round($sign * $dim * floatval(str_replace('%', '', $val)) / 100)); else return $sign * intval(round($val)); } } /** * Calculates and fixes a smart coordinate into a numeric value * * @param mixed $value Smart coordinate, relative to $dim * @param int $dim Coordinate to which $value is relative * @param int $sec_dim Secondary dimension (for align) * @return int Calculated value */ static function fix($value, $dim, $sec_dim = null) { $coord_tokens = self::parse($value); if (count($coord_tokens) == 0 || $coord_tokens[count($coord_tokens) - 1]['type'] != 'operand') throw new WideImage_InvalidCoordinateException("Couldn't parse coordinate '$value' properly."); $value = 0; $operation = 1; foreach ($coord_tokens as $token) { if ($token['type'] == 'operand') { $operand_value = self::evaluate($token['value'], $dim, $sec_dim); if ($operation == 1) $value = $value + $operand_value; elseif ($operation == -1) $value = $value - $operand_value; else throw new WideImage_InvalidCoordinateException("Invalid coordinate syntax."); $operation = 0; } elseif ($token['type'] == 'operator') { if ($token['value'] == '-') { if ($operation == 0) $operation = -1; else $operation = $operation * -1; } elseif ($token['value'] == '+') { if ($operation == 0) $operation = '1'; } } } return $value; } }