pixielity / laravel-color-thief
Color extraction and palette generation utilities
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
pkg:composer/pixielity/laravel-color-thief
Requires
- php: ^8.5
Requires (Dev)
- mockery/mockery: ^1.6
- orchestra/testbench: ^10.0
- phpunit/phpunit: ^11.0
README
Color extraction and palette generation utilities for the Pixielity Framework, providing easy-to-use methods for extracting dominant colors and color palettes from images.
Table of Contents
- Overview
- Features
- Installation
- Usage
- API Reference
- Caching
- Color Manipulation
- Best Practices
- Testing
- Troubleshooting
Overview
The ColorThief package wraps the popular ColorThief PHP library with Laravel-specific features including automatic caching, facade support, and color manipulation utilities. Extract dominant colors and generate color palettes from any image source.
Features
- ✅ Dominant Color Extraction: Get the main color from any image
- ✅ Color Palette Generation: Extract multiple colors to create palettes
- ✅ Multiple Image Sources: Support for file paths, URLs, GD resources, Imagick instances, and binary strings
- ✅ Automatic Caching: Built-in 30-day caching for performance
- ✅ Color Manipulation: Lighten, darken, and adjust color lightness
- ✅ Hex Color Support: All colors returned as hex codes
- ✅ Laravel Integration: Facade and service provider included
- ✅ Octane Safe: No request-specific state, fully compatible with Laravel Octane
Installation
The ColorThief package is part of the Framework package:
composer require pixielity/color-thief
The service provider is automatically registered via Laravel's package discovery.
Usage
Using the Facade
use Pixielity\ColorThief\Facades\ColorThief;
// Get dominant color from image
$dominantColor = ColorThief::getDominantColor('/path/to/image.jpg');
// Returns: "#3a5f8b"
// Get color palette
$palette = ColorThief::getColorPalette('/path/to/image.jpg', 5);
// Returns: ["#3a5f8b", "#8b3a5f", "#5f8b3a", "#8b5f3a", "#5f3a8b"]
// Lighten a color
$lighter = ColorThief::lightenColor('#3a5f8b', 20);
// Returns: "#6a8fbb"
// Darken a color
$darker = ColorThief::darkenColor('#3a5f8b', 20);
// Returns: "#0a2f5b"
Using Dependency Injection
use Pixielity\ColorThief\Contracts\ColorThief;
class ImageService
{
public function __construct(
private ColorThief $colorThief
) {}
public function extractColors(string $imagePath): array
{
return [
'dominant' => $this->colorThief->getDominantColor($imagePath),
'palette' => $this->colorThief->getColorPalette($imagePath, 5),
];
}
}
Using Service Container
// Resolve from container
$colorThief = app(Pixielity\ColorThief\ColorThief::class);
// Or use contract
$colorThief = app(Pixielity\ColorThief\Contracts\ColorThiefInterface::class);
API Reference
getDominantColor()
Extract the dominant (most prominent) color from an image.
public function getDominantColor(
mixed $sourceImage,
int $quality = 10,
?array $area = null
): string
Parameters:
$sourceImage(mixed) - Image source (file path, URL, GD resource, Imagick instance, or binary string)$quality(int) - Sampling quality from 1 (best) to 10 (fastest). Default: 10$area(array|null) - Optional area to sample [x, y, width, height]
Returns:
string- Hex color code (e.g., "#3a5f8b")
Examples:
use Pixielity\ColorThief\Facades\ColorThief;
// From file path
$color = ColorThief::getDominantColor('/path/to/image.jpg');
// From URL
$color = ColorThief::getDominantColor('https://example.com/image.jpg');
// With higher quality (slower but more accurate)
$color = ColorThief::getDominantColor('/path/to/image.jpg', 1);
// Sample specific area [x, y, width, height]
$color = ColorThief::getDominantColor('/path/to/image.jpg', 10, [0, 0, 100, 100]);
// From GD resource
$gd = imagecreatefromjpeg('/path/to/image.jpg');
$color = ColorThief::getDominantColor($gd);
// From binary string
$binary = file_get_contents('/path/to/image.jpg');
$color = ColorThief::getDominantColor($binary);
getColorPalette()
Extract a palette of colors from an image.
public function getColorPalette(
mixed $sourceImage,
int $colorCount = 10,
int $quality = 10,
?array $area = null
): array
Parameters:
$sourceImage(mixed) - Image source$colorCount(int) - Number of colors to extract. Default: 10$quality(int) - Sampling quality from 1 (best) to 10 (fastest). Default: 10$area(array|null) - Optional area to sample [x, y, width, height]
Returns:
array<string>- Array of hex color codes
Examples:
use Pixielity\ColorThief\Facades\ColorThief;
// Get 5 colors
$palette = ColorThief::getColorPalette('/path/to/image.jpg', 5);
// Returns: ["#3a5f8b", "#8b3a5f", "#5f8b3a", "#8b5f3a", "#5f3a8b"]
// Get 10 colors with high quality
$palette = ColorThief::getColorPalette('/path/to/image.jpg', 10, 1);
// Sample specific area
$palette = ColorThief::getColorPalette('/path/to/image.jpg', 5, 10, [0, 0, 200, 200]);
// Get many colors for detailed palette
$palette = ColorThief::getColorPalette('/path/to/image.jpg', 20);
lightenColor()
Lighten a color by a specified percentage.
public function lightenColor(string $hexColor, int $percentage): string
Parameters:
$hexColor(string) - Hex color code (e.g., "#3a5f8b" or "3a5f8b")$percentage(int) - Percentage to lighten (0-100)
Returns:
string- Lightened hex color code
Examples:
use Pixielity\ColorThief\Facades\ColorThief;
$original = '#3a5f8b';
// Lighten by 20%
$lighter = ColorThief::lightenColor($original, 20);
// Returns: "#6a8fbb"
// Lighten by 50%
$muchLighter = ColorThief::lightenColor($original, 50);
// Returns: "#9abfdb"
// Create a gradient
$gradient = [
ColorThief::lightenColor($original, 0), // Original
ColorThief::lightenColor($original, 25), // Slightly lighter
ColorThief::lightenColor($original, 50), // Medium lighter
ColorThief::lightenColor($original, 75), // Very light
];
darkenColor()
Darken a color by a specified percentage.
public function darkenColor(string $hexColor, int $percentage): string
Parameters:
$hexColor(string) - Hex color code (e.g., "#3a5f8b" or "3a5f8b")$percentage(int) - Percentage to darken (0-100)
Returns:
string- Darkened hex color code
Examples:
use Pixielity\ColorThief\Facades\ColorThief;
$original = '#3a5f8b';
// Darken by 20%
$darker = ColorThief::darkenColor($original, 20);
// Returns: "#0a2f5b"
// Darken by 50%
$muchDarker = ColorThief::darkenColor($original, 50);
// Returns: "#00001b"
// Create a dark gradient
$gradient = [
ColorThief::darkenColor($original, 0), // Original
ColorThief::darkenColor($original, 25), // Slightly darker
ColorThief::darkenColor($original, 50), // Medium darker
ColorThief::darkenColor($original, 75), // Very dark
];
adjustColorLightness()
Adjust the lightness of a color by a specific value.
public function adjustColorLightness(string $hexColor, int $adjustment): string
Parameters:
$hexColor(string) - Hex color code$adjustment(int) - Adjustment value (-255 to 255). Positive lightens, negative darkens
Returns:
string- Adjusted hex color code
Examples:
use Pixielity\ColorThief\Facades\ColorThief;
$original = '#3a5f8b';
// Lighten by 50 units
$lighter = ColorThief::adjustColorLightness($original, 50);
// Darken by 50 units
$darker = ColorThief::adjustColorLightness($original, -50);
// No change
$same = ColorThief::adjustColorLightness($original, 0);
Caching
All color extraction and manipulation operations are automatically cached for 30 days to improve performance.
Cache Strategy
- TTL: 30 days (2,592,000 seconds)
- Key Format:
color_thief_{operation}_{parameters} - Deterministic: Same input always produces same output, perfect for long-term caching
Cache Keys
// Dominant color
"color_thief_/path/to/image.jpg"
// Color palette
"color_thief_color_palette_/path/to/image.jpg_5_10"
// Lighten color
"color_thief_lighten_color_#3a5f8b_20"
// Darken color
"color_thief_darken_color_#3a5f8b_20"
Manual Cache Management
use Illuminate\Support\Facades\Cache;
// Clear all ColorThief cache
Cache::flush(); // Clears all cache
// Clear specific image cache
$cacheKey = app(Pixielity\ColorThief\ColorThief::class)
->generateCacheKey('/path/to/image.jpg');
Cache::forget($cacheKey);
Color Manipulation
Creating Color Variations
use Pixielity\ColorThief\Facades\ColorThief;
$baseColor = '#3a5f8b';
// Create a complete color scheme
$colorScheme = [
'base' => $baseColor,
'light' => ColorThief::lightenColor($baseColor, 30),
'lighter' => ColorThief::lightenColor($baseColor, 60),
'dark' => ColorThief::darkenColor($baseColor, 30),
'darker' => ColorThief::darkenColor($baseColor, 60),
];
Generating Theme Colors
// Extract colors from brand logo
$logo = '/path/to/logo.png';
$palette = ColorThief::getColorPalette($logo, 5);
// Create theme with variations
$theme = [
'primary' => $palette[0],
'primary-light' => ColorThief::lightenColor($palette[0], 20),
'primary-dark' => ColorThief::darkenColor($palette[0], 20),
'secondary' => $palette[1],
'accent' => $palette[2],
];
Creating Gradients
$startColor = '#3a5f8b';
$steps = 5;
$gradient = [];
for ($i = 0; $i < $steps; $i++) {
$percentage = ($i / ($steps - 1)) * 100;
$gradient[] = ColorThief::lightenColor($startColor, (int)$percentage);
}
Best Practices
1. Use Appropriate Quality Settings
// For thumbnails or quick previews - use default quality (10)
$color = ColorThief::getDominantColor($image, 10);
// For production use - use medium quality (5)
$color = ColorThief::getDominantColor($image, 5);
// For critical color matching - use best quality (1)
$color = ColorThief::getDominantColor($image, 1);
2. Sample Relevant Areas
// Sample only the product, not the background
$productArea = [50, 50, 300, 300]; // [x, y, width, height]
$productColor = ColorThief::getDominantColor($image, 10, $productArea);
// Sample the top portion for header colors
$headerArea = [0, 0, 1920, 200];
$headerColor = ColorThief::getDominantColor($image, 10, $headerArea);
3. Request Appropriate Palette Sizes
// For simple themes - 3-5 colors
$palette = ColorThief::getColorPalette($image, 5);
// For detailed palettes - 10-15 colors
$palette = ColorThief::getColorPalette($image, 12);
// Avoid excessive colors (slow and unnecessary)
// ❌ Bad
$palette = ColorThief::getColorPalette($image, 50);
4. Handle Errors Gracefully
try {
$color = ColorThief::getDominantColor($imagePath);
} catch (\Exception $e) {
// Fallback to default color
$color = '#3a5f8b';
Log::warning('Color extraction failed', [
'image' => $imagePath,
'error' => $e->getMessage()
]);
}
5. Process Images Asynchronously
use Illuminate\Support\Facades\Queue;
// Queue color extraction for large images
Queue::push(function () use ($imagePath) {
$colors = ColorThief::getColorPalette($imagePath, 10, 1);
// Store results
cache()->put("image_colors_{$imagePath}", $colors, now()->addDays(30));
});
6. Validate Color Inputs
function isValidHexColor(string $color): bool
{
return (bool) preg_match('/^#?[0-9A-Fa-f]{6}$/', $color);
}
if (isValidHexColor($userColor)) {
$lighter = ColorThief::lightenColor($userColor, 20);
}
Testing
Unit Testing
use Tests\TestCase;
use Pixielity\ColorThief\Facades\ColorThief;
class ColorThiefTest extends TestCase
{
public function test_extracts_dominant_color(): void
{
$imagePath = __DIR__ . '/fixtures/test-image.jpg';
$color = ColorThief::getDominantColor($imagePath);
$this->assertIsString($color);
$this->assertMatchesRegularExpression('/^#[0-9a-f]{6}$/i', $color);
}
public function test_generates_color_palette(): void
{
$imagePath = __DIR__ . '/fixtures/test-image.jpg';
$palette = ColorThief::getColorPalette($imagePath, 5);
$this->assertIsArray($palette);
$this->assertCount(5, $palette);
foreach ($palette as $color) {
$this->assertMatchesRegularExpression('/^#[0-9a-f]{6}$/i', $color);
}
}
public function test_lightens_color(): void
{
$original = '#3a5f8b';
$lighter = ColorThief::lightenColor($original, 20);
$this->assertNotEquals($original, $lighter);
$this->assertMatchesRegularExpression('/^#[0-9a-f]{6}$/i', $lighter);
}
public function test_darkens_color(): void
{
$original = '#3a5f8b';
$darker = ColorThief::darkenColor($original, 20);
$this->assertNotEquals($original, $darker);
$this->assertMatchesRegularExpression('/^#[0-9a-f]{6}$/i', $darker);
}
}
Integration Testing
public function test_extracts_colors_from_uploaded_image(): void
{
Storage::fake('public');
$file = UploadedFile::fake()->image('test.jpg', 600, 400);
$path = $file->store('images', 'public');
$fullPath = Storage::disk('public')->path($path);
$color = ColorThief::getDominantColor($fullPath);
$palette = ColorThief::getColorPalette($fullPath, 5);
$this->assertIsString($color);
$this->assertCount(5, $palette);
}
Troubleshooting
Image Not Found
Problem: Exception thrown when image path is invalid
Solution:
if (file_exists($imagePath)) {
$color = ColorThief::getDominantColor($imagePath);
} else {
Log::error("Image not found: {$imagePath}");
$color = '#000000'; // Fallback
}
Memory Limit Exceeded
Problem: Large images cause memory errors
Solution:
// Resize image before color extraction
$image = Image::make($largePath)->resize(800, null, function ($constraint) {
$constraint->aspectRatio();
});
$tempPath = storage_path('temp/resized.jpg');
$image->save($tempPath);
$color = ColorThief::getDominantColor($tempPath);
unlink($tempPath);
Slow Performance
Problem: Color extraction takes too long
Solutions:
- Use lower quality setting (higher number)
- Resize images before processing
- Sample smaller areas
- Process asynchronously
- Ensure caching is enabled
// Fast extraction
$color = ColorThief::getDominantColor($image, 10); // Quality 10 (fastest)
// Sample smaller area
$color = ColorThief::getDominantColor($image, 10, [0, 0, 200, 200]);
Invalid Color Output
Problem: Colors don't match visual appearance
Solutions:
- Use better quality setting (lower number)
- Sample specific areas instead of entire image
- Increase palette size for more options
// Better quality
$color = ColorThief::getDominantColor($image, 1);
// Sample relevant area
$color = ColorThief::getDominantColor($image, 5, [100, 100, 400, 400]);
Common Use Cases
Product Image Colors
class ProductService
{
public function extractProductColors(Product $product): void
{
$imagePath = storage_path("app/public/{$product->image}");
$product->update([
'primary_color' => ColorThief::getDominantColor($imagePath),
'color_palette' => ColorThief::getColorPalette($imagePath, 5),
]);
}
}
Dynamic Theme Generation
class ThemeService
{
public function generateThemeFromLogo(string $logoPath): array
{
$palette = ColorThief::getColorPalette($logoPath, 3);
return [
'primary' => $palette[0],
'primary-light' => ColorThief::lightenColor($palette[0], 30),
'primary-dark' => ColorThief::darkenColor($palette[0], 30),
'secondary' => $palette[1],
'accent' => $palette[2],
];
}
}
Image Search by Color
class ImageSearchService
{
public function findSimilarColorImages(string $targetColor): Collection
{
return Image::all()->filter(function ($image) use ($targetColor) {
$imageColor = ColorThief::getDominantColor($image->path);
return $this->colorDistance($imageColor, $targetColor) < 50;
});
}
private function colorDistance(string $color1, string $color2): float
{
// Calculate color distance using RGB values
// Implementation details...
}
}
Related Packages
- Framework/Support - String and array utilities
- Framework/Response - API response formatting
- Foundation - Base application structure
External Resources
- ColorThief PHP - Underlying library
- Color Theory - Understanding colors
License
MIT License - Part of the Pixielity Framework package.