PHPackages                             ksubileau/color-thief-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Image &amp; Media](/categories/media)
4. /
5. ksubileau/color-thief-php

ActiveLibrary[Image &amp; Media](/categories/media)

ksubileau/color-thief-php
=========================

Grabs the dominant color or a representative color palette from an image.

v3.0.0(1w ago)6394.1M↓36.9%68[2 issues](https://github.com/ksubileau/color-thief-php/issues)20MITPHPPHP ^8.2CI passing

Since May 4Pushed 1w ago23 watchersCompare

[ Source](https://github.com/ksubileau/color-thief-php)[ Packagist](https://packagist.org/packages/ksubileau/color-thief-php)[ Docs](http://www.kevinsubileau.fr/projets/color-thief-php)[ RSS](/packages/ksubileau-color-thief-php/feed)WikiDiscussions main Synced 3d ago

READMEChangelog (9)Dependencies (9)Versions (17)Used By (20)

Color Thief PHP
===============

[](#color-thief-php)

[![Latest Stable Version](https://camo.githubusercontent.com/3d3120f04fefa774b02964b5037ae7aad2fd4ab0cfcdfadc50f31c0e04579949/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b737562696c6561752f636f6c6f722d74686965662d7068703f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ksubileau/color-thief-php)[![Build Status](https://camo.githubusercontent.com/4c73e2d1f58f267f0838ceedf7e9314a2a73f781b7ce685e360ba6b152afb05a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6b737562696c6561752f636f6c6f722d74686965662d7068702f74657374732e796d6c3f7374796c653d666c61742d737175617265)](https://github.com/ksubileau/color-thief-php/actions?query=workflow%3ATests)[![GitHub issues](https://camo.githubusercontent.com/aa240f6e218da01513d5e4b9e0802a00d6d1dc716c43dff7e8c91423e615e558/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f6b737562696c6561752f636f6c6f722d74686965662d7068703f7374796c653d666c61742d737175617265)](https://github.com/ksubileau/color-thief-php/issues)[![Packagist](https://camo.githubusercontent.com/9323f7498b401b5000e621b3eb3986de874e5195e9dd72f7dae2a689a8308f67/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f6b737562696c6561752f636f6c6f722d74686965662d7068703f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ksubileau/color-thief-php)[![License](https://camo.githubusercontent.com/2974b4ae4b64e2165037236e38b9263b94bd206da3072e03a6c567bf9159a062/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6b737562696c6561752f636f6c6f722d74686965662d7068703f7374796c653d666c61742d737175617265)](https://packagist.org/packages/ksubileau/color-thief-php)

A PHP library for grabbing the **dominant color** or a **representative color palette** from an image.

It is a PHP port of the [Color Thief Javascript library](http://github.com/lokesh/color-thief), using the MMCQ (modified median cut quantization) algorithm from the [Leptonica library](http://www.leptonica.com/).

[**See examples**](http://www.kevinsubileau.fr/projets/color-thief-php?utm_campaign=github&utm_term=color-thief-php_readme)

---

Why Color Thief?
----------------

[](#why-color-thief)

Extracting meaningful colors from an image unlocks a surprising range of use cases: generating dynamic themes that match a user's uploaded avatar, building visually coherent product cards from cover art, creating adaptive UI backgrounds for music or video players, or simply analyzing the dominant hues of a dataset of images.

Color Thief PHP does this for you, without any manual color-picking, and returns results in the color format that suits you: hex, CSS `rgb()`, HSL, OKLCH, CMYK, or a plain integer. You can ask for a single dominant color, a ranked palette of up to 20 colors, or semantic *swatches* (Vibrant, Muted, DarkVibrant, etc.).

---

Requirements
------------

[](#requirements)

- PHP **8.2** or higher
- Fileinfo extension
- One or more PHP extensions for image processing:
    - GD &gt;= 2.0
    - Imagick &gt;= 2.0 (but &gt;= 3.0 for CMYK images)
    - Gmagick &gt;= 1.0
- Supports JPEG, PNG, GIF and WEBP images.

---

Getting started
---------------

[](#getting-started)

### Install via Composer

[](#install-via-composer)

The recommended way to install Color Thief is through [Composer](http://getcomposer.org):

```
composer require ksubileau/color-thief-php
```

### Get the dominant color

[](#get-the-dominant-color)

All functionality is exposed through the `ColorThief\ColorThief` class. Instantiate it once and reuse it across multiple images.

```
use ColorThief\ColorThief;

$thief = new ColorThief();
$sourceImage = '/path/to/image.jpg';
$color = $thief->getColor($sourceImage);

echo $color->toCss();    // "rgb(98, 42, 131)"
echo $color->toHex('#'); // "#622a83"
```

`getColor()` returns a `RgbColor` object (or `null` if no color could be extracted), with a set of utility methods to get the color representation that suits you.

### Get a color palette

[](#get-a-color-palette)

```
$palette = $thief->getPalette($sourceImage);

foreach ($palette as $color) {
    echo $color->toHex('#') . "\n";
}
// #622a83
// #d4a832
// #1e6b4a
// ...
```

`getPalette()` returns a `ColorPalette` object, which is countable, iterable, and array-accessible. Colors are ordered from most to least dominant.

### Get semantic swatches

[](#get-semantic-swatches)

```
$swatches = $thief->getSwatches($sourceImage);

echo $swatches->vibrant?->toHex('#');      // e.g. "#e03c7d"
echo $swatches->darkVibrant?->toHex('#');  // e.g. "#7b1c2e"
echo $swatches->muted?->toHex('#');        // e.g. "#b07a92"
```

`getSwatches()` classifies the palette colors into up to six named roles: `vibrant`, `muted`, `darkVibrant`, `darkMuted`, `lightVibrant`, and `lightMuted`. Each property holds an `RgbColor` or `null` if no palette color matched that role.

### Accepted image sources

[](#accepted-image-sources)

All three methods accept the same types for the `$sourceImage` parameter:

- A **file path** string: `'/path/to/image.jpg'` (You must ensure that the path is sanitized before calling ColorThief)
- A **GD resource** (`\GdImage`)
- An **Imagick** instance
- A **Gmagick** instance
- Raw image **binary content** as a string

> **Note:** Loading images from URLs is no longer supported in v3. If you need to process a remote image, fetch it yourself before passing the content to Color Thief (see [Migrating from v2 to v3](#migrating-from-v2-to-v3)).

---

Working with Color Objects
--------------------------

[](#working-with-color-objects)

Every method returns `RgbColor` objects (or collections of them), with a rich set of chainable conversion and utility methods.

### Converting a single color

[](#converting-a-single-color)

```
$color = $thief->getColor('/path/to/image.jpg');

// CSS representations
$color->toCss();            // "rgb(98, 42, 131)"
$color->toOklch()->toCss(); // "oklch(0.3721 0.1584 307.45)"
$color->toHsl()->toCss();   // "hsl(277, 52%, 34%)"

// Hexadecimal
$color->toHex();     // "622a83"
$color->toHex('#');  // "#622a83"

// Component arrays
$color->toArray();            // [98, 42, 131]
$color->toHsl()->toArray();   // [276.92, 0.515, 0.339]
$color->toOklch()->toArray(); // [0.3721, 0.1584, 307.45]
$color->toCmyk()->toArray();  // [0.252, 0.679, 0.0, 0.486]

// RGB packed integer (r luminance();  // 0.042 (WCAG 2.x relative luminance)
$color->isDark();     // true
$color->textColor();  // RgbColor(255, 255, 255) — white text on this background

// Population data
$color->population();  // 4821  (number of pixels this color represents)
$color->proportion();  // 0.127 (fraction of analyzed pixels, 0-1)
```

Available conversion targets from any color object: `toRgb()`, `toOklch()`, `toHsl()`, `toHsv()`, `toCmyk()`.

### Converting a palette

[](#converting-a-palette)

`ColorPalette` mirrors the same conversion methods, applied to all colors at once:

```
$palette = $thief->getPalette('/path/to/image.jpg', colorCount: 6);

$palette->toHex('#');         // ["#622a83", "#d4a832", "#1e6b4a", ...]
$palette->toCss();            // ["rgb(98, 42, 131)", "rgb(212, 168, 50)", ...]
$palette->toArray();          // [[98,42,131], [212,168,50], ...]
$palette->toInt();            // [6432387, 13936178, ...]

// Convert entire palette to another colorspace
$hslPalette = $palette->toHsl();
$oklchPalette = $palette->toOklch();

// Chaining to convert to OKLCH colorspace and get CSS representation
$palette->toOklch()->toCss(); // ["oklch(0.4071 0.1471 310.39)", "oklch(0.7521 0.1381 87.12)", ...]

// map() and reduce() for custom processing
$hexList = $palette->map(fn ($color) => strtoupper($color->toHex('#')));
```

---

Advanced Configuration
----------------------

[](#advanced-configuration)

### Constructor options

[](#constructor-options)

All configuration is passed to the `ColorThief` constructor. Every parameter is optional and falls back to a sensible default:

OptionTypeDefaultDescription`quality``int``10`Pixel sampling rate. `1` analyzes every pixel (highest quality, slowest), `10` samples every 10th pixel.`whiteThreshold``int``250`Pixels with R, G, and B all above this value are ignored. Set to `255` to disable white filtering`alphaThreshold``int``125`Pixels with alpha below this value are ignored (0 = fully transparent, 255 = fully opaque). Set to `0` to include transparent pixels`minSaturation``float``0`Pixels with HSV saturation below this ratio (0–1) are ignored. Set to `0` to disable`colorSpace``ColorSpace``ColorSpace::Oklch`Color space used for internal quantization. `ColorSpace::Oklch` produces perceptually uniform palettes.`preferredAdapter``AdapterInterface|string|null``null`Force using a specific image adapter: `'Gd'`, `'Imagick'`, `'Gmagick'`, or a custom `AdapterInterface` instance. Default `null` value means automatically choosing an available adapter### Overriding options per call with `with()`

[](#overriding-options-per-call-with-with)

`ColorThief` instances are **immutable**. If you need different settings for a specific call without affecting the base configuration, use `with()` by calling it with named arguments. It accepts the exact same parameters as the constructor and returns a new instance with only the specified options overridden. The original instance is left unchanged.

```
$thief = new ColorThief(quality: 10, minSaturation: 0.05);

// Faster extraction, keeping all other settings
$palette = $thief->with(quality: 50)->getPalette('/path/to/image.jpg');

// Stricter filtering for a single call
$color = $thief->with(whiteThreshold: 230, minSaturation: 0.1)->getColor('/path/to/image.jpg');
```

### Adjusting pixel filters

[](#adjusting-pixel-filters)

```
// Include near-white pixels (useful for images where white is meaningful)
$thief = new ColorThief(whiteThreshold: 255);

// Exclude semi-transparent pixels more aggressively
$thief = new ColorThief(alphaThreshold: 200);

// Discard gray and low-saturation pixels to focus on vivid colors
$thief = new ColorThief(minSaturation: 0.15);
```

### Restricting extraction to a region

[](#restricting-extraction-to-a-region)

Use `ImageRegion` to analyze only a rectangular crop of the image:

```
use ColorThief\ImageRegion;

// Crop starting at (50, 100), 200 px wide and 150 px tall
$region = new ImageRegion(x: 50, y: 100, width: 200, height: 150);

// Or: from (50, 100) to the right/bottom edges of the image
$region = new ImageRegion(x: 50, y: 100);

$color   = $thief->getColor('/path/to/image.jpg', region: $region);
$palette = $thief->getPalette('/path/to/image.jpg', region: $region);
```

---

API Reference
-------------

[](#api-reference)

### `ColorThief`

[](#colorthief)

```
new ColorThief(
    int $quality = 10,
    int $whiteThreshold = 250,
    int $alphaThreshold = 125,
    float $minSaturation = 0,
    ColorSpace $colorSpace = ColorSpace::Oklch,
    AdapterInterface|string|null $preferredAdapter = null,
)
```

#### Methods

[](#methods)

**`getColor(mixed $sourceImage, ?ImageRegion $region = null): ?RgbColor`**Returns the single most dominant color, or `null` if the image yields no usable pixels.

**`getPalette(mixed $sourceImage, int $colorCount = 10, ?ImageRegion $region = null): ColorPalette`**Returns a palette of dominant colors (2–20). Colors are ordered most to least dominant.

**`getSwatches(mixed $sourceImage, ?ImageRegion $region = null): ColorSwatches`**Returns semantic swatches classified into six named roles: Vibrant, Muted, DarkVibrant, DarkMuted, LightVibrant, and LightMuted.

**`with(...): self`**Returns a new `ColorThief` instance with the specified options overridden. All arguments are optional and default to the current instance's setting.

### `ColorPalette`

[](#colorpalettetcolor)

An immutable, ordered, array-accessible collection of color objects.

MethodReturnsDescription`count()``int`Number of colors in the palette`isEmpty()``bool`True if the palette has no colors`toRgb()``ColorPalette`Convert the palette to sRGB colorspace`toOklch()``ColorPalette`Convert the palette to OKLCH colorspace`toHsl()``ColorPalette`Convert the palette to HSL colorspace`toHsv()``ColorPalette`Convert the palette to HSV colorspace`toCmyk()``ColorPalette`Convert the palette to CMYK colorspace`toArray()``list`Component arrays in current colorspace`toInt()``list`Packed RGB integers`toHex(string $prefix = '')``list`Hex strings, e.g. `["#622a83", ...]``toCss()``list`CSS strings using the colorspace's native notation`toString()``list`String representation of each color in its current colorspace`map(callable $fn)``array`Apply a callback to each color`reduce(callable $fn, $initial)``mixed`Reduce palette to a single value`ColorPalette` implements `ArrayAccess`, `Countable`, and `IteratorAggregate`, so it supports `foreach`, `count()`, and `$palette[0]` access.

### Color classes

[](#color-classes)

All color classes (`RgbColor`, `HslColor`, `HsvColor`, `OklchColor`, `CmykColor`) share these members.

#### Population and weight

[](#population-and-weight)

MethodReturnsDescription`population()``int`Pixel count this color represents in the source image (among the sampled pixels)`proportion()``float`Fraction of analyzed pixels (0-1)#### Conversions

[](#conversions)

MethodReturnsDescription`toRgb()``RgbColor`Convert to sRGB`toOklch()``OklchColor`Convert to OKLCH`toHsl()``HslColor`Convert to HSL`toHsv()``HsvColor`Convert to HSV`toCmyk()``CmykColor`Convert to CMYK`toArray()``array`Components in native colorspace order`toInt()``int`Packed `(r getColor($image);
$hex     = $color->toHex('#');          // "#622a83"
$arr     = $color->toArray();           // [98, 42, 131]
$int     = $color->toInt();             // 6432387
$palette = $thief->getPalette($image, 5);
$hexList = $palette->toHex('#');        // ["#622a83", ...]
```

### RGB channel getters have been renamed

[](#rgb-channel-getters-have-been-renamed)

v2 exposed `getRed()`, `getGreen()`, and `getBlue()` on the color object. In v3 these are `red()`, `green()`, and `blue()`.

```
// Before (v2)
$color->getRed();
$color->getGreen();
$color->getBlue();

// After (v3)
$color->red();
$color->green();
$color->blue();
```

### URL loading has been removed

[](#url-loading-has-been-removed)

Passing a URL string to `getColor()` or `getPalette()` will now throw a `NotReadableException`. URL fetching was removed to prevent Server-Side Request Forgery (SSRF) vulnerabilities.

Fetch the image yourself and pass the binary content:

```
// Before (v2)
$color = ColorThief::getColor('https://example.com/image.jpg');

// After (v3)
// You are responsible for validating the URL and implementing
// appropriate security controls (allowlisting, redirect policy, timeouts, etc.)
$data  = file_get_contents('https://example.com/image.jpg');
$color = $thief->getColor($data);
```

### OKLCH is now the default quantization color space

[](#oklch-is-now-the-default-quantization-color-space)

v3 uses OKLCH internally by default, which produces more perceptually uniform palettes. If your application depends on the exact palette output of v2, you can restore the old behavior:

```
use ColorThief\ColorSpace;

$thief = new ColorThief(colorSpace: ColorSpace::Rgb);
```

### Maximum palette size reduced to 20

[](#maximum-palette-size-reduced-to-20)

`getPalette()` now accepts a `colorCount` between **2 and 20** (v2 allowed up to 256). Requests above 20 will throw an `InvalidArgumentException`.

### Edge-case behavior for degenerate images

[](#edge-case-behavior-for-degenerate-images)

In v2, fully transparent, fully white, or single-color images could throw exceptions. In v3 they return a graceful result instead: a single-color palette containing black (transparent images), white (all-white images), or the single color itself.

### Region parameter replaces positional `$area` array

[](#region-parameter-replaces-positional-area-array)

The optional area/region parameter in v2 was an associative array. In v3 it is a typed `ImageRegion` object, passed as a named argument.

```
// Before (v2)
$palette = ColorThief::getPalette($image, 5, 10, ['x' => 50, 'y' => 100, 'w' => 200, 'h' => 150]);

// After (v3)
use ColorThief\ImageRegion;

$region  = new ImageRegion(x: 50, y: 100, width: 200, height: 150);
$palette = $thief->getPalette($image, colorCount: 5, region: $region);
```

---

Credits
-------

[](#credits)

### Author

[](#author)

by Kevin Subileau [kevinsubileau.fr](http://www.kevinsubileau.fr/?utm_campaign=github&utm_term=color-thief-php_readme)

Based on the fabulous work done by Lokesh Dhakar [lokeshdhakar.com](http://www.lokeshdhakar.com)[twitter.com/lokesh](http://twitter.com/lokesh)

### Thanks

[](#thanks)

- Lokesh Dhakar - For creating the [original project](http://github.com/lokesh/color-thief).
- Nick Rabinowitz - For creating quantize.js.

License
-------

[](#license)

Licensed under the [MIT License](LICENSE).

###  Health Score

76

—

ExcellentBetter than 100% of packages

Maintenance98

Actively maintained with recent releases

Popularity65

Solid adoption and visibility

Community42

Growing community involvement

Maturity84

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 71.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~443 days

Recently: every ~700 days

Total

11

Last Release

8d ago

Major Versions

v1.4.1 → v2.0.02022-03-12

v2.0.2 → v3.0.02026-06-26

PHP version history (4 changes)v1.0.0PHP &gt;=5.3.0

v1.4.0PHP &gt;=5.4.0

v2.0.0PHP ^7.2|^8.0

v3.0.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/6a117de8a64be55f321ccc90875f969cf990b0c0ca4360be4e181d56d3601c89?d=identicon)[ksubileau](/maintainers/ksubileau)

---

Top Contributors

[![ksubileau](https://avatars.githubusercontent.com/u/3837104?v=4)](https://github.com/ksubileau "ksubileau (207 commits)")[![crishoj](https://avatars.githubusercontent.com/u/20393?v=4)](https://github.com/crishoj "crishoj (26 commits)")[![joeworkman](https://avatars.githubusercontent.com/u/225628?v=4)](https://github.com/joeworkman "joeworkman (16 commits)")[![kisPocok](https://avatars.githubusercontent.com/u/434719?v=4)](https://github.com/kisPocok "kisPocok (13 commits)")[![mreiden](https://avatars.githubusercontent.com/u/6321246?v=4)](https://github.com/mreiden "mreiden (9 commits)")[![jbboehr](https://avatars.githubusercontent.com/u/225601?v=4)](https://github.com/jbboehr "jbboehr (4 commits)")[![rewmike](https://avatars.githubusercontent.com/u/294947?v=4)](https://github.com/rewmike "rewmike (4 commits)")[![red-led](https://avatars.githubusercontent.com/u/1540305?v=4)](https://github.com/red-led "red-led (2 commits)")[![simonschaufi](https://avatars.githubusercontent.com/u/941794?v=4)](https://github.com/simonschaufi "simonschaufi (1 commits)")[![furey](https://avatars.githubusercontent.com/u/1914481?v=4)](https://github.com/furey "furey (1 commits)")[![grachov](https://avatars.githubusercontent.com/u/798245?v=4)](https://github.com/grachov "grachov (1 commits)")[![Moerlin](https://avatars.githubusercontent.com/u/5207329?v=4)](https://github.com/Moerlin "Moerlin (1 commits)")[![othmar52](https://avatars.githubusercontent.com/u/7056051?v=4)](https://github.com/othmar52 "othmar52 (1 commits)")[![Redominus](https://avatars.githubusercontent.com/u/22024214?v=4)](https://github.com/Redominus "Redominus (1 commits)")[![chellem](https://avatars.githubusercontent.com/u/570856?v=4)](https://github.com/chellem "chellem (1 commits)")

---

Tags

color-palettedominant-colorsgdimage-processingimagickphpphpcolorpalettethiefdominant

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Rector

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ksubileau-color-thief-php/health.svg)

```
[![Health](https://phpackages.com/badges/ksubileau-color-thief-php/health.svg)](https://phpackages.com/packages/ksubileau-color-thief-php)
```

###  Alternatives

[league/color-extractor

Extract colors from an image as a human would do.

1.3k5.1M19](/packages/league-color-extractor)[brianmcdo/image-palette

Extracts colors from an image and generates a color palette against a whitelist of colors.

183222.1k2](/packages/brianmcdo-image-palette)[dereuromark/media-embed

A PHP library to deal with all those media services around, parsing their URLs and embedding their audio/video content in websites.

181576.2k17](/packages/dereuromark-media-embed)[marijnvdwerf/material-palette

Prominent image colour extraction for PHP

3154.1k](/packages/marijnvdwerf-material-palette)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
