src/Common/Resize.php line 98

Open in your IDE?
  1. <?php
  2. namespace App\Common;
  3. use GdImage;
  4. class Resize
  5. {
  6.     // *** Class variables
  7.     private ?GdImage $image;
  8.     private int $width = -1;
  9.     private int $height = -1;
  10.     private ?GdImage $imageResized;
  11.     private string $extension "";
  12.     public function build(string $fileName)
  13.     {
  14.         // *** Open up the file
  15.         $this->image $this->openImage($fileName);
  16.         // *** Get width and height
  17.         $this->width imagesx($this->image);
  18.         $this->height imagesy($this->image);
  19.         if (!$this->image || $this->width <= || $this->height<=0) {
  20.             throw new \Exception('Unable to open image.');
  21.         }
  22.     }
  23.     ## --------------------------------------------------------
  24.     private function openImage($file)
  25.     {
  26.         // *** Get extension
  27.         $this->extension strtolower(strrchr($file'.'));
  28.         $img = match ($this->extension) {
  29.             '.jpg''.jpeg' => @imagecreatefromjpeg($file),
  30.             '.gif' => @imagecreatefromgif($file),
  31.             '.png' => @imagecreatefrompng($file),
  32.             default => false,
  33.         };
  34.         if (!$img) {
  35.             throw new \Exception('Unable to open image.');
  36.         }
  37.         // *** Get EXIF data
  38.         $exif exif_read_data($file);
  39.         // *** Handle Rotation
  40.         if ($exif && isset($exif['Orientation'])) {
  41.             $orientation $exif['Orientation'];
  42.             if ($orientation != 1) {
  43.                 $deg 0;
  44.                 switch ($orientation) {
  45.                     case 3:
  46.                         $deg 180;
  47.                         break;
  48.                     case 6:
  49.                         $deg 270;
  50.                         break;
  51.                     case 8:
  52.                         $deg 90;
  53.                         break;
  54.                 }
  55.                 if ($deg) {
  56.                     $img imagerotate($img$deg0);
  57.                 }
  58.             }
  59.         }
  60.         return $img;
  61.     }
  62.     ## --------------------------------------------------------
  63.     public function resizeImage($newWidth$newHeight$option "auto")
  64.     {
  65.         // *** Get optimal width and height - based on $option
  66.         $optionArray $this->getDimensions($newWidth$newHeight$option);
  67.         $optimalWidth $optionArray['optimalWidth'];
  68.         $optimalHeight $optionArray['optimalHeight'];
  69.         // *** Resample - create image canvas of x, y size
  70.         $this->imageResized imagecreatetruecolor($optimalWidth$optimalHeight);
  71.         imagecopyresampled(
  72.             $this->imageResized,
  73.             $this->image,
  74.             0,
  75.             0,
  76.             0,
  77.             0,
  78.             $optimalWidth,
  79.             $optimalHeight,
  80.             $this->width,
  81.             $this->height
  82.         );
  83.         // *** if option is 'crop', then crop too
  84.         if ($option == 'crop') {
  85.             $this->crop($optimalWidth$optimalHeight$newWidth$newHeight);
  86.         }
  87.     }
  88.     ## --------------------------------------------------------
  89.     private function getDimensions($newWidth$newHeight$option): array
  90.     {
  91.         switch ($option) {
  92.             case 'exact':
  93.                 $optimalWidth $newWidth;
  94.                 $optimalHeight $newHeight;
  95.                 break;
  96.             case 'portrait':
  97.                 $optimalWidth $this->getSizeByFixedHeight($newHeight);
  98.                 $optimalHeight $newHeight;
  99.                 break;
  100.             case 'landscape':
  101.                 $optimalWidth $newWidth;
  102.                 $optimalHeight $this->getSizeByFixedWidth($newWidth);
  103.                 break;
  104.             case 'crop':
  105.                 $optionArray $this->getOptimalCrop($newWidth$newHeight);
  106.                 $optimalWidth $optionArray['optimalWidth'];
  107.                 $optimalHeight $optionArray['optimalHeight'];
  108.                 break;
  109.             case 'auto':
  110.             default:
  111.                 $optionArray $this->getSizeByAuto($newWidth$newHeight);
  112.                 $optimalWidth $optionArray['optimalWidth'];
  113.                 $optimalHeight $optionArray['optimalHeight'];
  114.                 break;
  115.         }
  116.         return ['optimalWidth' => $optimalWidth'optimalHeight' => $optimalHeight];
  117.     }
  118.     ## --------------------------------------------------------
  119.     private function getSizeByFixedHeight($newHeight)
  120.     {
  121.         $ratio $this->width $this->height;
  122.         return $newHeight $ratio;
  123.     }
  124.     private function getSizeByFixedWidth($newWidth)
  125.     {
  126.         $ratio $this->height $this->width;
  127.         return $newWidth $ratio;
  128.     }
  129.     private function getOptimalCrop($newWidth$newHeight): array
  130.     {
  131.         $heightRatio $this->height $newHeight;
  132.         $widthRatio $this->width $newWidth;
  133.         if ($heightRatio $widthRatio) {
  134.             $optimalRatio $heightRatio;
  135.         } else {
  136.             $optimalRatio $widthRatio;
  137.         }
  138.         $optimalHeight $this->height $optimalRatio;
  139.         $optimalWidth $this->width $optimalRatio;
  140.         return ['optimalWidth' => $optimalWidth'optimalHeight' => $optimalHeight];
  141.     }
  142.     ## --------------------------------------------------------
  143.     private function getSizeByAuto($newWidth$newHeight): array
  144.     {
  145.         if ($this->height $this->width) { // *** Image to be resized is wider (landscape)
  146.             $optimalWidth $newWidth;
  147.             $optimalHeight $this->getSizeByFixedWidth($newWidth);
  148.         } elseif ($this->height $this->width) { // *** Image to be resized is taller (portrait)
  149.             $optimalWidth $this->getSizeByFixedHeight($newHeight);
  150.             $optimalHeight $newHeight;
  151.         } else { // *** Image to be resizerd is a square
  152.             if ($newHeight $newWidth) {
  153.                 $optimalWidth $newWidth;
  154.                 $optimalHeight $this->getSizeByFixedWidth($newWidth);
  155.             } else {
  156.                 if ($newHeight $newWidth) {
  157.                     $optimalWidth $this->getSizeByFixedHeight($newHeight);
  158.                     $optimalHeight $newHeight;
  159.                 } else {
  160.                     // *** Sqaure being resized to a square
  161.                     $optimalWidth $newWidth;
  162.                     $optimalHeight $newHeight;
  163.                 }
  164.             }
  165.         }
  166.         return ['optimalWidth' => $optimalWidth'optimalHeight' => $optimalHeight];
  167.     }
  168.     ## --------------------------------------------------------
  169.     private function crop($optimalWidth$optimalHeight$newWidth$newHeight)
  170.     {
  171.         // *** Find center - this will be used for the crop
  172.         $cropStartX = ($optimalWidth 2) - ($newWidth 2);
  173.         $cropStartY = ($optimalHeight 2) - ($newHeight 2);
  174.         $crop $this->imageResized;
  175.         //imagedestroy($this->imageResized);
  176.         // *** Now crop from center to exact requested size
  177.         $this->imageResized imagecreatetruecolor($newWidth$newHeight);
  178.         imagecopyresampled(
  179.             $this->imageResized,
  180.             $crop,
  181.             0,
  182.             0,
  183.             $cropStartX,
  184.             $cropStartY,
  185.             $newWidth,
  186.             $newHeight,
  187.             $newWidth,
  188.             $newHeight
  189.         );
  190.     }
  191.     ## --------------------------------------------------------
  192.     public function saveImage($savePath$imageQuality "100")
  193.     {
  194.         // *** Get extension
  195.         $extension strrchr($savePath'.');
  196.         $extension strtolower($extension);
  197.         switch ($extension) {
  198.             case '.jpg':
  199.             case '.jpeg':
  200.                 if (imagetypes() & IMG_JPG) {
  201.                     imagejpeg($this->imageResized$savePath$imageQuality);
  202.                 }
  203.                 break;
  204.             case '.gif':
  205.                 if (imagetypes() & IMG_GIF) {
  206.                     imagegif($this->imageResized$savePath);
  207.                 }
  208.                 break;
  209.             case '.png':
  210.                 // *** Scale quality from 0-100 to 0-9
  211.                 $scaleQuality round(($imageQuality 100) * 9);
  212.                 // *** Invert quality setting as 0 is best, not 9
  213.                 $invertScaleQuality $scaleQuality;
  214.                 if (imagetypes() & IMG_PNG) {
  215.                     imagepng($this->imageResized$savePath$invertScaleQuality);
  216.                 }
  217.                 break;
  218.             default:
  219.                 // *** No extension - No save.
  220.                 break;
  221.         }
  222.         imagedestroy($this->imageResized);
  223.     }
  224.     ## --------------------------------------------------------
  225.     public function getImage()
  226.     {
  227.         switch ($this->extension) {
  228.             case '.jpg':
  229.             case '.jpeg':
  230.                 if (imagetypes() & IMG_JPG) {
  231.                     imagejpeg($this->imageResized);
  232.                 }
  233.                 break;
  234.             case '.gif':
  235.                 if (imagetypes() & IMG_GIF) {
  236.                     imagegif($this->imageResized);
  237.                 }
  238.                 break;
  239.             case '.png':
  240.                 if (imagetypes() & IMG_PNG) {
  241.                     imagepng($this->imageResized);
  242.                 }
  243.                 break;
  244.             default:
  245.                 // *** No extension - No save.
  246.                 break;
  247.         }
  248.         imagedestroy($this->imageResized);
  249.     }
  250.     ## --------------------------------------------------------
  251.     public function getContentType(): string
  252.     {
  253.         return match ($this->extension) {
  254.             ".jpeg"".jpg" => "image/jpeg",
  255.             ".gif" => "image/gif",
  256.             ".png" => "image/png",
  257.             default => "",
  258.         };
  259.     }
  260.     public function getHeight(): int
  261.     {
  262.         return $this->height;
  263.     }
  264.     public function getWidth(): int
  265.     {
  266.         return $this->width;
  267.     }
  268. }