![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/soundstudiopro.com/private_html/utils/ |
<?php
/**
* Image Compression Utility
* Automatically compresses and optimizes uploaded images
*/
/**
* Compress and optimize an image file
*
* @param string $filepath Path to the image file
* @param array $options Compression options:
* - max_width: Maximum width (default: 1920)
* - max_height: Maximum height (default: 1920)
* - quality: JPEG quality 0-100 (default: 85)
* - convert_png_to_jpeg: Convert PNG to JPEG if no transparency (default: true)
* - max_file_size: Maximum file size in bytes (default: 500KB)
* @return array Result with 'success', 'original_size', 'new_size', 'saved_bytes', 'filepath'
*/
function compressImage($filepath, $options = []) {
// Default options
$defaults = [
'max_width' => 1920,
'max_height' => 1920,
'quality' => 85,
'convert_png_to_jpeg' => true,
'max_file_size' => 500 * 1024, // 500KB
];
$options = array_merge($defaults, $options);
// Check if GD is available
if (!extension_loaded('gd')) {
return [
'success' => false,
'error' => 'GD library not available'
];
}
// Check if file exists
if (!file_exists($filepath)) {
return [
'success' => false,
'error' => 'File not found'
];
}
$original_size = filesize($filepath);
$image_info = @getimagesize($filepath);
if (!$image_info) {
return [
'success' => false,
'error' => 'Invalid image file'
];
}
$original_width = $image_info[0];
$original_height = $image_info[1];
$mime_type = $image_info['mime'];
// If image is already small enough and file size is acceptable, skip compression
if ($original_width <= $options['max_width'] &&
$original_height <= $options['max_height'] &&
$original_size <= $options['max_file_size']) {
return [
'success' => true,
'original_size' => $original_size,
'new_size' => $original_size,
'saved_bytes' => 0,
'filepath' => $filepath,
'skipped' => true,
'message' => 'Image already optimized'
];
}
// Load image based on type
$source_image = null;
switch ($mime_type) {
case 'image/jpeg':
case 'image/jpg':
$source_image = @imagecreatefromjpeg($filepath);
break;
case 'image/png':
$source_image = @imagecreatefrompng($filepath);
break;
case 'image/gif':
$source_image = @imagecreatefromgif($filepath);
break;
case 'image/webp':
if (function_exists('imagecreatefromwebp')) {
$source_image = @imagecreatefromwebp($filepath);
}
break;
default:
return [
'success' => false,
'error' => 'Unsupported image type: ' . $mime_type
];
}
if (!$source_image) {
return [
'success' => false,
'error' => 'Failed to load image'
];
}
// Calculate new dimensions maintaining aspect ratio
$ratio = min($options['max_width'] / $original_width, $options['max_height'] / $original_height);
$ratio = min($ratio, 1.0); // Don't upscale
$new_width = (int)($original_width * $ratio);
$new_height = (int)($original_height * $ratio);
// Create new image
$new_image = imagecreatetruecolor($new_width, $new_height);
// Preserve transparency for PNG
$has_transparency = false;
if ($mime_type === 'image/png' || $mime_type === 'image/gif') {
imagealphablending($new_image, false);
imagesavealpha($new_image, true);
$transparent = imagecolorallocatealpha($new_image, 0, 0, 0, 127);
imagefill($new_image, 0, 0, $transparent);
imagealphablending($new_image, true);
// Check if PNG has transparency
if ($mime_type === 'image/png') {
$has_transparency = imagecolortransparent($source_image) >= 0 ||
(function_exists('imageistruecolor') && !imageistruecolor($source_image));
}
}
// Resize image
imagecopyresampled($new_image, $source_image, 0, 0, 0, 0, $new_width, $new_height, $original_width, $original_height);
// Determine output format
$output_format = 'jpeg';
$output_path = $filepath;
// Convert PNG to JPEG if no transparency and option is enabled
if ($mime_type === 'image/png' && $options['convert_png_to_jpeg'] && !$has_transparency) {
$output_path = preg_replace('/\.png$/i', '.jpg', $filepath);
$output_format = 'jpeg';
} elseif ($mime_type === 'image/png') {
$output_format = 'png';
} elseif ($mime_type === 'image/gif') {
// Convert GIF to JPEG for better compression
$output_path = preg_replace('/\.gif$/i', '.jpg', $filepath);
$output_format = 'jpeg';
}
// Save compressed image
$saved = false;
switch ($output_format) {
case 'jpeg':
$saved = @imagejpeg($new_image, $output_path, $options['quality']);
break;
case 'png':
// PNG compression level 6 (0-9, 6 is good balance)
$saved = @imagepng($new_image, $output_path, 6);
break;
}
// Clean up
imagedestroy($source_image);
imagedestroy($new_image);
if (!$saved) {
return [
'success' => false,
'error' => 'Failed to save compressed image'
];
}
// If file path changed (PNG->JPEG conversion), delete original
if ($output_path !== $filepath && file_exists($filepath)) {
@unlink($filepath);
}
$new_size = filesize($output_path);
$saved_bytes = $original_size - $new_size;
return [
'success' => true,
'original_size' => $original_size,
'new_size' => $new_size,
'saved_bytes' => $saved_bytes,
'filepath' => $output_path,
'original_dimensions' => [$original_width, $original_height],
'new_dimensions' => [$new_width, $new_height],
'format_changed' => ($output_path !== $filepath),
'message' => sprintf('Compressed from %s to %s (saved %s)',
formatBytes($original_size),
formatBytes($new_size),
formatBytes($saved_bytes))
];
}
/**
* Format bytes to human readable format
*/
function formatBytes($bytes, $precision = 2) {
$units = ['B', 'KB', 'MB', 'GB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
/**
* Compress profile image with profile-specific settings
*/
function compressProfileImage($filepath) {
return compressImage($filepath, [
'max_width' => 800,
'max_height' => 800,
'quality' => 85,
'convert_png_to_jpeg' => true,
'max_file_size' => 200 * 1024, // 200KB max for profile images
]);
}
/**
* Compress track cover image with track cover-specific settings
*/
function compressTrackCover($filepath) {
return compressImage($filepath, [
'max_width' => 1920,
'max_height' => 1920,
'quality' => 85,
'convert_png_to_jpeg' => true,
'max_file_size' => 500 * 1024, // 500KB max for track covers
]);
}