v1.0 Initial commit of project
This commit is contained in:
202
pub/api/classes/imageProcessor.php
Normal file
202
pub/api/classes/imageProcessor.php
Normal file
@@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace api\classes;
|
||||
class imageProcessor
|
||||
{
|
||||
public $postedFile = null;
|
||||
private $imageTmpPath;
|
||||
private $imageInfo;
|
||||
|
||||
public $imageRestrictions = [
|
||||
'min_width' => 100,
|
||||
'max_width' => 600,
|
||||
'min_height' => 100,
|
||||
'max_height' => 600,
|
||||
'square' => false,
|
||||
'allowed_types' => ['image/png', 'image/jpeg', 'image/webp'],
|
||||
'max_size_kb' => 2048, // 2MB
|
||||
'transparent' => false
|
||||
];
|
||||
|
||||
private $finalImage = null;
|
||||
|
||||
public function __construct($imageName)
|
||||
{
|
||||
if (isset($_FILES[$imageName]) && $_FILES[$imageName]['error'] === UPLOAD_ERR_OK) {
|
||||
$this->postedFile = $_FILES[$imageName];
|
||||
$this->imageTmpPath = $this->postedFile['tmp_name'];
|
||||
$this->imageInfo = getimagesize($this->imageTmpPath);
|
||||
} elseif (isset($_POST['image_base64'])) {
|
||||
$base64 = $_POST['image_base64'];
|
||||
|
||||
if (preg_match('/^data:(image\/\w+);base64,/', $base64, $matches)) {
|
||||
$mimeType = $matches[1];
|
||||
$base64 = substr($base64, strpos($base64, ',') + 1);
|
||||
} else {
|
||||
throw new Exception('Invalid image data.');
|
||||
}
|
||||
|
||||
$imageData = base64_decode($base64);
|
||||
if ($imageData === false) {
|
||||
throw new Exception('Invalid base64 image data.');
|
||||
}
|
||||
|
||||
# Create image directly from string (no file)
|
||||
$srcImage = imagecreatefromstring($imageData);
|
||||
if (!$srcImage) {
|
||||
throw new Exception('Failed to create image from string.');
|
||||
}
|
||||
|
||||
# Now you can get dimensions directly
|
||||
$width = imagesx($srcImage);
|
||||
$height = imagesy($srcImage);
|
||||
|
||||
# Store $srcImage in a class property, continue processing in-memory
|
||||
$this->imageResource = $srcImage;
|
||||
$this->imageInfo = [
|
||||
'mime' => $mimeType,
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'size' => strlen($imageData)
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
public function validateAndProcess()
|
||||
{
|
||||
if (!$this->postedFile) {
|
||||
return true;
|
||||
}
|
||||
$width = $this->imageInfo[0];
|
||||
$height = $this->imageInfo[1];
|
||||
$mime = $this->imageInfo['mime'];
|
||||
$fileSizeKB = filesize($this->imageTmpPath) / 1024;
|
||||
|
||||
if (!in_array($mime, $this->imageRestrictions['allowed_types'])) {
|
||||
throw new Exception("Invalid image type: $mime");
|
||||
}
|
||||
|
||||
if ($fileSizeKB > $this->imageRestrictions['max_size_kb']) {
|
||||
throw new Exception("Image exceeds max file size.");
|
||||
}
|
||||
|
||||
# Resize to fit within min/max bounds
|
||||
$resizedImage = $this->resizeToFitRestrictions($mime, $width, $height);
|
||||
|
||||
# Optionally square it
|
||||
if ($this->imageRestrictions['square']) {
|
||||
$resizedImage = $this->makeImageSquare($resizedImage, $mime);
|
||||
}
|
||||
|
||||
ob_start();
|
||||
switch ($mime) {
|
||||
case 'image/jpeg':
|
||||
imagejpeg($resizedImage);
|
||||
break;
|
||||
case 'image/png':
|
||||
imagepng($resizedImage);
|
||||
break;
|
||||
case 'image/webp':
|
||||
imagewebp($resizedImage);
|
||||
break;
|
||||
}
|
||||
$this->finalImage = ob_get_clean();
|
||||
|
||||
imagedestroy($resizedImage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function mimeSupportsTransparency($mime)
|
||||
{
|
||||
return in_array($mime, ['image/png', 'image/webp']);
|
||||
}
|
||||
|
||||
private function setTransparentCanvas($image, $width, $height)
|
||||
{
|
||||
// Enable alpha blending and preserve alpha channel
|
||||
imagealphablending($image, false);
|
||||
imagesavealpha($image, true);
|
||||
|
||||
// Fill the image with a fully transparent color
|
||||
$transparent = imagecolorallocatealpha($image, 0, 0, 0, 127);
|
||||
imagefilledrectangle($image, 0, 0, $width, $height, $transparent);
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
private function resizeToFitRestrictions($mime, $width, $height)
|
||||
{
|
||||
$minW = $this->imageRestrictions['min_width'];
|
||||
$maxW = $this->imageRestrictions['max_width'];
|
||||
$minH = $this->imageRestrictions['min_height'];
|
||||
$maxH = $this->imageRestrictions['max_height'];
|
||||
|
||||
$srcImage = match ($mime) {
|
||||
'image/jpeg' => imagecreatefromjpeg($this->imageTmpPath),
|
||||
'image/png' => imagecreatefrompng($this->imageTmpPath),
|
||||
'image/webp' => imagecreatefromwebp($this->imageTmpPath),
|
||||
default => throw new Exception("Unsupported image type.")
|
||||
};
|
||||
|
||||
# Determine new size
|
||||
$newWidth = $width;
|
||||
$newHeight = $height;
|
||||
|
||||
if ($width < $minW || $width > $maxW || $height < $minH || $height > $maxH) {
|
||||
# Calculate scale factor based on limits
|
||||
$widthScale = ($width < $minW) ? $minW / $width : ($width > $maxW ? $maxW / $width : 1);
|
||||
$heightScale = ($height < $minH) ? $minH / $height : ($height > $maxH ? $maxH / $height : 1);
|
||||
|
||||
# Use the smallest scale to ensure both dimensions fit
|
||||
$scale = min($widthScale, $heightScale);
|
||||
|
||||
$newWidth = round($width * $scale);
|
||||
$newHeight = round($height * $scale);
|
||||
}
|
||||
|
||||
$resizedImage = imagecreatetruecolor($newWidth, $newHeight);
|
||||
|
||||
# keep transparent
|
||||
if ($this->mimeSupportsTransparency($mime)) {
|
||||
$this->setTransparentCanvas($resizedImage, $newWidth, $newHeight);
|
||||
}
|
||||
|
||||
imagecopyresampled($resizedImage, $srcImage, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);
|
||||
imagedestroy($srcImage);
|
||||
return $resizedImage;
|
||||
}
|
||||
|
||||
private function makeImageSquare($srcImage, $mime)
|
||||
{
|
||||
$width = imagesx($srcImage);
|
||||
$height = imagesy($srcImage);
|
||||
|
||||
$size = min($width, $height);
|
||||
$x = ($width - $size) / 2;
|
||||
$y = ($height - $size) / 2;
|
||||
|
||||
$squareImage = imagecreatetruecolor($size, $size);
|
||||
|
||||
# keep transparent
|
||||
if ($this->mimeSupportsTransparency($mime)) {
|
||||
$this->setTransparentCanvas($squareImage, $size, $size);
|
||||
}
|
||||
|
||||
imagecopyresampled($squareImage, $srcImage, 0, 0, $x, $y, $size, $size, $size, $size);
|
||||
imagedestroy($srcImage);
|
||||
|
||||
return $squareImage;
|
||||
}
|
||||
|
||||
public function returnBase64image()
|
||||
{
|
||||
if ($this->finalImage) {
|
||||
return base64_encode($this->finalImage);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user