Installation:
composer require league/color-extractor
Ensure ext-gd is enabled in your PHP environment.
First Use Case: Extract colors from an uploaded image in a Laravel controller:
use League\ColorExtractor\ColorExtractor;
use League\ColorExtractor\Palette;
public function extractColors(Request $request)
{
$imagePath = $request->file('image')->getRealPath();
$palette = Palette::fromFilename($imagePath);
$colors = (new ColorExtractor($palette))->extract(5);
return response()->json($colors);
}
Where to Look First:
Palette class: Core for loading images and generating color data.ColorExtractor class: Extracts representative colors from a palette.Color helper: Converts between integer and hex representations.Extracting Colors from Uploads:
// In a Laravel controller
public function handleUpload(Request $request)
{
$image = $request->file('image');
$palette = Palette::fromFilename($image->getRealPath());
$topColors = $palette->getMostUsedColors(3);
return view('result', ['colors' => $topColors]);
}
URL-Based Extraction (Async): Use Laravel Queues to process remote images:
// Job
class ExtractRemoteColorsJob implements ShouldQueue
{
public function handle()
{
$palette = Palette::fromUrl('https://example.com/image.jpg');
$colors = (new ColorExtractor($palette))->extract(5);
// Store in database or cache
}
}
// Dispatch
ExtractRemoteColorsJob::dispatch();
Dynamic Theming: Generate CSS variables from extracted colors:
public function getThemeColors(Request $request)
{
$palette = Palette::fromFilename($request->file('theme_image')->getRealPath());
$colors = $palette->getMostUsedColors(4);
$cssVars = collect($colors)->map(fn($color) => "--color-$color: " . Color::fromIntToHex($color) . ";");
return response()->json(['css' => $cssVars->implode(' ')], 200);
}
Transparency Handling: Blend transparent pixels with a background color:
$palette = Palette::fromFilename($imagePath, Color::fromHexToInt('#FFFFFF'));
Batch Processing:
Use Laravel’s Artisan commands to process a directory of images:
// app/Console/Commands/ProcessImages.php
public function handle()
{
$images = Storage::disk('public')->files('images');
foreach ($images as $image) {
$palette = Palette::fromFilename(storage_path('app/' . $image));
$colors = (new ColorExtractor($palette))->extract(3);
// Save to database
}
}
Caching Palettes: Cache extracted palettes to avoid reprocessing:
public function getCachedPalette($imagePath)
{
return Cache::remember("palette-{$imagePath}", now()->addHours(1), function() use ($imagePath) {
return Palette::fromFilename($imagePath);
});
}
Integration with Laravel Filesystem: Read images from S3 or other disks:
$path = Storage::disk('s3')->path('uploads/product.jpg');
$palette = Palette::fromFilename($path);
Validation: Validate image types and GD extension before processing:
if (!extension_loaded('gd')) {
throw new RuntimeException('GD extension is required.');
}
$request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
]);
Error Handling: Gracefully handle file/permission errors:
try {
$palette = Palette::fromFilename($path);
} catch (InvalidArgumentException $e) {
Log::error("Color extraction failed: " . $e->getMessage());
return back()->withError('Invalid image file.');
}
Testing:
Mock image inputs using Palette::fromContents():
public function testColorExtraction()
{
$imageData = file_get_contents(__DIR__ . '/test-image.png');
$palette = Palette::fromContents($imageData);
$this->assertCount(5, $palette->getMostUsedColors(5));
}
GD Extension Dependency:
ext-gd will cause runtime errors.bootstrap/app.php or use a fallback (e.g., Imagick).Transparency Handling:
$palette = Palette::fromFilename($path, Color::fromHexToInt('#FFFFFF'));
Large Images:
$image = Image::make($request->file('image')->getRealPath())->resize(800, null);
$image->save($tempPath);
$palette = Palette::fromFilename($tempPath);
URL Fetching:
Palette::fromUrl() requires cURL or allow_url_fopen.Color Count Mismatches:
getColorCount() may return 0 for non-existent colors.$colorInt = Color::fromHexToInt('#000000');
$count = $palette->getColorCount($colorInt) ?? 0;
Log Palette Data: Inspect extracted colors for debugging:
foreach ($palette as $color => $count) {
Log::debug("Color: " . Color::fromIntToHex($color) . ", Count: " . $count);
}
Check Image Validity: Verify images are readable before processing:
if (!is_readable($imagePath)) {
throw new RuntimeException("Image file is not readable.");
}
Memory Limits: Increase PHP memory limit for large images:
ini_set('memory_limit', '512M');
Optimize for Performance:
Extend Functionality:
ColorExtractor decorator to add domain-specific logic:
class BrandColorExtractor extends ColorExtractor
{
public function extractBrandColors($limit = 3)
{
$colors = parent::extract($limit);
return collect($colors)->filter(fn($color) => $this->isBrandColor($color));
}
}
Handle Edge Cases:
$colors = $extractor->extract(5);
if (empty($colors)) {
$colors = [$palette->getMostUsedColor()];
}
Laravel Service Container: Bind the extractor as a singleton for reuse:
$this->app->singleton(ColorExtractor::class, function ($app) {
$imagePath = $app['request']->file('image')->getRealPath();
return new ColorExtractor(Palette::fromFilename($imagePath));
});
Testing Transparency: Test with images containing transparency to ensure blending works as expected:
public function testTransparentImage()
{
$pngWithAlpha = file_get_contents(__DIR__ . '/transparent-image.png');
$palette = Palette::fromContents($pngWithAlpha, Color::fromHexToInt('#00FF00'));
$this->assertNotEmpty($palette->getMostUsedColors(1));
}
Fallback for Missing GD: Use a queue job with a fallback to a cloud service:
class ExtractColorsJob implements ShouldQueue
{
public function handle()
{
if (extension_loaded('gd')) {
$palette = Palette::fromFilename($
How can I help you explore Laravel packages today?