diff --git a/src/SimpleImageCompressor.php b/src/SimpleImageCompressor.php index 1e94a10..d2e9b1b 100644 --- a/src/SimpleImageCompressor.php +++ b/src/SimpleImageCompressor.php @@ -9,6 +9,9 @@ namespace geckon01\SimpleImageCompressor; +use geckon01\SimpleImageCompressor\Drivers\DriverInterface; +use geckon01\SimpleImageCompressor\Drivers\GdDriver; + /** * Class SimpleImageCompressor * @package geckon01\SimpleImageCompressor @@ -17,7 +20,6 @@ class SimpleImageCompressor { private const ALLOWED_IMAGE_FORMAT = "image/jpeg,image/png,image/gif,image/webp,image/bmp"; private string $imageResourceUrl; - private string $imageData; private string $imageType; private int $approxMinimumHeight = 90; @@ -25,17 +27,25 @@ class SimpleImageCompressor private bool $exifLoaded = false; + private ?DriverInterface $driver; /** * SimpleImageCompressor constructor. - * @param $url url or path from where to load file + * @param $url string url or path from where to load file + * @param DriverInterface|null $driver */ - private function __construct($url) + private function __construct(string $url, ?DriverInterface $driver = null) { $this->imageResourceUrl = $url; $this->exifLoaded = in_array("exif", get_loaded_extensions()); - } + if($driver == null) + { + $this->driver = new GdDriver(); + } else { + $this->driver = $driver; + } + } /** * Returns current loaded image type @@ -83,7 +93,7 @@ class SimpleImageCompressor /** * Determine current loaded image type */ - private function loadImageType() { + private function loadImageType(string $imageBinary) { $this->imageType = "image"; if($this->exifLoaded) { @@ -116,77 +126,43 @@ class SimpleImageCompressor // Fallback to bytes recognition trigger_error("simple-image-compressor: Exif extension not found. Image MIME type recognition may be inaccurate."); - if (substr($this->imageData, 0, 2) === "\xFF\xD8") { + if (substr($imageBinary, 0, 2) === "\xFF\xD8") { $this->imageType = 'image/jpeg'; } - if (substr($this->imageData, 0, 3) === "\x89\x50\x4E") { + if (substr($imageBinary, 0, 3) === "\x89\x50\x4E") { $this->imageType = 'image/png'; } - if (substr($this->imageData, 0, 4) === "\x47\x49\x46\x38") { + if (substr($imageBinary, 0, 4) === "\x47\x49\x46\x38") { $this->imageType = 'image/gif'; } } - /** - * Loading image from provided url. Whether it local file or internet resource - */ - private function readImageToString(): void { - $imageData = file_get_contents($this->imageResourceUrl); - - if($imageData === false) - throw new \Exception("Cannot load image from provided resource: ".$this->imageResourceUrl); - - $this->imageData = $imageData; - } - /** * Resizes and compressing image. * Note that gif compression not supported * @param int $reductionPercent percent shows how much image resolution to original will be. The greater percent, the lower resolution * @param int $quality * @return CompressedImage + * @throws \Exception */ public function resizeAndCompress($reductionPercent = 5, $quality = 90): CompressedImage { - $originImage = imagecreatefromstring($this->imageData); - - if($originImage === false) - throw new \Exception("Can not read provided file"); - - $width = imagesx($originImage); - $height = imagesy($originImage); - - $totalPixelCount = $width * $height; - $minimumPixelCount = $this->approxMinimumWidth * $this->approxMinimumHeight; - $maxReductionPercent = round(abs(100 - ($minimumPixelCount / $totalPixelCount * 100))); - - // Due to saving proportion we can't guarantee that width and height be equals max and min - // As example, if we have original image 1920*1080 which we want to get 50% of original resolution - // If we want to save 16*9 aspect ration it must be 960*540 - // So, we override $maxReductionPercent to value which satisfy origin aspect ratio - if($maxReductionPercent < $reductionPercent) - $reductionPercent = $maxReductionPercent; - - $newWidth = round($width - ($width * $reductionPercent) / 100); - $newHeight = round($height - ($height * $reductionPercent) / 100); - - $thumb = imagecreatetruecolor($newWidth, $newHeight); - imagecopyresized($thumb, $originImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height); - - return new CompressedImage($quality, $this->imageType,$thumb); + return $this->driver + ->resize($reductionPercent, $quality, $this->approxMinimumWidth, $this->approxMinimumHeight, $this->imageType); } /** * Initalize lib from provided image file path * @param string $urlImageResource image resource path. Can be local file or internet URL + * @param DriverInterface|null $driver * @return SimpleImageCompressor * @throws \Exception */ - public static function load(string $urlImageResource): SimpleImageCompressor + public static function load(string $urlImageResource, ?DriverInterface $driver = null): SimpleImageCompressor { - $compressorObject = new SimpleImageCompressor($urlImageResource); - $compressorObject->readImageToString(); - $compressorObject->loadImageType(); + $compressorObject = new SimpleImageCompressor($urlImageResource, $driver); + $compressorObject->driver->load($urlImageResource); + $compressorObject->loadImageType($compressorObject->driver->getImageBinary()); if(!str_contains(self::ALLOWED_IMAGE_FORMAT, $compressorObject->getImageType()) || $compressorObject->getImageType() === "") diff --git a/src/drivers/DriverInterface.php b/src/drivers/DriverInterface.php new file mode 100644 index 0000000..b8db834 --- /dev/null +++ b/src/drivers/DriverInterface.php @@ -0,0 +1,14 @@ +imageData); + + if($originImage === false) + throw new \Exception("Can not read provided file"); + + $width = imagesx($originImage); + $height = imagesy($originImage); + + $totalPixelCount = $width * $height; + $minimumPixelCount = $approxMinimumWidth * $approxMinimumHeight; + $maxReductionPercent = round(abs(100 - ($minimumPixelCount / $totalPixelCount * 100))); + + // Due to saving proportion we can't guarantee that width and height be equals max and min + // As example, if we have original image 1920*1080 which we want to get 50% of original resolution + // If we want to save 16*9 aspect ration it must be 960*540 + // So, we override $maxReductionPercent to value which satisfy origin aspect ratio + if($maxReductionPercent < $reductionPercent) + $reductionPercent = $maxReductionPercent; + + $newWidth = round($width - ($width * $reductionPercent) / 100); + $newHeight = round($height - ($height * $reductionPercent) / 100); + + $thumb = imagecreatetruecolor($newWidth, $newHeight); + imagecopyresized($thumb, $originImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height); + + return new CompressedImage($quality, $imageType, $thumb); + } + + function load(string $path): DriverInterface + { + $this->imageData = file_get_contents($path); + + if($this->imageData === false) + throw new \Exception("Cannot load image from provided resource: ".$path); + + return $this; + } + + function getImageBinary(): string + { + if($this->imageData == null) + throw new \Exception("Load image before getting its binary."); + + return $this->imageData; + } +} \ No newline at end of file