File indexing completed on 2025-03-02 05:33:39
0001 <?php 0002 0003 namespace Intervention\Image; 0004 0005 use Closure; 0006 0007 class Size 0008 { 0009 /** 0010 * Width 0011 * 0012 * @var int 0013 */ 0014 public $width; 0015 0016 /** 0017 * Height 0018 * 0019 * @var int 0020 */ 0021 public $height; 0022 0023 /** 0024 * Pivot point 0025 * 0026 * @var Point 0027 */ 0028 public $pivot; 0029 0030 /** 0031 * Creates a new Size instance 0032 * 0033 * @param int $width 0034 * @param int $height 0035 * @param Point $pivot 0036 */ 0037 public function __construct($width = null, $height = null, Point $pivot = null) 0038 { 0039 $this->width = is_numeric($width) ? intval($width) : 1; 0040 $this->height = is_numeric($height) ? intval($height) : 1; 0041 $this->pivot = $pivot ? $pivot : new Point; 0042 } 0043 0044 /** 0045 * Set the width and height absolutely 0046 * 0047 * @param int $width 0048 * @param int $height 0049 */ 0050 public function set($width, $height) 0051 { 0052 $this->width = $width; 0053 $this->height = $height; 0054 } 0055 0056 /** 0057 * Set current pivot point 0058 * 0059 * @param Point $point 0060 */ 0061 public function setPivot(Point $point) 0062 { 0063 $this->pivot = $point; 0064 } 0065 0066 /** 0067 * Get the current width 0068 * 0069 * @return int 0070 */ 0071 public function getWidth() 0072 { 0073 return $this->width; 0074 } 0075 0076 /** 0077 * Get the current height 0078 * 0079 * @return int 0080 */ 0081 public function getHeight() 0082 { 0083 return $this->height; 0084 } 0085 0086 /** 0087 * Calculate the current aspect ratio 0088 * 0089 * @return float 0090 */ 0091 public function getRatio() 0092 { 0093 return $this->width / $this->height; 0094 } 0095 0096 /** 0097 * Resize to desired width and/or height 0098 * 0099 * @param int $width 0100 * @param int $height 0101 * @param Closure $callback 0102 * @return Size 0103 */ 0104 public function resize($width, $height, Closure $callback = null) 0105 { 0106 if (is_null($width) && is_null($height)) { 0107 throw new \Intervention\Image\Exception\InvalidArgumentException( 0108 "Width or height needs to be defined." 0109 ); 0110 } 0111 0112 // new size with dominant width 0113 $dominant_w_size = clone $this; 0114 $dominant_w_size->resizeHeight($height, $callback); 0115 $dominant_w_size->resizeWidth($width, $callback); 0116 0117 // new size with dominant height 0118 $dominant_h_size = clone $this; 0119 $dominant_h_size->resizeWidth($width, $callback); 0120 $dominant_h_size->resizeHeight($height, $callback); 0121 0122 // decide which size to use 0123 if ($dominant_h_size->fitsInto(new self($width, $height))) { 0124 $this->set($dominant_h_size->width, $dominant_h_size->height); 0125 } else { 0126 $this->set($dominant_w_size->width, $dominant_w_size->height); 0127 } 0128 0129 return $this; 0130 } 0131 0132 /** 0133 * Scale size according to given constraints 0134 * 0135 * @param int $width 0136 * @param Closure $callback 0137 * @return Size 0138 */ 0139 private function resizeWidth($width, Closure $callback = null) 0140 { 0141 $constraint = $this->getConstraint($callback); 0142 0143 if ($constraint->isFixed(Constraint::UPSIZE)) { 0144 $max_width = $constraint->getSize()->getWidth(); 0145 $max_height = $constraint->getSize()->getHeight(); 0146 } 0147 0148 if (is_numeric($width)) { 0149 0150 if ($constraint->isFixed(Constraint::UPSIZE)) { 0151 $this->width = ($width > $max_width) ? $max_width : $width; 0152 } else { 0153 $this->width = $width; 0154 } 0155 0156 if ($constraint->isFixed(Constraint::ASPECTRATIO)) { 0157 $h = intval(round($this->width / $constraint->getSize()->getRatio())); 0158 0159 if ($constraint->isFixed(Constraint::UPSIZE)) { 0160 $this->height = ($h > $max_height) ? $max_height : $h; 0161 } else { 0162 $this->height = $h; 0163 } 0164 } 0165 } 0166 } 0167 0168 /** 0169 * Scale size according to given constraints 0170 * 0171 * @param int $height 0172 * @param Closure $callback 0173 * @return Size 0174 */ 0175 private function resizeHeight($height, Closure $callback = null) 0176 { 0177 $constraint = $this->getConstraint($callback); 0178 0179 if ($constraint->isFixed(Constraint::UPSIZE)) { 0180 $max_width = $constraint->getSize()->getWidth(); 0181 $max_height = $constraint->getSize()->getHeight(); 0182 } 0183 0184 if (is_numeric($height)) { 0185 0186 if ($constraint->isFixed(Constraint::UPSIZE)) { 0187 $this->height = ($height > $max_height) ? $max_height : $height; 0188 } else { 0189 $this->height = $height; 0190 } 0191 0192 if ($constraint->isFixed(Constraint::ASPECTRATIO)) { 0193 $w = intval(round($this->height * $constraint->getSize()->getRatio())); 0194 0195 if ($constraint->isFixed(Constraint::UPSIZE)) { 0196 $this->width = ($w > $max_width) ? $max_width : $w; 0197 } else { 0198 $this->width = $w; 0199 } 0200 } 0201 } 0202 } 0203 0204 /** 0205 * Calculate the relative position to another Size 0206 * based on the pivot point settings of both sizes. 0207 * 0208 * @param Size $size 0209 * @return \Intervention\Image\Point 0210 */ 0211 public function relativePosition(Size $size) 0212 { 0213 $x = $this->pivot->x - $size->pivot->x; 0214 $y = $this->pivot->y - $size->pivot->y; 0215 0216 return new Point($x, $y); 0217 } 0218 0219 /** 0220 * Resize given Size to best fitting size of current size. 0221 * 0222 * @param Size $size 0223 * @return \Intervention\Image\Size 0224 */ 0225 public function fit(Size $size, $position = 'center') 0226 { 0227 // create size with auto height 0228 $auto_height = clone $size; 0229 0230 $auto_height->resize($this->width, null, function ($constraint) { 0231 $constraint->aspectRatio(); 0232 }); 0233 0234 // decide which version to use 0235 if ($auto_height->fitsInto($this)) { 0236 0237 $size = $auto_height; 0238 0239 } else { 0240 0241 // create size with auto width 0242 $auto_width = clone $size; 0243 0244 $auto_width->resize(null, $this->height, function ($constraint) { 0245 $constraint->aspectRatio(); 0246 }); 0247 0248 $size = $auto_width; 0249 } 0250 0251 $this->align($position); 0252 $size->align($position); 0253 $size->setPivot($this->relativePosition($size)); 0254 0255 return $size; 0256 } 0257 0258 /** 0259 * Checks if given size fits into current size 0260 * 0261 * @param Size $size 0262 * @return boolean 0263 */ 0264 public function fitsInto(Size $size) 0265 { 0266 return ($this->width <= $size->width) && ($this->height <= $size->height); 0267 } 0268 0269 /** 0270 * Aligns current size's pivot point to given position 0271 * and moves point automatically by offset. 0272 * 0273 * @param string $position 0274 * @param int $offset_x 0275 * @param int $offset_y 0276 * @return \Intervention\Image\Size 0277 */ 0278 public function align($position, $offset_x = 0, $offset_y = 0) 0279 { 0280 switch (strtolower($position)) { 0281 0282 case 'top': 0283 case 'top-center': 0284 case 'top-middle': 0285 case 'center-top': 0286 case 'middle-top': 0287 $x = intval($this->width / 2); 0288 $y = 0 + $offset_y; 0289 break; 0290 0291 case 'top-right': 0292 case 'right-top': 0293 $x = $this->width - $offset_x; 0294 $y = 0 + $offset_y; 0295 break; 0296 0297 case 'left': 0298 case 'left-center': 0299 case 'left-middle': 0300 case 'center-left': 0301 case 'middle-left': 0302 $x = 0 + $offset_x; 0303 $y = intval($this->height / 2); 0304 break; 0305 0306 case 'right': 0307 case 'right-center': 0308 case 'right-middle': 0309 case 'center-right': 0310 case 'middle-right': 0311 $x = $this->width - $offset_x; 0312 $y = intval($this->height / 2); 0313 break; 0314 0315 case 'bottom-left': 0316 case 'left-bottom': 0317 $x = 0 + $offset_x; 0318 $y = $this->height - $offset_y; 0319 break; 0320 0321 case 'bottom': 0322 case 'bottom-center': 0323 case 'bottom-middle': 0324 case 'center-bottom': 0325 case 'middle-bottom': 0326 $x = intval($this->width / 2); 0327 $y = $this->height - $offset_y; 0328 break; 0329 0330 case 'bottom-right': 0331 case 'right-bottom': 0332 $x = $this->width - $offset_x; 0333 $y = $this->height - $offset_y; 0334 break; 0335 0336 case 'center': 0337 case 'middle': 0338 case 'center-center': 0339 case 'middle-middle': 0340 $x = intval($this->width / 2); 0341 $y = intval($this->height / 2); 0342 break; 0343 0344 default: 0345 case 'top-left': 0346 case 'left-top': 0347 $x = 0 + $offset_x; 0348 $y = 0 + $offset_y; 0349 break; 0350 } 0351 0352 $this->pivot->setPosition($x, $y); 0353 0354 return $this; 0355 } 0356 0357 /** 0358 * Runs constraints on current size 0359 * 0360 * @param Closure $callback 0361 * @return \Intervention\Image\Constraint 0362 */ 0363 private function getConstraint(Closure $callback = null) 0364 { 0365 $constraint = new Constraint(clone $this); 0366 0367 if (is_callable($callback)) { 0368 $callback($constraint); 0369 } 0370 0371 return $constraint; 0372 } 0373 }