mirror of
https://github.com/Geckon01/simple-image-compressor.git
synced 2026-06-17 00:37:50 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5109dfd39 | |||
| fef495df07 | |||
| e3c759a75a | |||
| dca7db5442 | |||
| 178c158618 | |||
| 1baf7ae2ca | |||
| a7461536bc | |||
| f9b21bcf05 | |||
| de877f3b6a | |||
| 10338aec18 | |||
| 1e0f13a7a6 | |||
| a538362343 | |||
| a6f42255c8 |
@@ -2,15 +2,26 @@
|
|||||||
|
|
||||||
# SimpleImageCompressor
|
# SimpleImageCompressor
|
||||||
|
|
||||||
[![Software License][ico-license]](LICENSE.md)
|
|
||||||
|
|
||||||
**SimpleImageCompressor** - is a tiny simple PHP image compressor lib which allows you to compress any image easily on the fly.
|

|
||||||
|

|
||||||
|

|
||||||
|
[](https://app.codacy.com/gh/Geckon01/simple-image-compressor/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
|
||||||
|
|
||||||
|
**SimpleImageCompressor** - is a tiny simple PHP image resizer lib which allows you to resize and compress any image easily on the fly.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Download latest release [here](https://github.com/Geckon01/simple-image-compressor/releases).
|
### With composer
|
||||||
2. Unpack archive to any folder of your project you wish.
|
```bash
|
||||||
3. Load main lib files:
|
composer require "geckon01/simple-image-compressor"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Without composer
|
||||||
|
|
||||||
|
1. Download latest release [here](https://github.com/Geckon01/simple-image-compressor/releases).
|
||||||
|
2. Unpack the archive to your project directory.
|
||||||
|
3. Include the library files:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
require "src/SimpleImageCompressor.php";
|
require "src/SimpleImageCompressor.php";
|
||||||
@@ -20,26 +31,25 @@ use geckon01\SimpleImageCompressor\SimpleImageCompressor;
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
To resize and compress your image you can use next code:
|
Resize and compress an image:
|
||||||
```php
|
```php
|
||||||
$resulutionTargetPercent = 50;
|
$resolutionTargetPercent = 50;
|
||||||
$targetQuality = 50;
|
$targetQuality = 50;
|
||||||
$compressor = SimpleImageCompressor::load("image.png");
|
$compressor = SimpleImageCompressor::load("image.png");
|
||||||
$compressedImage = $compressor->resizeAndCompress($resulutionTargetPercent, $targetQuality);
|
$compressedImage = $compressor->resizeAndCompress($resolutionTargetPercent, $targetQuality);
|
||||||
$compressedImage->toFile("image");
|
$compressedImage->toFile("image");
|
||||||
```
|
```
|
||||||
load method supports loading from local file, or you can specify any valid URL image link like this:
|
load method supports loading from local file, or you can specify any valid URL image link like this:
|
||||||
```php
|
```php
|
||||||
$compressor = SimpleImageCompressor::load("https://example.com/image.jpg");
|
$compressor = SimpleImageCompressor::load("https://example.com/image.jpg");
|
||||||
```
|
```
|
||||||
This lib support chaining, so you can do something like this:
|
Method chaining is supported:
|
||||||
```php
|
```php
|
||||||
SimpleImageCompressor::load("image.png")
|
SimpleImageCompressor::load("image.png")
|
||||||
->resizeAndCompress(50, 50)
|
->resizeAndCompress(50, 50)
|
||||||
->toFile("image");
|
->toFile("image");
|
||||||
```
|
```
|
||||||
> Note that you don't need to specify file extension. The lib will save
|
> Note: File extensions are automatically added. Use toFile("filename") without extension.
|
||||||
> file with proper one automatically.
|
|
||||||
|
|
||||||
### Output format
|
### Output format
|
||||||
You can specify output format. Supported output fomats are:
|
You can specify output format. Supported output fomats are:
|
||||||
@@ -53,17 +63,15 @@ $compressedImage->toBase64();
|
|||||||
```php
|
```php
|
||||||
$compressedImage->toGdImage();
|
$compressedImage->toGdImage();
|
||||||
```
|
```
|
||||||
### Max/min height/width
|
### Size Constraints
|
||||||
Also you can set approximate minumum and maximum image size.
|
Set approximate minimum dimensions (aspect ratio preserved):
|
||||||
```php
|
```php
|
||||||
$compressor->setApproxMinimumHeight(500);
|
$compressor->setApproxMinimumHeight(500);
|
||||||
$compressor->setApproxMinimumWidth(500);
|
$compressor->setApproxMinimumWidth(500);
|
||||||
```
|
```
|
||||||
> Note that Due to saving proportion lib can't guarantee that width and height be equals max and min .
|
> Note actual dimensions may differ due to aspect ratio preservation.
|
||||||
As example, if we have original image 1920x1080 which we want to get 50% of original resolution and save original 16x9 aspect ration the reduced image must be 960x540.
|
Example: 1920×1080 image reduced to 50% becomes 960×540 (maintaining 16:9).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This software is licensed under the MIT License. [View the license](LICENSE.md).
|
This software is licensed under the MIT License. [View the license](LICENSE.md).
|
||||||
|
|
||||||
[ico-license]: https://img.shields.io/badge/license-MIT-green
|
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "geckon01/simple-image-compressor",
|
"name": "geckon01/simple-image-compressor",
|
||||||
"description": "SimpleImageCompressor is a tiny simple PHP image compressor lib which allows you to compress any image easily on the fly",
|
"description": "SimpleImageCompressor is a tiny simple PHP image compressor lib which allows you to compress any image easily on the fly",
|
||||||
"version": "0.3.1",
|
"version": "0.4.3.25",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"php",
|
"php",
|
||||||
"images",
|
"images",
|
||||||
|
|||||||
+14
-2
@@ -57,11 +57,17 @@ class CompressedImage
|
|||||||
imagejpeg($this->imageObject, null, $this->qualityRate);
|
imagejpeg($this->imageObject, null, $this->qualityRate);
|
||||||
break;
|
break;
|
||||||
case "image/png":
|
case "image/png":
|
||||||
imagepng( $this->imageObject, null, self::mapValue($this->qualityRate, 0, 100, 0, 9));
|
imagepng($this->imageObject, null, self::mapValue($this->qualityRate, 0, 100, 0, 9));
|
||||||
break;
|
break;
|
||||||
case "image/gif":
|
case "image/gif":
|
||||||
imagegif($this->imageObject);
|
imagegif($this->imageObject);
|
||||||
break;
|
break;
|
||||||
|
case "image/webp":
|
||||||
|
imagewebp($this->imageObject);
|
||||||
|
break;
|
||||||
|
case "image/bmp":
|
||||||
|
imagebmp($this->imageObject);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
$base64_output = ob_get_contents();
|
$base64_output = ob_get_contents();
|
||||||
ob_end_clean();
|
ob_end_clean();
|
||||||
@@ -81,11 +87,17 @@ class CompressedImage
|
|||||||
imagejpeg($this->imageObject, $filePath.".jpg", $this->qualityRate);
|
imagejpeg($this->imageObject, $filePath.".jpg", $this->qualityRate);
|
||||||
break;
|
break;
|
||||||
case "image/png":
|
case "image/png":
|
||||||
imagepng( $this->imageObject, $filePath.".png", self::mapValue($this->qualityRate, 0, 100, 0, 9));
|
imagepng($this->imageObject, $filePath.".png", self::mapValue($this->qualityRate, 0, 100, 0, 9));
|
||||||
break;
|
break;
|
||||||
case "image/gif":
|
case "image/gif":
|
||||||
imagegif($this->imageObject, $filePath.".gif");
|
imagegif($this->imageObject, $filePath.".gif");
|
||||||
break;
|
break;
|
||||||
|
case "image/webp":
|
||||||
|
imagewebp($this->imageObject, $filePath.".webp");
|
||||||
|
break;
|
||||||
|
case "image/bmp":
|
||||||
|
imagebmp($this->imageObject, $filePath.".bmp");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,27 +8,43 @@
|
|||||||
|
|
||||||
namespace geckon01\SimpleImageCompressor;
|
namespace geckon01\SimpleImageCompressor;
|
||||||
|
|
||||||
|
|
||||||
|
use geckon01\SimpleImageCompressor\Drivers\DriverInterface;
|
||||||
|
use geckon01\SimpleImageCompressor\Drivers\GdDriver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class SimpleImageCompressor
|
* Class SimpleImageCompressor
|
||||||
* @package geckon01\SimpleImageCompressor
|
* @package geckon01\SimpleImageCompressor
|
||||||
*/
|
*/
|
||||||
class SimpleImageCompressor
|
class SimpleImageCompressor
|
||||||
{
|
{
|
||||||
private const ALLOWED_IMAGE_FORMAT = "image/jpeg,image/png,image/gif";
|
private const ALLOWED_IMAGE_FORMAT = "image/jpeg,image/png,image/gif,image/webp,image/bmp";
|
||||||
private string $imageResourceUrl;
|
private string $imageResourceUrl;
|
||||||
private string $imageData;
|
|
||||||
private string $imageType;
|
private string $imageType;
|
||||||
|
|
||||||
private int $approxMinimumHeight = 90;
|
private int $approxMinimumHeight = 90;
|
||||||
private int $approxMinimumWidth = 90;
|
private int $approxMinimumWidth = 90;
|
||||||
|
|
||||||
|
private bool $exifLoaded = false;
|
||||||
|
|
||||||
|
private ?DriverInterface $driver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SimpleImageCompressor constructor.
|
* SimpleImageCompressor constructor.
|
||||||
* @param $url
|
* @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->imageResourceUrl = $url;
|
||||||
|
$this->exifLoaded = in_array("exif", get_loaded_extensions());
|
||||||
|
if($driver == null)
|
||||||
|
{
|
||||||
|
$this->driver = new GdDriver();
|
||||||
|
} else {
|
||||||
|
$this->driver = $driver;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,72 +93,76 @@ class SimpleImageCompressor
|
|||||||
/**
|
/**
|
||||||
* Determine current loaded image type
|
* Determine current loaded image type
|
||||||
*/
|
*/
|
||||||
private function loadImageType() {
|
private function loadImageType(string $imageBinary) {
|
||||||
$filetype = '';
|
$this->imageType = "image";
|
||||||
|
|
||||||
if (substr($this->imageData, 0, 2) === "\xFF\xD8") {
|
if($this->exifLoaded) {
|
||||||
$filetype = 'image/jpeg';
|
switch (exif_imagetype($this->imageResourceUrl))
|
||||||
} elseif (substr($this->imageData, 0, 3) === "\x89\x50\x4E") {
|
{
|
||||||
$filetype = 'image/png';
|
case IMAGETYPE_GIF:
|
||||||
} elseif (substr($this->imageData, 0, 4) === "\x47\x49\x46\x38") {
|
$this->imageType = 'image/gif';
|
||||||
$filetype = 'image/gif';
|
break;
|
||||||
|
case IMAGETYPE_JPEG:
|
||||||
|
$this->imageType = 'image/jpeg';
|
||||||
|
break;
|
||||||
|
case IMAGETYPE_PNG:
|
||||||
|
$this->imageType = 'image/png';
|
||||||
|
break;
|
||||||
|
case IMAGETYPE_BMP:
|
||||||
|
$this->imageType = 'image/bmp';
|
||||||
|
break;
|
||||||
|
case IMAGETYPE_WEBP:
|
||||||
|
$this->imageType = 'image/webp';
|
||||||
|
break;
|
||||||
|
case IMAGETYPE_ICO:
|
||||||
|
$this->imageType = 'image/ico';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to bytes recognition
|
||||||
|
trigger_error("simple-image-compressor: Exif extension not found. Image MIME type recognition may be inaccurate.");
|
||||||
|
|
||||||
|
if (substr($imageBinary, 0, 2) === "\xFF\xD8") {
|
||||||
|
$this->imageType = 'image/jpeg';
|
||||||
|
}
|
||||||
|
if (substr($imageBinary, 0, 3) === "\x89\x50\x4E") {
|
||||||
|
$this->imageType = 'image/png';
|
||||||
|
}
|
||||||
|
if (substr($imageBinary, 0, 4) === "\x47\x49\x46\x38") {
|
||||||
|
$this->imageType = 'image/gif';
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->imageType = $filetype;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loading image from provided url. Whether it local file or internet resource
|
|
||||||
*/
|
|
||||||
private function readImageToString(): void {
|
|
||||||
$imageData = file_get_contents($this->imageResourceUrl);
|
|
||||||
$this->imageData = $imageData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes and compressing image.
|
* Resizes and compressing image.
|
||||||
* Note that gif compression not supported
|
* Note that gif compression not supported
|
||||||
* @param int $resolutionReductionPercent percent shows how much image resolution to original will be. The greater percent, the lower resolution
|
* @param int $reductionPercent percent shows how much image resolution to original will be. The greater percent, the lower resolution
|
||||||
* @param int $quality
|
* @param int $quality
|
||||||
* @return CompressedImage
|
* @return CompressedImage
|
||||||
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function resizeAndCompress($resolutionReductionPercent = 5, $quality = 90): CompressedImage
|
public function resizeAndCompress($reductionPercent = 5, $quality = 90): CompressedImage
|
||||||
{
|
{
|
||||||
$im = imagecreatefromstring($this->imageData);
|
return $this->driver
|
||||||
$width = imagesx($im);
|
->resize($reductionPercent, $quality, $this->approxMinimumWidth, $this->approxMinimumHeight, $this->imageType);
|
||||||
$height = imagesy($im);
|
|
||||||
|
|
||||||
$totalPixelCount = $width * $height;
|
|
||||||
$minimumPixelCount = $this->approxMinimumWidth * $this->approxMinimumHeight;
|
|
||||||
$maximumResolutionReductionPercent = 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 $maximumResolutionReductionPercent to value which satisfy origin aspect ratio
|
|
||||||
if($maximumResolutionReductionPercent < $resolutionReductionPercent)
|
|
||||||
$resolutionReductionPercent = $maximumResolutionReductionPercent;
|
|
||||||
|
|
||||||
$newWidth = round($width - ($width * $resolutionReductionPercent) / 100);
|
|
||||||
$newHeight = round($height - ($height * $resolutionReductionPercent) / 100);
|
|
||||||
|
|
||||||
$thumb = imagecreatetruecolor($newWidth, $newHeight);
|
|
||||||
imagecopyresized($thumb, $im, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
|
||||||
|
|
||||||
return new CompressedImage($quality, $this->imageType,$thumb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initalize lib from provided image file path
|
* Initalize lib from provided image file path
|
||||||
* @param string $urlImageResource image resource path. Can be local file or internet URL
|
* @param string $urlImageResource image resource path. Can be local file or internet URL
|
||||||
|
* @param DriverInterface|null $driver
|
||||||
* @return SimpleImageCompressor
|
* @return SimpleImageCompressor
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function load(string $urlImageResource): SimpleImageCompressor
|
public static function load(string $urlImageResource, ?DriverInterface $driver = null): SimpleImageCompressor
|
||||||
{
|
{
|
||||||
$compressorObject = new SimpleImageCompressor($urlImageResource);
|
$compressorObject = new SimpleImageCompressor($urlImageResource, $driver);
|
||||||
$compressorObject->readImageToString();
|
$compressorObject->driver->load($urlImageResource);
|
||||||
$compressorObject->loadImageType();
|
$compressorObject->loadImageType($compressorObject->driver->getImageBinary());
|
||||||
|
|
||||||
if(!str_contains(self::ALLOWED_IMAGE_FORMAT, $compressorObject->getImageType())
|
if(!str_contains(self::ALLOWED_IMAGE_FORMAT, $compressorObject->getImageType())
|
||||||
|| $compressorObject->getImageType() === "")
|
|| $compressorObject->getImageType() === "")
|
||||||
@@ -150,4 +170,4 @@ class SimpleImageCompressor
|
|||||||
|
|
||||||
return $compressorObject;
|
return $compressorObject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace geckon01\SimpleImageCompressor\Drivers;
|
||||||
|
|
||||||
|
use geckon01\SimpleImageCompressor\CompressedImage;
|
||||||
|
use geckon01\SimpleImageCompressor\SimpleImageCompressor;
|
||||||
|
|
||||||
|
interface DriverInterface
|
||||||
|
{
|
||||||
|
function resize(int $reductionPercent, int $quality, int $approxMinimumWidth, int $approxMinimumHeight, string $imageType): CompressedImage;
|
||||||
|
function load(string $path): DriverInterface;
|
||||||
|
function getImageBinary(): string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
|
||||||
|
namespace geckon01\SimpleImageCompressor\Drivers;
|
||||||
|
|
||||||
|
|
||||||
|
use geckon01\SimpleImageCompressor\CompressedImage;
|
||||||
|
|
||||||
|
class GdDriver implements DriverInterface
|
||||||
|
{
|
||||||
|
private string $imageData;
|
||||||
|
|
||||||
|
function resize(int $reductionPercent, int $quality, int $approxMinimumWidth, int $approxMinimumHeight, string $imageType): 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 = $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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user