From 86321df3f8e52408dda34924a9e9b51c369fb033 Mon Sep 17 00:00:00 2001 From: Jack Wilkinson Date: Fri, 18 Mar 2022 16:02:44 +0000 Subject: [PATCH 1/2] Added php8.0 features to Resizer --- src/Database/Attach/Resizer.php | 158 +++++++++++++++----------------- 1 file changed, 73 insertions(+), 85 deletions(-) diff --git a/src/Database/Attach/Resizer.php b/src/Database/Attach/Resizer.php index 777d4b972..165d3665c 100644 --- a/src/Database/Attach/Resizer.php +++ b/src/Database/Attach/Resizer.php @@ -1,6 +1,7 @@ mime === 'image/gif') { $alphaIndex = imagecolortransparent($this->image); @@ -140,7 +141,7 @@ protected function retainImageTransparency($img) * Resets the image back to the original. * @return self */ - public function reset() + public function reset(): static { $this->image = $this->originalImage; @@ -157,7 +158,7 @@ public function reset() * @param array $options Set of resizing option * @return self */ - public function setOptions($options) + public function setOptions(array $options): static { $this->options = array_merge([ 'mode' => 'auto', @@ -176,7 +177,7 @@ public function setOptions($options) * @param mixed $value Option value to set * @return self */ - protected function setOption($option, $value) + protected function setOption(string $option, mixed $value): static { $this->options[$option] = $value; @@ -188,7 +189,7 @@ protected function setOption($option, $value) * @param string $option Option name to get * @return mixed Depends on the option */ - protected function getOption($option) + protected function getOption(string $option): mixed { return array_get($this->options, $option); } @@ -198,7 +199,7 @@ protected function getOption($option) * @param \Symfony\Component\HttpFoundation\File\File $file * @return int|null */ - protected function getOrientation($file) + protected function getOrientation(FileObj $file): ?int { $filePath = $file->getPathname(); @@ -228,7 +229,7 @@ protected function getOrientation($file) * the exif orientation * @return int */ - protected function getWidth() + protected function getWidth(): int { switch ($this->orientation) { case 6: @@ -247,7 +248,7 @@ protected function getWidth() * the exif orientation * @return int */ - protected function getHeight() + protected function getHeight(): int { switch ($this->orientation) { case 6: @@ -264,9 +265,9 @@ protected function getHeight() /** * Receives the original but rotated image * according to exif orientation - * @return resource (gd) + * @return GdImage */ - protected function getRotatedOriginal() + protected function getRotatedOriginal(): GdImage { switch ($this->orientation) { case 6: @@ -298,16 +299,10 @@ protected function getRotatedOriginal() * @return self * @throws Exception */ - public function resize($newWidth, $newHeight, $options = []) + public function resize(int $newWidth, int $newHeight, array $options = []): static { $this->setOptions($options); - /* - * Sanitize input - */ - $newWidth = (int) $newWidth; - $newHeight = (int) $newHeight; - if (!$newWidth && !$newHeight) { $newWidth = $this->width; $newHeight = $this->height; @@ -376,7 +371,7 @@ public function resize($newWidth, $newHeight, $options = []) * @param int $sharpness * @return self */ - public function sharpen($sharpness) + public function sharpen(int $sharpness): static { if ($sharpness <= 0 || $sharpness > 100) { return $this; @@ -412,7 +407,14 @@ public function sharpen($sharpness) * @param int $srcHeight Source area height. * @return self */ - public function crop($cropStartX, $cropStartY, $newWidth, $newHeight, $srcWidth = null, $srcHeight = null) + public function crop( + int $cropStartX, + int $cropStartY, + int $newWidth, + int $newHeight, + int $srcWidth = null, + int $srcHeight = null + ): static { $image = $this->image; @@ -440,7 +442,7 @@ public function crop($cropStartX, $cropStartY, $newWidth, $newHeight, $srcWidth * @param string $savePath Where to save the image * @throws Exception Thrown for invalid extension */ - public function save($savePath) + public function save(string $savePath): void { $image = $this->image; @@ -502,10 +504,10 @@ public function save($savePath) /** * Open a file, detect its mime-type and create an image resource from it. * @param \Symfony\Component\HttpFoundation\File\File $file File instance - * @return mixed + * @return GdImage * @throws Exception Thrown for invalid MIME type */ - protected function openImage($file) + protected function openImage(FileObj $file): GdImage { $filePath = $file->getPathname(); @@ -534,45 +536,33 @@ protected function openImage($file) /** * Return the image dimensions based on the option that was chosen. - * @param int $newWidth The width of the image - * @param int $newHeight The height of the image + * @param float $newWidth The width of the image + * @param float $newHeight The height of the image * @return array * @throws Exception Thrown for invalid dimension string */ - protected function getDimensions($newWidth, $newHeight) + #[ArrayShape(['width' => 'float', 'height' => 'float'])] + protected function getDimensions(float $newWidth, float $newHeight): array { $mode = $this->getOption('mode'); - switch ($mode) { - case 'exact': - return [$newWidth, $newHeight]; - - case 'portrait': - return [$this->getSizeByFixedHeight($newHeight), $newHeight]; - - case 'landscape': - return [$newWidth, $this->getSizeByFixedWidth($newWidth)]; - - case 'auto': - return $this->getSizeByAuto($newWidth, $newHeight); - - case 'crop': - return $this->getOptimalCrop($newWidth, $newHeight); - - case 'fit': - return $this->getSizeByFit($newWidth, $newHeight); - - default: - throw new Exception('Invalid dimension type. Accepted types: exact, portrait, landscape, auto, crop, fit.'); - } + return match ($mode) { + 'exact' => [$newWidth, $newHeight], + 'portrait' => [$this->getSizeByFixedHeight($newHeight), $newHeight], + 'landscape' => [$newWidth, $this->getSizeByFixedWidth($newWidth)], + 'auto' => $this->getSizeByAuto($newWidth, $newHeight), + 'crop' => $this->getOptimalCrop($newWidth, $newHeight), + 'fit' => $this->getSizeByFit($newWidth, $newHeight), + default => throw new Exception('Invalid dimension type. Accepted types: exact, portrait, landscape, auto, crop, fit.'), + }; } /** * Returns the width based on the image height - * @param int $newHeight The height of the image - * @return int + * @param float $newHeight The height of the image + * @return float */ - protected function getSizeByFixedHeight($newHeight) + protected function getSizeByFixedHeight(float $newHeight): float { $ratio = $this->width / $this->height; return $newHeight * $ratio; @@ -580,10 +570,10 @@ protected function getSizeByFixedHeight($newHeight) /** * Returns the height based on the image width - * @param int $newWidth The width of the image - * @return int + * @param float $newWidth The width of the image + * @return float */ - protected function getSizeByFixedWidth($newWidth) + protected function getSizeByFixedWidth(float $newWidth): float { $ratio = $this->height / $this->width; return $newWidth * $ratio; @@ -591,11 +581,12 @@ protected function getSizeByFixedWidth($newWidth) /** * Checks to see if an image is portrait or landscape and resizes accordingly. - * @param int $newWidth The width of the image - * @param int $newHeight The height of the image + * @param float $newWidth The width of the image + * @param float $newHeight The height of the image * @return array */ - protected function getSizeByAuto($newWidth, $newHeight) + #[ArrayShape(['width' => 'float', 'height' => 'float'])] + protected function getSizeByAuto(float $newWidth, float $newHeight): array { // Less than 1 pixel height and width? (revert to original) if ($newWidth <= 1 && $newHeight <= 1) { @@ -643,21 +634,17 @@ protected function getSizeByAuto($newWidth, $newHeight) /** * Attempts to find the best way to crop. Whether crop is based on the * image being portrait or landscape. - * @param int $newWidth The width of the image - * @param int $newHeight The height of the image + * @param float $newWidth The width of the image + * @param float $newHeight The height of the image * @return array */ - protected function getOptimalCrop($newWidth, $newHeight) + #[ArrayShape(['width' => 'float', 'height' => 'float'])] + protected function getOptimalCrop(float $newWidth, float $newHeight): array { $heightRatio = $this->height / $newHeight; $widthRatio = $this->width / $newWidth; - if ($heightRatio < $widthRatio) { - $optimalRatio = $heightRatio; - } - else { - $optimalRatio = $widthRatio; - } + $optimalRatio = min($heightRatio, $widthRatio); $optimalHeight = round($this->height / $optimalRatio); $optimalWidth = round($this->width / $optimalRatio); @@ -667,11 +654,12 @@ protected function getOptimalCrop($newWidth, $newHeight) /** * Fit the image inside a bounding box using maximum width and height constraints. - * @param int $maxWidth The maximum width of the image - * @param int $maxHeight The maximum height of the image + * @param float $maxWidth The maximum width of the image + * @param float $maxHeight The maximum height of the image * @return array */ - protected function getSizeByFit($maxWidth, $maxHeight) + #[ArrayShape(['width' => 'float', 'height' => 'float'])] + protected function getSizeByFit(float $maxWidth, float $maxHeight): array { // Calculate the scaling ratios in order to get the target width and height From 7c40616a95b4bb413497c3159f8d07ae6f3c7ed9 Mon Sep 17 00:00:00 2001 From: Jack Wilkinson Date: Fri, 18 Mar 2022 16:14:38 +0000 Subject: [PATCH 2/2] Added styling fix --- src/Database/Attach/Resizer.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Database/Attach/Resizer.php b/src/Database/Attach/Resizer.php index 165d3665c..e44db7a49 100644 --- a/src/Database/Attach/Resizer.php +++ b/src/Database/Attach/Resizer.php @@ -414,8 +414,7 @@ public function crop( int $newHeight, int $srcWidth = null, int $srcHeight = null - ): static - { + ): static { $image = $this->image; if ($srcWidth === null) {