Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
3cd33df
Implement color palette extraction
olivervogel Aug 7, 2026
e22d05c
Merge branch 'develop' into feat/color-palette-lazy
olivervogel Aug 8, 2026
3db0b5e
Add ColorCountAnalyzer
olivervogel Aug 8, 2026
d45e416
Merge branch 'feat/color-count-analyzer' into feat/color-palette-lazy
olivervogel Aug 8, 2026
54e8718
Implement color palette
olivervogel Aug 8, 2026
288dcbf
Implement ColorPaletteModifiedMedianCutAnalyzer
olivervogel Aug 9, 2026
5653bc4
Adjust sample coordinate grid
olivervogel Aug 9, 2026
d2f4054
Remove ColorPaletteModifiedMedianCutAnalyzer::class
olivervogel Aug 9, 2026
f2d3bbd
Rename classes
olivervogel Aug 9, 2026
4d94255
Refactor
olivervogel Aug 9, 2026
aa99578
Refactor
olivervogel Aug 10, 2026
ae35763
Add tests
olivervogel Aug 10, 2026
148c88a
Refactor
olivervogel Aug 10, 2026
d2b6c00
Add tests
olivervogel Aug 10, 2026
6b95279
Add tests
olivervogel Aug 10, 2026
eb392ec
Add tests
olivervogel Aug 10, 2026
bc9a661
Add tests
olivervogel Aug 10, 2026
1fffde4
Rename PaletteColor to QuantizedColor
olivervogel Aug 10, 2026
10a291b
Fix analyzer
olivervogel Aug 10, 2026
2d07028
Update maxColors default value
olivervogel Aug 10, 2026
806976b
Rename method
olivervogel Aug 10, 2026
2c63321
Redesign color palette API
olivervogel Aug 11, 2026
261470c
Add tests
olivervogel Aug 11, 2026
bc9806c
Add comments
olivervogel Aug 11, 2026
1c500f4
Remove unused PaletteException
olivervogel Aug 11, 2026
012fa25
Add tests
olivervogel Aug 11, 2026
bfb500e
Refactor Quantizer logic
olivervogel Aug 11, 2026
080cec7
Fix Analyzers
olivervogel Aug 11, 2026
b102ce2
Refactor
olivervogel Aug 12, 2026
2ab0f81
Fix bug
olivervogel Aug 12, 2026
277b7c7
Refactor
olivervogel Aug 12, 2026
c3d7ae4
Edit description
olivervogel Aug 12, 2026
677b7bb
Refactor swatches
olivervogel Aug 12, 2026
f1090e4
Refactor
olivervogel Aug 13, 2026
56e1e64
Fix reseeding PHP's global RNG
olivervogel Aug 13, 2026
8a15a28
Add condition for Rng::getInt call
olivervogel Aug 13, 2026
f337d72
Fix bug
olivervogel Aug 13, 2026
3d3e2fe
Fix palette sort order
olivervogel Aug 13, 2026
5136371
Add gates
olivervogel Aug 13, 2026
7ebd0b3
Fix bug
olivervogel Aug 13, 2026
af19f81
Fix
olivervogel Aug 13, 2026
ef8b529
Add Test
olivervogel Aug 13, 2026
c4eda2c
Fix sorting palettes loosing color details
olivervogel Aug 13, 2026
9a57742
Fix
olivervogel Aug 13, 2026
535bd6d
Remove try/catch
olivervogel Aug 13, 2026
9bfef2f
Refactor
olivervogel Aug 13, 2026
2399dec
Remove redundant code
olivervogel Aug 13, 2026
fd95c10
Improve code
olivervogel Aug 13, 2026
a8d3d28
Add @template to phpcs config
olivervogel Aug 13, 2026
13a384e
Add type hints
olivervogel Aug 13, 2026
eba9403
Edit comments
olivervogel Aug 13, 2026
af3d4ac
Merge Histogram into Palette
olivervogel Aug 14, 2026
280aedb
Update Swatches
olivervogel Aug 14, 2026
51941ef
Make SwatchesInterface more flexible
olivervogel Aug 14, 2026
344d492
Add region limiter to ColorExtractor
olivervogel Aug 14, 2026
6a5360f
Add tests
olivervogel Aug 14, 2026
bccf420
Fix bug
olivervogel Aug 14, 2026
ee2824e
Remove redundant code
olivervogel Aug 14, 2026
d313a61
Rename variables
olivervogel Aug 14, 2026
d7064e9
Remove unused code
olivervogel Aug 14, 2026
8c14e76
Implement PaletteInterface::sortByPresence()
olivervogel Aug 14, 2026
9210a9b
Fix bug
olivervogel Aug 14, 2026
bb66791
Add assertions
olivervogel Aug 14, 2026
5a2b468
Fix bug
olivervogel Aug 14, 2026
8f91ddf
chore: remove unrelated whitespace change in Collection
deluxetom Aug 14, 2026
64af127
fix(colors): correct palette colorspace conversion, mixed sorting and…
deluxetom Aug 14, 2026
5bd670c
fix(colors): extract actual image colors with driver-independent quan…
deluxetom Aug 14, 2026
5eac98f
fix(analyzers): make dominant color analysis deterministic and fast
deluxetom Aug 14, 2026
fc261f6
fix(analyzers): validate sample region position within image bounds
deluxetom Aug 14, 2026
fb6b5cb
fix(colors): validate swatches classname before instantiation
deluxetom Aug 14, 2026
6f0d931
fix(swatches): keep object usable after array offset unset
deluxetom Aug 14, 2026
15ee1e2
feat(image): declare colors() in ImageInterface
deluxetom Aug 14, 2026
2fb1245
Remove colors() from ImageInterface to prevent BC
olivervogel Aug 15, 2026
4c582d0
Remove unused ColorCountAnalyzers
olivervogel Aug 15, 2026
c21583d
Lower verbosity
olivervogel Aug 15, 2026
7383917
Create DominantPaletteAnalyzer::randomize()
olivervogel Aug 15, 2026
7bd2571
Refactor
olivervogel Aug 15, 2026
4479985
Add secondary order for sorting colors with same presence
olivervogel Aug 15, 2026
71b40ff
Add test for Quantizer bug reproduction
olivervogel Aug 15, 2026
19043c6
Rename classes
olivervogel Aug 15, 2026
42074d5
A little bit of everything
olivervogel Aug 15, 2026
ee1e65f
Add PaletteInterface::quantize() and PaletteInterface::reduce()
olivervogel Aug 16, 2026
650934f
Implement PaletteInterface:hasColor()
olivervogel Aug 16, 2026
ae4137e
Add assertion
olivervogel Aug 16, 2026
16ede3d
Edit descriptions
olivervogel Aug 16, 2026
77ba9e8
Add PHPDocs generics for ColorExtractor::swatches()
olivervogel Aug 16, 2026
0c6f868
Edit description
olivervogel Aug 16, 2026
cda2f5c
Fix bug in ArrayAccess implementation of AbstractSwatches
olivervogel Aug 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
@uses,
"/>
<element value="
@template,
@param,
@throws,
@return,
Expand Down
78 changes: 78 additions & 0 deletions src/Analyzers/AbstractPaletteAnalyzer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

namespace Intervention\Image\Analyzers;

use Generator;
use Intervention\Image\Exceptions\InvalidArgumentException;
use Intervention\Image\Interfaces\AnalyzerInterface;
use Intervention\Image\Interfaces\ColorInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\SizeInterface;

abstract class AbstractPaletteAnalyzer implements AnalyzerInterface
{
/**
* Collect sample colors from the image dependant on the image size and the given region.
*
* @throws InvalidArgumentException
* @return Generator<ColorInterface>
*/
protected function collectColors(ImageInterface $image, ?SizeInterface $region = null): Generator
{
foreach ($this->sampleCoordinates($image->size(), $region) as $coordinate) {
$color = $image->colorAt(...$coordinate);
if ($color->isClear()) {
continue;
}

yield $color;
}
}

/**
* Get dynamic grid of pixel sample coordinates in the given region of the image size.
*
* @throws InvalidArgumentException
* @return Generator<array{x: int, y: int}>
*/
protected function sampleCoordinates(SizeInterface $size, ?SizeInterface $region = null): Generator
{
$region = $region === null ? $size : $region;

$startX = $region->pivot()->x();
$startY = $region->pivot()->y();
$width = $region->width();
$height = $region->height();

// validate the region including its position, otherwise offset
// regions would sample coordinates outside of the image
if (
$startX < 0 || $startY < 0
|| $startX + $width > $size->width()
|| $startY + $height > $size->height()
) {
throw new InvalidArgumentException('The region must fit within the actual image size');
}

$totalPixels = $width * $height;

$sampleRate = match (true) {
$totalPixels <= 10000 => 1, // <= 10k pixels: sample all
$totalPixels <= 100000 => 5, // 10k-100k: every 5th pixel
$totalPixels <= 500000 => 10, // 100k-500k: every 10th pixel
$totalPixels <= 2000000 => 20, // 500k-2m: every 20th pixel
default => 30, // > 2m: every 30th pixel
};

$endX = $startX + $width;
$endY = $startY + $height;

for ($y = $startY; $y < $endY; $y += $sampleRate) {
for ($x = $startX; $x < $endX; $x += $sampleRate) {
yield ['x' => $x, 'y' => $y];
}
}
}
}
Loading