Cookbook
Image Processing Examples
Comprehensive examples of image processing with the glueful/media extension
This document provides comprehensive examples of image processing in Glueful, powered by the
glueful/media extension and Intervention Image v4.
Basic Operations
Simple Resize
// Using helper function (recommended)
image($context, '/path/to/photo.jpg')
->resize(800, 600)
->save('/path/to/resized.jpg');
// Using service injection
$processor = app($context, ImageProcessorInterface::class);
$result = $processor::make('/path/to/photo.jpg')
->resize(800, 600)
->save('/path/to/resized.jpg');
Maintain Aspect Ratio
// Resize by width (height auto-calculated)
image($context, '/path/to/photo.jpg')
->resize(800, null) // maintain aspect ratio
->save('/path/to/resized.jpg');
// Or resize by height (width auto-calculated)
image($context, '/path/to/photo.jpg')
->resize(null, 600) // maintain aspect ratio
->save('/path/to/resized.jpg');
Quality Control
// Set JPEG quality (1-100)
image($context, '/path/to/photo.jpg')
->resize(800, 600)
->quality(85)
->save('/path/to/output.jpg');
// Format conversion with quality
image($context, '/path/to/photo.png')
->format('webp')
->quality(80)
->save('/path/to/output.webp');
Advanced Operations
Cropping and Fitting
// Crop to exact dimensions from center
image($context, '/path/to/photo.jpg')
->crop(400, 300, 100, 50) // width, height, x, y
->save('/path/to/cropped.jpg');
// Fit to exact dimensions (covers area and may crop edges)
image($context, '/path/to/photo.jpg')
->fit(800, 600)
->save('/path/to/fitted.jpg');
Watermarking
// Add watermark to bottom-right
image($context, '/path/to/photo.jpg')
->watermark('/path/to/logo.png', 'bottom-right', 50) // 50% opacity
->save('/path/to/watermarked.jpg');
// Different watermark position
image($context, '/path/to/photo.jpg')
->watermark('/path/to/logo.png', 'top-left', 75)
->save('/path/to/watermarked.jpg');
Custom Modifications
// Apply custom Intervention operations via modify()
image($context, '/path/to/photo.jpg')
->modify(function ($img) {
// Example: adjust brightness/contrast using Intervention methods
// $img->brightness(20)->contrast(15);
})
->save('/path/to/adjusted.jpg');
Caching Examples
Basic Caching
// Cache processed image for 24 hours
$imageData = image($context, '/path/to/photo.jpg')
->resize(800, 600)
->quality(85)
->cached('photo-800x600', 86400)
->getImageData();
Cache Key Generation
// Automatic cache key based on operations
$processor = image($context, '/path/to/photo.jpg')
->resize(800, 600)
->quality(85)
->cached(); // Auto-generates cache key
// Custom cache key with TTL
$processor = image($context, '/path/to/photo.jpg')
->resize(800, 600)
->cached('custom-thumbnail-' . $userId, 3600);
Retrieve From Cache (and Serve)
use Glueful\Cache\CacheStore;
// Resolve cache store
/** @var CacheStore<mixed> $cache */
$cache = app($context, 'cache.store');
// Compose full cache key used by ImageProcessor::cached()
$prefix = (string) (config($context, 'image.cache.prefix', 'image_'));
$key = $prefix . 'photo-800x600';
// Try to serve from cache first
if ($cached = $cache->get($key)) {
header('Content-Type: ' . $cached['mime_type']);
echo $cached['image_data'];
return; // done
}
// Cache miss: process and cache
$imageData = image($context, '/path/to/photo.jpg')
->resize(800, 600)
->quality(85)
->cached('photo-800x600', 86400)
->getImageData();
header('Content-Type: image/jpeg');
echo $imageData;
Invalidate Cached Variant
$prefix = (string) (config($context, 'image.cache.prefix', 'image_'));
$key = $prefix . 'photo-800x600';
app($context, 'cache.store')->delete($key);
// Note: cached() stores the processed result under a cache key; retrieval and // invalidation should be handled by your cache layer if needed.
Remote Image Processing
Basic Remote Processing
// Process remote image with security checks
try {
$result = image($context, 'https://example.com/photo.jpg')
->resize(800, 600)
->quality(85)
->cached('remote-photo-800x600')
->save('/path/to/local.jpg');
} catch (\Glueful\Exceptions\BusinessLogicException $e) {
// Handle validation/security/processing errors
echo "Image error: " . $e->getMessage();
}
Batch Processing
// Process multiple images efficiently
$urls = [
'https://example.com/photo1.jpg',
'https://example.com/photo2.jpg',
'https://example.com/photo3.jpg'
];
foreach ($urls as $index => $url) {
try {
image($context, $url)
->resize(400, 300)
->cached("batch-photo-{$index}")
->save("/path/to/batch_{$index}.jpg");
} catch (Exception $e) {
// Log error and continue
error_log("Failed to process {$url}: " . $e->getMessage());
}
}
Working with Uploads
Process File Uploads
// In controller handling file upload
public function uploadImage(Request $request): Response
{
$uploadedFile = $request->getUploadedFiles()['image'] ?? null;
if (!$uploadedFile) {
return Response::error('No image uploaded');
}
try {
// Process uploaded file (use fromUpload for UploadedFileInterface)
$processedData = app($context, ImageProcessorInterface::class)
::fromUpload($uploadedFile)
->resize(1200, 800)
->quality(85)
->format('webp')
->cached('upload-' . uniqid())
->getImageData();
// Save to storage
$filename = 'processed_' . time() . '.webp';
file_put_contents(storage_path($context, 'images/' . $filename), $processedData);
return Response::success(['filename' => $filename]);
} catch (Exception $e) {
return Response::error('Image processing failed: ' . $e->getMessage());
}
}
Generate Multiple Sizes
// Create thumbnail variants from upload
$uploadedFile = $request->getUploadedFiles()['image'];
$processor = app($context, ImageProcessorInterface::class)::fromUpload($uploadedFile);
$sizes = [
'thumbnail' => [150, 150],
'medium' => [400, 300],
'large' => [800, 600],
'original' => [1200, 900]
];
$results = [];
foreach ($sizes as $size => $dimensions) {
$processed = $processor->clone()
->fit($dimensions[0], $dimensions[1])
->quality(85)
->cached("upload-{$size}-" . uniqid())
->getImageData();
$filename = "{$size}_" . time() . '.jpg';
file_put_contents(storage_path($context, "images/{$filename}"), $processed);
$results[$size] = $filename;
}
Performance Optimization
Memory Efficient Processing
// Process large images efficiently
$processor = image($context, '/path/to/large-image.jpg');
// Check dimensions before processing
if ($processor->getWidth() > 4000 || $processor->getHeight() > 4000) {
// Resize very large images first
$processor->resize(2000, 1500);
}
// Continue with normal processing
$result = $processor
->resize(800, 600)
->quality(85)
->save('/path/to/output.jpg');
Streaming for Large Files
// Stream large processed images
public function serveProcessedImage(string $path): void
{
$processor = image($context, $path)
->resize(1200, 800)
->cached();
// Stream directly to output
$processor->stream([
'Content-Disposition' => 'inline; filename="processed.jpg"'
]);
}
Error Handling
Comprehensive Error Handling
try {
$result = image($context, '/path/to/photo.jpg')
->resize(800, 600)
->quality(85)
->save('/path/to/output.jpg');
} catch (\Glueful\Exceptions\BusinessLogicException $e) {
// Validation/security/processing errors (format, size, dimensions, etc.)
error_log("Image error: " . $e->getMessage());
} catch (Exception $e) {
// Generic errors
error_log("Unexpected error: " . $e->getMessage());
}
Configuration Examples
Environment Variables
# Production settings
IMAGE_DRIVER=imagick
IMAGE_MAX_WIDTH=2048
IMAGE_MAX_HEIGHT=2048
IMAGE_MAX_FILESIZE=10M
IMAGE_JPEG_QUALITY=85
IMAGE_WEBP_QUALITY=80
IMAGE_CACHE_ENABLED=true
IMAGE_CACHE_TTL=86400
IMAGE_VALIDATE_MIME=true
IMAGE_CHECK_INTEGRITY=true
IMAGE_DISABLE_EXTERNAL_URLS=false
IMAGE_ALLOWED_DOMAINS=example.com,cdn.example.com
Custom Configuration in Services
use Glueful\Extensions\Media\ImageProcessor;
// Custom image processor with specific settings
$processor = new ImageProcessor(
$imageManager,
$cache,
$security,
$logger,
[
'optimization' => [
'jpeg_quality' => 90,
'webp_quality' => 85,
],
'security' => [
'allowed_domains' => ['trusted-cdn.com'],
'validate_mime' => true,
],
'cache' => [
'enabled' => true,
'ttl' => 3600,
'prefix' => 'custom-images-',
]
]
);
Integration with Controllers
RESTful Image API
class ImageController extends BaseController
{
public function resize(Request $request): Response
{
$this->requirePermission('images.process');
$url = $request->get('url');
$width = (int) $request->get('width', 800);
$height = (int) $request->get('height', 600);
$quality = (int) $request->get('quality', 85);
try {
$imageData = image($context, $url)
->resize($width, $height)
->quality($quality)
->cached("resize-{$width}x{$height}-q{$quality}")
->getImageData();
return Response::success([
'processed' => true,
'size' => strlen($imageData),
'data' => base64_encode($imageData)
]);
} catch (Exception $e) {
return Response::error('Processing failed: ' . $e->getMessage());
}
}
}
This completes the comprehensive examples for image processing with the glueful/media extension.