https://github.com/imsus/laravel-imgproxy
Laravel integration for ImgProxy
https://github.com/imsus/laravel-imgproxy
Last synced: 8 months ago
JSON representation
Laravel integration for ImgProxy
- Host: GitHub
- URL: https://github.com/imsus/laravel-imgproxy
- Owner: imsus
- License: mit
- Created: 2024-08-27T16:40:55.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2025-01-27T01:17:58.000Z (over 1 year ago)
- Last Synced: 2025-01-27T02:23:49.942Z (over 1 year ago)
- Language: PHP
- Homepage:
- Size: 45.9 KB
- Stars: 0
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE.md
Awesome Lists containing this project
README
# Laravel integration for ImgProxy
[](https://packagist.org/packages/imsus/laravel-imgproxy)
[](https://github.com/imsus/laravel-imgproxy/actions?query=workflow%3Arun-tests+branch%3Amain)
[](https://github.com/imsus/laravel-imgproxy/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain)
[](https://packagist.org/packages/imsus/laravel-imgproxy)
A comprehensive Laravel package for [ImgProxy](https://imgproxy.net/) integration. Generate optimized, signed image URLs with fluent API including resizing, quality control, visual effects, and advanced processing options.
## Features
- ๐ **Fluent API** - Clean, chainable method syntax
- ๐ **Secure URLs** - HMAC-SHA256 signed URLs with hex key/salt validation
- ๐จ **Visual Effects** - Blur, sharpen, brightness, contrast, saturation adjustments
- โก **Quality Control** - Fine-tune compression for JPEG, WebP, AVIF formats
- ๐ **Flexible Resizing** - Multiple resize modes with DPR support
- ๐ง **Laravel Integration** - Service provider, facade, and helper function
- โ
**Type Safe** - PHP 8.2+ enums and comprehensive validation
- ๐งช **Well Tested** - 39+ tests with workbench integration & visual testing
## Installation
You can install the package via composer:
```bash
composer require imsus/laravel-imgproxy
```
You can publish the config file with:
```bash
php artisan vendor:publish --tag="imgproxy-config"
```
This is the contents of the published config file:
```php
return [
'endpoint' => env('IMGPROXY_ENDPOINT', 'http://localhost:8080'),
'key' => env('IMGPROXY_KEY'),
'salt' => env('IMGPROXY_SALT'),
'default_source_url_mode' => env('IMGPROXY_DEFAULT_SOURCE_URL_MODE', 'encoded'),
'default_output_extension' => env('IMGPROXY_DEFAULT_OUTPUT_EXTENSION', 'jpeg'),
];
```
## Configuration
You can configure the package by updating the values in your `.env` file:
```dotenv
IMGPROXY_ENDPOINT=http://localhost:8080
IMGPROXY_KEY=your_hex_key_here
IMGPROXY_SALT=your_hex_salt_here
IMGPROXY_DEFAULT_SOURCE_URL_MODE=encoded
IMGPROXY_DEFAULT_OUTPUT_EXTENSION=jpeg
```
> [!NOTE]
> The `key` and `salt` are required only if you want to generate signed URLs. If you don't want to generate signed URLs, you can leave them empty.
> [!CAUTION]
> The `key` and `salt` should be in hex-encoded format. Generate them using: `openssl rand -hex 32`
### Configuration Options
| Option | Description | Default | Options |
| -------------------------- | ------------------------- | ----------------------- | ----------------------------------- |
| `endpoint` | ImgProxy server URL | `http://localhost:8080` | Any valid URL |
| `key` | Hex-encoded signing key | `null` | 64-char hex string |
| `salt` | Hex-encoded signing salt | `null` | 64-char hex string |
| `default_source_url_mode` | How to encode source URLs | `encoded` | `encoded`, `plain` |
| `default_output_extension` | Default output format | `jpeg` | `jpeg`, `png`, `webp`, `avif`, etc. |
## Usage
### Basic Usage
```php
use Imsus\ImgProxy\Facades\ImgProxy;
use Imsus\ImgProxy\Enums\OutputExtension;
use Imsus\ImgProxy\Enums\ResizeType;
// Generate URL using Facade
$url = ImgProxy::url('https://example.com/image.jpg')
->setWidth(300)
->setHeight(200)
->build();
// Generate URL using helper function
$url = imgproxy('https://example.com/image.jpg')
->setWidth(300)
->setHeight(200)
->build();
```
### Resizing & Formatting
```php
$url = imgproxy('https://example.com/image.jpg')
->setWidth(400)
->setHeight(300)
->setResizeType(ResizeType::FILL)
->setExtension(OutputExtension::WEBP)
->setDpr(2) // High DPI displays
->build();
```
### Quality Control
```php
// Optimize for different use cases
$thumbnail = imgproxy($image)
->setWidth(150)
->setHeight(150)
->setQuality(70) // Lower quality for thumbnails
->build();
$hero = imgproxy($image)
->setWidth(1200)
->setHeight(600)
->setQuality(90) // Higher quality for hero images
->build();
```
### Visual Effects
```php
$url = imgproxy('https://example.com/photo.jpg')
->setWidth(500)
->setHeight(300)
->setBlur(2.0) // Blur effect
->setSharpen(1.5) // Sharpen details
->setBrightness(20) // Increase brightness
->setContrast(1.2) // Enhance contrast
->setSaturation(1.1) // Boost saturation
->build();
```
### Advanced Processing
```php
use Imsus\ImgProxy\Enums\SourceUrlMode;
// Plain URL mode for debugging
$url = imgproxy('https://example.com/image.jpg')
->setMode(SourceUrlMode::PLAIN)
->setWidth(300)
->setHeight(200)
->build();
// Custom processing options
$url = imgproxy('https://example.com/image.jpg')
->setProcessing('rs:fill:400:300:1/rt:fit/q:85/bl:2.0')
->build();
```
### Method Chaining Examples
```php
// Complete image optimization pipeline
$optimizedUrl = imgproxy($originalImage)
->setWidth(800)
->setHeight(600)
->setResizeType(ResizeType::FILL)
->setExtension(OutputExtension::WEBP)
->setQuality(85)
->setSharpen(1.0)
->setDpr(2)
->build();
// Portrait enhancement
$portraitUrl = imgproxy($portrait)
->setWidth(400)
->setHeight(600)
->setResizeType(ResizeType::FILL)
->setBrightness(10)
->setContrast(1.1)
->setSaturation(1.05)
->setQuality(90)
->build();
```
## API Reference
### Available Methods
| Method | Parameters | Description |
| ------------------------------------ | ----------------- | ------------------------------- |
| `url(string $url)` | Image URL | Set the source image URL |
| `setWidth(int $width)` | Width in pixels | Set image width |
| `setHeight(int $height)` | Height in pixels | Set image height |
| `setResizeType(ResizeType $type)` | Resize mode | Set how image should be resized |
| `setExtension(OutputExtension $ext)` | Output format | Set output image format |
| `setDpr(int $dpr)` | 1-8 | Set device pixel ratio |
| `setQuality(int $quality)` | 0-100 | Set compression quality |
| `setBlur(float $sigma)` | โฅ0.0 | Apply blur effect |
| `setSharpen(float $sigma)` | โฅ0.0 | Apply sharpen effect |
| `setBrightness(int $brightness)` | -255 to 255 | Adjust brightness |
| `setContrast(float $contrast)` | โฅ0.0 | Adjust contrast |
| `setSaturation(float $saturation)` | โฅ0.0 | Adjust saturation |
| `setMode(SourceUrlMode $mode)` | `encoded`/`plain` | Set URL encoding mode |
| `setProcessing(string $options)` | Processing string | Custom processing options |
| `build()` | - | Generate final URL |
### Enums
#### ResizeType
- `ResizeType::FIT` - Resize keeping aspect ratio to fit dimensions
- `ResizeType::FILL` - Resize keeping aspect ratio to fill dimensions (crops overflow)
- `ResizeType::FILL_DOWN` - Same as fill, but maintains requested aspect ratio for smaller images
- `ResizeType::FORCE` - Resize without keeping aspect ratio
- `ResizeType::AUTO` - Automatically choose between fit/fill based on orientation
#### OutputExtension
- `OutputExtension::JPEG` - JPEG format
- `OutputExtension::PNG` - PNG format
- `OutputExtension::WEBP` - WebP format
- `OutputExtension::AVIF` - AVIF format
- `OutputExtension::GIF` - GIF format
- `OutputExtension::ICO` - ICO format
- `OutputExtension::SVG` - SVG format
- `OutputExtension::HEIC` - HEIC format
- `OutputExtension::BMP` - BMP format
- `OutputExtension::TIFF` - TIFF format
#### SourceUrlMode
- `SourceUrlMode::ENCODED` - Base64 encode source URL (default)
- `SourceUrlMode::PLAIN` - Use plain text URL
## Error Handling
The package includes comprehensive validation and will throw `InvalidArgumentException` for invalid parameters:
```php
try {
$url = imgproxy('invalid-url')
->setQuality(150) // Invalid: > 100
->build();
} catch (InvalidArgumentException $e) {
// Handle validation error
echo $e->getMessage(); // "Quality must be between 0 and 100"
}
```
For invalid URLs, the package gracefully returns the original URL instead of throwing an exception.
## Troubleshooting
### Common Issues
**Problem**: Getting "insecure" URLs instead of signed URLs
```
http://localhost:8080/insecure/width:300/height:200/...
```
**Solution**: Ensure `IMGPROXY_KEY` and `IMGPROXY_SALT` are set in your `.env` file with valid hex values.
**Problem**: Invalid hex key/salt errors
```
InvalidArgumentException: The key must be a hex-encoded string.
```
**Solution**: Generate proper hex keys:
```bash
# Generate 32-byte hex key and salt
openssl rand -hex 32
```
**Problem**: Images not loading/404 errors
**Solutions**:
- Verify ImgProxy server is running at the configured endpoint
- Check source image URLs are accessible
- Ensure ImgProxy server can reach source URLs (firewall/network issues)
**Problem**: Poor image quality
**Solutions**:
- Increase quality setting: `->setQuality(90)`
- Use appropriate output format: `->setExtension(OutputExtension::WEBP)`
- Avoid excessive sharpening: `->setSharpen(1.0)` instead of higher values
### Debug Mode
Enable plain URL mode for debugging:
```php
$debugUrl = imgproxy('https://example.com/image.jpg')
->setMode(SourceUrlMode::PLAIN)
->setWidth(300)
->build();
echo $debugUrl;
// Output: http://localhost:8080/signature/width:300/plain/https://example.com/image.jpg@jpg
```
## Advanced Usage & Patterns
### Performance Optimization
Choose optimal quality settings based on image use case:
```php
// Thumbnails - prioritize small file size
$thumbnail = imgproxy($image)
->setWidth(150)
->setHeight(150)
->setQuality(60)
->setExtension(OutputExtension::WEBP)
->build();
// Hero images - balance quality and size
$hero = imgproxy($image)
->setWidth(1920)
->setHeight(1080)
->setQuality(85)
->setExtension(OutputExtension::WEBP)
->build();
// Product images - prioritize quality
$product = imgproxy($image)
->setWidth(800)
->setHeight(600)
->setQuality(95)
->setSharpen(0.5)
->build();
```
### Format Selection Strategy
```php
// Modern browsers - use AVIF for best compression
$avifUrl = imgproxy($image)
->setExtension(OutputExtension::AVIF)
->setQuality(75) // AVIF allows lower quality with better visual results
->build();
// Fallback for older browsers - use WebP
$webpUrl = imgproxy($image)
->setExtension(OutputExtension::WEBP)
->setQuality(85)
->build();
// Universal fallback - use JPEG
$jpegUrl = imgproxy($image)
->setExtension(OutputExtension::JPEG)
->setQuality(90)
->build();
```
### Laravel Integration
#### Blade Directives
Create custom Blade directives for common use cases:
```php
// In AppServiceProvider::boot()
use Illuminate\Support\Facades\Blade;
Blade::directive('imgproxy', function ($expression) {
return "build(); ?>";
});
Blade::directive('avatar', function ($expression) {
return "setWidth(150)->setHeight(150)->setResizeType(\Imsus\ImgProxy\Enums\ResizeType::FILL)->build(); ?>";
});
```
```blade
{{-- Usage in Blade templates --}}
```
#### Eloquent Accessors
Add image processing to Eloquent models:
```php
class User extends Model
{
public function getAvatarUrlAttribute(): string
{
if (!$this->avatar) {
return '/default-avatar.png';
}
return imgproxy($this->avatar)
->setWidth(150)
->setHeight(150)
->setResizeType(ResizeType::FILL)
->setExtension(OutputExtension::WEBP)
->setQuality(85)
->build();
}
}
```
#### API Resources
Use in API resources for consistent image URLs:
```php
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'avatar' => [
'small' => imgproxy($this->avatar)->setWidth(50)->setHeight(50)->build(),
'medium' => imgproxy($this->avatar)->setWidth(150)->setHeight(150)->build(),
'large' => imgproxy($this->avatar)->setWidth(300)->setHeight(300)->build(),
],
];
}
}
```
### Common Patterns
#### Avatar Processing
```php
class UserAvatar
{
public static function generate(string $imageUrl, int $size = 150): string
{
return imgproxy($imageUrl)
->setWidth($size)
->setHeight($size)
->setResizeType(ResizeType::FILL)
->setExtension(OutputExtension::WEBP)
->setQuality(85)
->setSharpen(0.5)
->build();
}
}
// Usage
$avatarUrl = UserAvatar::generate($user->profile_image, 200);
```
#### Responsive Images
Generate multiple image sizes for responsive images:
```php
class ResponsiveImage
{
public static function generateSrcset(string $imageUrl, array $sizes): array
{
$srcset = [];
foreach ($sizes as $width) {
$url = imgproxy($imageUrl)
->setWidth($width)
->setHeight(intval($width * 0.75)) // 4:3 aspect ratio
->setResizeType(ResizeType::FILL)
->setExtension(OutputExtension::WEBP)
->setQuality(85)
->build();
$srcset[] = "{$url} {$width}w";
}
return $srcset;
}
}
// Usage
$sizes = [400, 800, 1200, 1600];
$srcset = ResponsiveImage::generateSrcset($image, $sizes);
$srcsetString = implode(', ', $srcset);
```
```blade
```
### Image Processing Recipes
#### Photo Enhancement
```php
// Portrait enhancement
$enhancedPortrait = imgproxy($portrait)
->setWidth(600)
->setHeight(800)
->setResizeType(ResizeType::FILL)
->setBrightness(8) // Slightly brighter
->setContrast(1.1) // Enhanced contrast
->setSaturation(1.05) // Subtle saturation boost
->setSharpen(0.8) // Gentle sharpening
->setQuality(92)
->build();
// High contrast black and white
$highContrastBW = imgproxy($image)
->setWidth(800)
->setHeight(600)
->setSaturation(0) // Remove all color
->setContrast(1.5) // High contrast
->setBrightness(-5) // Slightly darker
->setSharpen(2.0) // Sharp details
->build();
```
#### E-commerce Optimization
```php
// Clean product photos
$productClean = imgproxy($product)
->setWidth(800)
->setHeight(800)
->setResizeType(ResizeType::FIT)
->setBrightness(15) // Bright and clean
->setContrast(1.1) // Good contrast
->setSharpen(1.5) // Sharp product details
->setQuality(95) // High quality for products
->setExtension(OutputExtension::WEBP)
->build();
```
### Security Best Practices
#### Environment Configuration
```bash
# Use strong, unique keys
IMGPROXY_KEY=$(openssl rand -hex 32)
IMGPROXY_SALT=$(openssl rand -hex 32)
# Use HTTPS in production
IMGPROXY_ENDPOINT=https://imgproxy.yoursite.com
# Consider using encoded mode for security
IMGPROXY_DEFAULT_SOURCE_URL_MODE=encoded
```
#### URL Validation
Always validate source URLs before processing:
```php
class ImageProcessor
{
private array $allowedDomains = [
'your-cdn.com',
'storage.googleapis.com',
's3.amazonaws.com',
];
public function processImage(string $imageUrl): string
{
$parsedUrl = parse_url($imageUrl);
if (!in_array($parsedUrl['host'], $this->allowedDomains)) {
throw new InvalidArgumentException('Image domain not allowed');
}
return imgproxy($imageUrl)
->setWidth(800)
->setHeight(600)
->setQuality(85)
->build();
}
}
```
## Testing
### Unit & Integration Tests
```bash
# Run all tests
composer test
# Run only unit tests
composer test --filter=ImgProxyTest
# Run only integration tests
composer test --filter=WorkbenchIntegrationTest
# Run with coverage
composer test-coverage
```
### Interactive Testing with Workbench
The package includes a comprehensive workbench environment for interactive testing:
```bash
# Build and start the workbench server
composer start
# Or build separately and serve
composer build
php vendor/bin/testbench serve
```
Once the server is running (typically at `http://localhost:8000`), you can access:
#### API Test Endpoints
- **Test Overview**: `http://localhost:8000/imgproxy-test/` - JSON overview of all available tests
- **Basic Test**: `http://localhost:8000/imgproxy-test/basic` - Basic URL generation testing
- **Effects Test**: `http://localhost:8000/imgproxy-test/effects` - Quality and visual effects testing
- **Formats Test**: `http://localhost:8000/imgproxy-test/formats` - Format conversion (JPEG, PNG, WebP, AVIF)
- **Resize Test**: `http://localhost:8000/imgproxy-test/resize` - Different resize types comparison
- **Facade vs Helper**: `http://localhost:8000/imgproxy-test/facade-vs-helper` - Compare facade and helper output
- **Config Test**: `http://localhost:8000/imgproxy-test/config` - Configuration validation
- **Error Handling**: `http://localhost:8000/imgproxy-test/error-handling` - Error scenarios testing
- **Performance Test**: `http://localhost:8000/imgproxy-test/performance` - Performance benchmarks
#### Visual Testing
- **Visual Test Suite**: `http://localhost:8000/imgproxy-visual-test` - Complete browser-based visual testing
The visual test page includes:
- **Real Image Processing** - See actual ImgProxy results with sample images
- **Quality Comparison** - Side-by-side quality levels (30%, 70%, 95%)
- **Format Comparison** - Visual differences between JPEG, PNG, WebP, AVIF
- **Resize Types Demo** - Visual behavior of fit, fill, force, auto modes
- **Effects Showcase** - Blur, sharpen, saturation, brightness effects
- **Complex Processing** - Portrait enhancement and vintage effects
- **High DPI Examples** - Standard vs 2x DPI comparisons
### Test Coverage
The package includes **39 comprehensive tests** with **145 assertions** covering:
- โ
**Unit Tests** (26 tests) - Core functionality, validation, edge cases
- โ
**Integration Tests** (13 tests) - Laravel environment, HTTP endpoints, service provider registration
- โ
**Architecture Tests** (7 tests) - Code structure, security, conventions
- โ
**Visual Tests** - Browser-based real image processing validation
- โ
**Performance Tests** - URL generation speed benchmarks (>1000 URLs/second)
### Sample Test Responses
**Basic Test Response:**
```json
{
"original": "https://picsum.photos/800/600",
"processed": "http://localhost:8080/signed-url/width:400/height:300/...",
"test": "basic_url_generation"
}
```
**Performance Test Response:**
```json
{
"urls_generated": 100,
"duration_seconds": 0.0089,
"urls_per_second": 1123.6,
"test": "performance"
}
```
## Changelog
Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
## Security Vulnerabilities
Please review [our security policy](../../security/policy) on how to report security vulnerabilities.
## Credits
- [Imam Susanto](https://github.com/imsus)
- [All Contributors](../../contributors)
## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.