Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Color Palette Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. The README's "Usage" block — the entry point is typically an image factory or a static constructor (e.g. ColorPalette::fromImage($path) / ImageFactory::open(...)). Confirm whether it takes a file path, a binary string, or a GDImage/Imagick resource.
  2. 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.
  3. The extractor/strategy list — most implementations of this pattern offer 2–4 algorithms (quantize, k-means, dominant-color-only). Skim the class names under 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.

Implementation Patterns

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.

Gotchas and Tips

  • Transparent PNGs return garbage. Alpha pixels are often read as black. Composite onto white (or the intended background) with GD/Imagick before extraction, or filter near-black results manually.
  • JPEG compression shifts colors. The same image re-saved will yield slightly different hex values. Round to a stable representation and store what you got — don't expect byte-identical output across runs or across GD/Imagick backends.
  • GD and Imagick produce different palettes. If you have multiple app servers, pin the extension in your Docker image so every node agrees. Otherwise a palette computed on staging won't match production and you'll chase a phantom bug.
  • memory_limit is the usual failure mode on large uploads. Downscaling first (above) is the fix; raising the limit is not.
  • Count is a hint, not a guarantee. Requesting 6 colors may return 4 if the image is nearly monochrome — the extractor merges near-duplicates. Always handle a short array and have a fallback brand color.
  • Hex normalization. Some methods return #RRGGBB, others RRGGBB, some uppercase. Normalize at the boundary of your service class so templates and CSS never see inconsistency.
  • This is a 6-star library with zero dependents. Pin the version in 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.
  • The listed last release date is in the future relative to typical release cadences. Check the actual tags and commit history before adopting; if the repo looks stale or the tags don't line up, budget for vendoring or forking it. The MIT license makes that trivial.
  • Extension point to watch for: if the library exposes an extractor interface or accepts a custom strategy, implement it rather than post-processing the results. Post-hoc filtering of a fixed palette loses information you can't recover.
  • Debugging tip: when colors look "wrong," dump the intermediate downscaled image to disk and open it. Nine times out of ten the bug is in the resize/composite step, not the extractor.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core