1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-12 17:03:59 +02:00

Add Image::reduceColors()

This commit is contained in:
Oliver Vogel
2023-12-16 12:28:44 +01:00
parent 9863a1f7d7
commit 50b873d744
7 changed files with 94 additions and 81 deletions

View File

@@ -1,62 +0,0 @@
<?php
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverSpecializedModifier;
use Intervention\Image\Interfaces\ImageInterface;
/**
* @property int $limit
* @property int $threshold
*/
class LimitColorsModifier extends DriverSpecializedModifier
{
public function apply(ImageInterface $image): ImageInterface
{
// no color limit: no reduction
if ($this->limit === 0) {
return $image;
}
// limit is over threshold: no reduction
if ($this->limit > $this->threshold) {
return $image;
}
$width = $image->width();
$height = $image->height();
foreach ($image as $frame) {
// limitied color image must be palette (indexed) GDImage
$reduced = imagecreate($width, $height);
// save alpha channel
imagesavealpha($reduced, true);
// create matte
$matte = imagecolorallocatealpha($reduced, 255, 255, 255, 127);
// fill with matte
imagefill($reduced, 0, 0, $matte);
// disable alpha blending for the copy process
imagealphablending($reduced, false);
// set transparency and get transparency index
imagecolortransparent($reduced, $matte);
// copy original image (colors are limited automatically in the copy process)
imagecopy($reduced, $frame->native(), 0, 0, 0, 0, $width, $height);
// reduce limit by one to include possible transparency in palette
// $limit = imagecolortransparent($frame->native()) === -1 ? $this->limit : $this->limit - 1;
// decrease colors
// imagetruecolortopalette($reduced, true, $limit);
$frame->setNative($reduced);
}
return $image;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\DriverSpecializedModifier;
use Intervention\Image\Exceptions\InputException;
use Intervention\Image\Interfaces\ImageInterface;
/**
* @property int $limit
* @property mixed $background
*/
class QuantizeColorsModifier extends DriverSpecializedModifier
{
public function apply(ImageInterface $image): ImageInterface
{
if ($this->limit <= 0) {
throw new InputException('Quantization limit must be greater than 0.');
}
// no color reduction if the limit is higher than the colors in the img
$colorCount = imagecolorstotal($image->core()->native());
if ($colorCount > 0 && $this->limit > $colorCount) {
return $image;
}
$width = $image->width();
$height = $image->height();
$background = $this->driver()->colorProcessor($image->colorspace())->colorToNative(
$this->driver()->handleInput($this->background)
);
foreach ($image as $frame) {
// create new image for color quantization
$reduced = imagecreatetruecolor($width, $height);
// fill with background
imagefill($reduced, 0, 0, $background);
// set transparency
imagecolortransparent($reduced, $background);
// copy original image (colors are limited automatically in the copy process)
imagecopy($reduced, $frame->native(), 0, 0, 0, 0, $width, $height);
// gd library does not support color quantization directly therefore the
// colors are decrease by transforming the image to a palette version
imagetruecolortopalette($reduced, true, $this->limit);
$frame->setNative($reduced);
}
return $image;
}
}

View File

@@ -3,23 +3,23 @@
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\DriverSpecializedModifier;
use Intervention\Image\Exceptions\InputException;
use Intervention\Image\Interfaces\ImageInterface;
/**
* @property int $limit
* @property int $threshold
* @property mixed $background
*/
class LimitColorsModifier extends DriverSpecializedModifier
class QuantizeColorsModifier extends DriverSpecializedModifier
{
public function apply(ImageInterface $image): ImageInterface
{
// no color limit: no reduction
if ($this->limit === 0) {
return $image;
if ($this->limit <= 0) {
throw new InputException('Quantization limit must be greater than 0.');
}
// limit is over threshold: no reduction
if ($this->limit > $this->threshold) {
// no color reduction if the limit is higher than the colors in the img
if ($this->limit > $image->core()->native()->getImageColors()) {
return $image;
}

View File

@@ -64,6 +64,7 @@ use Intervention\Image\Modifiers\PixelateModifier;
use Intervention\Image\Modifiers\PlaceModifier;
use Intervention\Image\Modifiers\ProfileModifier;
use Intervention\Image\Modifiers\ProfileRemovalModifier;
use Intervention\Image\Modifiers\QuantizeColorsModifier;
use Intervention\Image\Modifiers\RemoveAnimationModifier;
use Intervention\Image\Modifiers\ResizeCanvasModifier;
use Intervention\Image\Modifiers\ResizeCanvasRelativeModifier;
@@ -366,6 +367,16 @@ final class Image implements ImageInterface, Countable
return $this->modify(new ProfileRemovalModifier());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::reduceColors()
*/
public function reduceColors(int $limit, mixed $background = 'transparent'): ImageInterface
{
return $this->modify(new QuantizeColorsModifier($limit, $background));
}
/**
* {@inheritdoc}
*

View File

@@ -198,6 +198,14 @@ interface ImageInterface extends IteratorAggregate, Countable
*/
public function removeProfile(): ImageInterface;
/**
* Apply color quantization to the current image
*
* @param int $limit
* @return ImageInterface
*/
public function reduceColors(int $limit): ImageInterface;
/**
* Sharpen the current image with given strength
*

View File

@@ -1,12 +0,0 @@
<?php
namespace Intervention\Image\Modifiers;
class LimitColorsModifier extends AbstractModifier
{
public function __construct(
public int $limit = 0,
public int $threshold = 256
) {
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace Intervention\Image\Modifiers;
class QuantizeColorsModifier extends AbstractModifier
{
public function __construct(
public int $limit,
public mixed $background = 'ffffff'
) {
}
}