farzai/color-palette
A Laravel package for generating color palettes from a single base color. Create shades, tints, and complementary colors, output them as hex or RGB, and reuse them across Blade views, CSS, or your own theme system. A simple API for consistent colors in any PHP app.
composer require farzai/color-palette
There is no service provider to register and no config file to publish — this is a plain PHP library, not a Laravel package. That means your first decision is where it lives in your app: put it behind a small service class or a facade alias rather than calling it from controllers and Blade templates directly.
Before writing anything, check three things in the repo:
ColorPalette::fromImage($path) / ImageFactory::open(...)). Confirm whether it takes a file path, a binary string, or a GDImage/Imagick resource.composer.json requirements — you need ext-gd or ext-imagick (usually GD), and PHP 8.x. Add the extension to your Docker/Forge/Envoyer provisioning now, not after the first deploy fails.src/ to see what is actually available.The canonical first use case: given an uploaded image, pull the dominant color to use as a header background or placeholder accent.
use Farzai\ColorPalette\ColorPalette;
$palette = ColorPalette::fromImage(storage_path('app/public/cover.jpg'));
$dominant = $palette->getDominantColor(); // a Color instance
$hex = $dominant->toHex(); // "#3b7dd8"
// Usually you also want a small set, ranked by frequency:
$swatches = $palette->getColors(5); // Color[] / PaletteCollection
Verify the exact method names against the source before committing to them — the API surface is small but names vary between versions of this kind of library. Write one test against a fixture image so a future composer update tells you immediately if the API shifted.
Wrap it in a single injectable service. Because there are zero dependents and a tiny star count, treat the library as a swappable detail. One class, one public surface:
namespace App\Services;
use Farzai\ColorPalette\ColorPalette;
class ImagePalette
{
public function forPath(string $absolutePath, int $count = 5): array
{
$palette = ColorPalette::fromImage($absolutePath);
return collect($palette->getColors($count))
->map(fn ($color) => [
'hex' => $color->toHex(),
'rgb' => $color->toRgb(), // [r, g, b]
])
->all();
}
}
Everything else in the app talks to ImagePalette, so ripping the library out later is a one-file change.
Queue the extraction on upload. Color extraction on a 12MP JPEG takes hundreds of milliseconds to seconds. Do it in a ProcessImagePalette job dispatched after the file is stored, and write the result to the model:
// migration
$table->json('palette')->nullable();
// job
public function handle(ImagePalette $palettes): void
{
$path = Storage::disk('public')->path($this->media->path);
$this->media->update([
'palette' => $palettes->forPath($path, 6),
]);
}
Cache by file hash, not by path or ID. Palette output is a pure function of the file bytes plus the extractor settings. hash_file('xxh128', $path) is cheap and gives you a cache key that survives renames, re-uploads of the same image, and storage moves:
$key = 'palette:'.hash_file('xxh128', $path);
$colors = Cache::remember($key, now()->addMonth(), fn () => $palettes->forPath($path));
Downscale before extracting. Accuracy does not depend on full resolution, and this is the single biggest performance lever:
$small = Image::read($path)->scale(width: 200); // intervention/image
$tmp = tempnam(sys_get_temp_dir(), 'pal').'.jpg';
$small->save($tmp);
Pick foreground text with a contrast check, don't guess. If the library exposes a luminance or contrast helper, use it; otherwise implement WCAG relative luminance yourself — never hard-code "white text on the brand color," because a single light uploaded image will break your card.
$text = $dominant->getLuminance() > 0.5 ? '#111111' : '#ffffff';
Expose it to Blade through a view component, not a global helper:
<x-image-swatch :media="$media" /> {{-- renders div with style="background-color: {{ $hex }}" --}}
Use it for CSS-driven theming. Store the palette JSON on your Team/Project model and generate CSS custom properties (--brand-500, --brand-100) from the swatches. This is the highest-value integration for a Laravel app: user-uploaded logos that auto-theme the tenant's dashboard.
memory_limit is the usual failure mode on large uploads. Downscaling first (above) is the fix; raising the limit is not.#RRGGBB, others RRGGBB, some uppercase. Normalize at the boundary of your service class so templates and CSS never see inconsistency.composer.json ("farzai/color-palette": "^1.0"), keep the wrapper class, and write a fixture-based test that asserts stable properties (e.g. "the dominant color of this red image has R > 180") rather than exact hex strings — exact-value tests will fail on any minor algorithm change or extension swap.How can I help you explore Laravel packages today?