202 lines
6.4 KiB
PHP
202 lines
6.4 KiB
PHP
<?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;
|
|
}
|
|
|
|
}
|
|
} |