Install the Bundle:
composer require chamber-orchestra/image-bundle
Add to config/bundles.php:
return [
// ...
ChamberOrchestra\ImageBundle\ImageBundle::class => ['all' => true],
];
Configure Basic Processing:
Edit config/packages/chamber_orchestra_image.yaml (auto-generated on first run):
chamber_orchestra_image:
cache_dir: '%kernel.project_dir%/var/cache/image'
processors:
- fit
- fill
post_processors:
- avifenc
binaries:
avifenc: '/usr/bin/avifenc'
cwebp: '/usr/bin/cwebp'
First Use Case: Resize an Image Use the Twig filter in a template:
<img src="{{ image_url('path/to/image.jpg', 'thumb') }}">
Define a filter in config/packages/chamber_orchestra_image.yaml:
filters:
thumb:
width: 200
height: 200
fit: 'cover'
Define Filters:
Configure filters in config/packages/chamber_orchestra_image.yaml under filters. Example:
filters:
avatar:
width: 100
height: 100
fit: 'crop'
crop: [50, 50, 100, 100] # [x1, y1, x2, y2]
webp_conversion:
post_processors: ['cwebp']
Generate Signed URLs:
Use the ImageUrlGenerator service in controllers:
use ChamberOrchestra\ImageBundle\Service\ImageUrlGenerator;
public function show(ImageUrlGenerator $urlGenerator, string $path, string $filter)
{
return new Response($urlGenerator->generate($path, $filter));
}
Async Processing with Messenger: Enable async processing in config:
chamber_orchestra_image:
async: true
Trigger async processing via ImageProcessor:
$processor = $this->container->get(ImageProcessor::class);
$processor->processAsync($sourcePath, $filterName, $destinationPath);
Twig Integration: Use built-in Twig filters:
{# Generate URL #}
{{ image_url('path/to/image.jpg', 'avatar') }}
{# Generate HTML img tag #}
{{ image_tag('path/to/image.jpg', 'avatar', { alt: 'User Avatar' }) }}
Cache Management: Clear cache for specific filters:
$cacheManager = $this->container->get(ImageCacheManager::class);
$cacheManager->clearFilter('avatar');
Or globally:
php bin/console cache:clear
Custom Processors:
Implement ProcessorInterface for custom logic (e.g., watermarking):
class WatermarkProcessor implements ProcessorInterface
{
public function getIndexName(): string { return 'watermark'; }
public function process(Imagine\Gd\Imagine $imagine, string $path): void
{
$watermark = $imagine->open('watermark.png');
$size = $imagine->size();
$imagine->paste($watermark, (int)($size->getWidth() * 0.8), (int)($size->getHeight() * 0.8));
}
}
Register in config/packages/chamber_orchestra_image.yaml:
processors:
- watermark
Binary Paths:
Use environment variables for binary paths (e.g., AVIFENC_PATH) and override in config:
binaries:
avifenc: '%env(AVIFENC_PATH)%'
Binary Dependencies:
avifenc, cwebp, MozJPEG, pngquant) are installed and paths are correct. Test with:
avifenc --version
post_processors: []
Cache Invalidation:
width) requires clearing the cache:
php bin/console chamber-orchestra:image:cache:clear
clearFilter() or clearAll() as needed.Async Processing Quirks:
async config is true and the Messenger transport (e.g., Doctrine, Redis) is configured.php bin/console messenger:consume async -vv
HMAC-Signed URLs:
ttl (time-to-live) in config is set too low. Default is 3600 (1 hour).IMAGE_SECRET env var).Image Source Paths:
public/ directory by default. Use absolute paths or configure a custom source_dir in config:
source_dir: '%kernel.project_dir%/uploads'
Log Processor Output:
Enable debug mode in config/packages/dev/chamber_orchestra_image.yaml:
debug: true
Logs will show processed paths and filter configurations.
Validate Filters:
Use the validate command to check filter configurations:
php bin/console chamber-orchestra:image:validate
Test Locally: Mock binaries for testing (e.g., symlink to dummy executables or use Docker containers with pre-installed tools).
Custom Post-Processors:
Extend AbstractPostProcessor for custom logic (e.g., adding metadata):
class CustomPostProcessor extends AbstractPostProcessor
{
protected function getBinary(): string { return '/usr/bin/custom-tool'; }
protected function getArguments(string $source, string $destination): array
{
return ['--metadata', $source, $destination];
}
}
Register in config:
post_processors:
- custom
Event Subscribers:
Listen to ImageProcessedEvent for post-processing actions:
use ChamberOrchestra\ImageBundle\Event\ImageProcessedEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(ImageProcessedEvent::class)]
public function onImageProcessed(ImageProcessedEvent $event)
{
// Example: Log processed images
$this->logger->info('Processed image', ['path' => $event->getPath()]);
}
Dynamic Filter Configuration:
Override filter settings at runtime via the ImageFilterManager:
$manager = $this->container->get(ImageFilterManager::class);
$manager->setFilter('dynamic_thumb', [
'width' => 300,
'height' => 300,
]);
Custom Cache Backend:
Implement CacheInterface for alternative storage (e.g., S3):
use ChamberOrchestra\ImageBundle\Model\CacheInterface;
class S3Cache implements CacheInterface
{
public function save(string $path, string $content): void { /* ... */ }
public function get(string $path): ?string { /* ... */ }
public function delete(string $path): void { /* ... */ }
}
Bind in services.yaml:
services:
ChamberOrchestra\ImageBundle\Model\CacheInterface: '@app.s3_cache'
Default Filter:
Set a default_filter in config to apply to all images without a specified filter:
default_filter: 'thumb'
Environment-Specific Configs:
Use %env() placeholders for paths or secrets:
cache_dir: '%env(IMAGE_CACHE_DIR)%'
secret: '%env(IMAGE_SECRET)%'
Disable Processing:
Set enabled: false to bypass all processing (useful for development):
chamber_orchestra_image:
enabled: false
How can I help you explore Laravel packages today?