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

Merge branch 'develop' into feature/png-encoder-indexed-option

This commit is contained in:
Oliver Vogel
2024-08-11 12:03:19 +02:00
21 changed files with 260 additions and 5 deletions

1
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,3 @@
github: [Intervention]
ko_fi: interventionphp
custom: https://paypal.me/interventionio

24
.github/images/support.svg vendored Normal file
View File

@@ -0,0 +1,24 @@
<svg width="160" height="20" viewBox="0 0 160 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2_27)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M3 0C1.34315 0 0 1.34315 0 3V17C0 18.6569 1.34314 20 3 20H23V0H3Z" fill="#874240"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23 20H157C158.657 20 160 18.6569 160 17V3C160 1.34315 158.657 0 157 0H23V20Z" fill="#ED6A65"/>
<path d="M10.5244 15.4007L10.8235 15.6239L11.1226 15.4007C13.8256 13.383 15.1801 11.9798 15.852 10.9039C16.1932 10.3575 16.3608 9.89187 16.4383 9.47284C16.5036 9.1191 16.5013 8.80663 16.4996 8.56265C16.4993 8.52495 16.499 8.48888 16.499 8.45455C16.499 7.09727 15.3348 5.5 13.4113 5.5C12.4275 5.5 11.6649 5.99724 11.1724 6.45018C11.0395 6.57244 10.923 6.69437 10.8235 6.80749C10.7241 6.69437 10.6076 6.57244 10.4747 6.45018C9.98221 5.99724 9.21955 5.5 8.23579 5.5C6.31222 5.5 5.14805 7.09727 5.14805 8.45455C5.14805 8.48888 5.14779 8.52495 5.14751 8.56265C5.14573 8.80662 5.14345 9.1191 5.20881 9.47284C5.28624 9.89187 5.45388 10.3575 5.79507 10.9039C6.46695 11.9798 7.82149 13.383 10.5244 15.4007Z" fill="#ED6A65" stroke="white"/>
<g font-family="&#39;DejaVu Sans&#39;,Verdana,Geneva,sans-serif" font-size="11">
<text fill="#010101" fill-opacity=".3">
<tspan x="33" y="15">Support me on Ko-fi</tspan>
</text>
</g>
<g font-family="&#39;DejaVu Sans&#39;,Verdana,Geneva,sans-serif" font-size="11">
<text fill="#FFFFFF">
<tspan x="33" y="14">Support me on Ko-fi</tspan>
</text>
</g>
</g>
<defs>
<clipPath id="clip0_2_27">
<rect width="160" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -4,6 +4,7 @@
[![Latest Version](https://img.shields.io/packagist/v/intervention/image.svg)](https://packagist.org/packages/intervention/image)
[![Build Status](https://github.com/Intervention/image/actions/workflows/run-tests.yml/badge.svg)](https://github.com/Intervention/image/actions)
[![Monthly Downloads](https://img.shields.io/packagist/dm/intervention/image.svg)](https://packagist.org/packages/intervention/image/stats)
[![Support me on Ko-fi](https://raw.githubusercontent.com/Intervention/image/develop/.github/images/support.svg)](https://ko-fi.com/interventionphp)
Intervention Image is a **PHP image processing library** that provides a simple
and expressive way to create, edit, and compose images. It features a unified

View File

@@ -152,4 +152,14 @@ class Color extends AbstractColor
{
return false;
}
/**
* {@inheritdoc}
*
* @see ColorInterface::isClear()
*/
public function isClear(): bool
{
return false;
}
}

View File

@@ -120,4 +120,14 @@ class Color extends AbstractColor
{
return false;
}
/**
* {@inheritdoc}
*
* @see ColorInterface::isClear()
*/
public function isClear(): bool
{
return false;
}
}

View File

@@ -120,4 +120,14 @@ class Color extends AbstractColor
{
return false;
}
/**
* {@inheritdoc}
*
* @see ColorInterface::isClear()
*/
public function isClear(): bool
{
return false;
}
}

View File

@@ -178,4 +178,14 @@ class Color extends AbstractColor
{
return $this->alpha()->value() < $this->alpha()->max();
}
/**
* {@inheritdoc}
*
* @see ColorInterface::isClear()
*/
public function isClear(): bool
{
return $this->alpha()->value() == 0;
}
}

View File

@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Decoders;
use Intervention\Image\Drivers\SpecializableDecoder;
class EncodedImageObjectDecoder extends SpecializableDecoder
{
}

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Intervention\Image\Drivers\Gd;
use GdImage;
use Intervention\Image\Colors\Rgb\Channels\Alpha;
use Intervention\Image\Colors\Rgb\Color;
use Intervention\Image\Exceptions\ColorException;
use Intervention\Image\Geometry\Rectangle;
@@ -50,10 +51,7 @@ class Cloner
ColorInterface $background = new Color(255, 255, 255, 0)
): GdImage {
// define size
$size = match (true) {
is_null($size) => new Rectangle(imagesx($gd), imagesy($gd)),
default => $size,
};
$size = $size ? $size : new Rectangle(imagesx($gd), imagesy($gd));
// create new gd image with same size or new given size
$clone = imagecreatetruecolor($size->width(), $size->height());
@@ -70,6 +68,12 @@ class Cloner
imagealphablending($clone, true);
imagesavealpha($clone, true);
// set background image as transparent if alpha channel value if color is below .5
// comes into effect when the end format only supports binary transparency (like GIF)
if ($background->channel(Alpha::class)->value() < 128) {
imagecolortransparent($clone, $processor->colorToNative($background));
}
return $clone;
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Drivers\Gd\Decoders;
use Intervention\Image\EncodedImage;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ColorInterface;
class EncodedImageObjectDecoder extends BinaryImageDecoder
{
/**
* {@inheritdoc}
*
* @see DecoderInterface::decode()
*/
public function decode(mixed $input): ImageInterface|ColorInterface
{
if (!is_a($input, EncodedImage::class)) {
throw new DecoderException('Unable to decode input');
}
return parent::decode($input->toString());
}
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Drivers\Imagick\Decoders;
use Intervention\Image\EncodedImage;
use Intervention\Image\Exceptions\DecoderException;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ColorInterface;
class EncodedImageObjectDecoder extends BinaryImageDecoder
{
/**
* {@inheritdoc}
*
* @see DecoderInterface::decode()
*/
public function decode(mixed $input): ImageInterface|ColorInterface
{
if (!is_a($input, EncodedImage::class)) {
throw new DecoderException('Unable to decode input');
}
return parent::decode($input->toString());
}
}

View File

@@ -17,6 +17,13 @@ use Intervention\Image\Modifiers\RemoveAnimationModifier;
class NativeObjectDecoder extends SpecializableDecoder implements SpecializedInterface
{
protected const SUPPORTED_COLORSPACES = [
Imagick::COLORSPACE_SRGB,
Imagick::COLORSPACE_CMYK,
Imagick::COLORSPACE_HSL,
Imagick::COLORSPACE_HSB,
];
public function decode(mixed $input): ImageInterface|ColorInterface
{
if (!is_object($input)) {
@@ -34,6 +41,13 @@ class NativeObjectDecoder extends SpecializableDecoder implements SpecializedInt
$input = $input->coalesceImages();
}
// turn image into rgb if colorspace if other than CMYK, RGB, HSL or HSV.
// this prevents working on greyscale colorspace images when loading
// from PNG color type greyscale format.
if (!in_array($input->getImageColorspace(), self::SUPPORTED_COLORSPACES)) {
$input->setImageColorspace(Imagick::COLORSPACE_SRGB);
}
// create image object
$image = new Image(
$this->driver(),

View File

@@ -15,6 +15,7 @@ use Intervention\Image\Decoders\Base64ImageDecoder;
use Intervention\Image\Decoders\BinaryImageDecoder;
use Intervention\Image\Decoders\ColorObjectDecoder;
use Intervention\Image\Decoders\DataUriImageDecoder;
use Intervention\Image\Decoders\EncodedImageObjectDecoder;
use Intervention\Image\Decoders\FilePathImageDecoder;
use Intervention\Image\Decoders\FilePointerImageDecoder;
use Intervention\Image\Decoders\ImageObjectDecoder;
@@ -53,6 +54,7 @@ class InputHandler implements InputHandlerInterface
BinaryImageDecoder::class,
DataUriImageDecoder::class,
Base64ImageDecoder::class,
EncodedImageObjectDecoder::class,
];
/**

View File

@@ -97,4 +97,11 @@ interface ColorInterface
* @return bool
*/
public function isTransparent(): bool;
/**
* Determine whether the current color is completely transparent
*
* @return bool
*/
public function isClear(): bool;
}

View File

@@ -111,4 +111,10 @@ final class ColorTest extends BaseTestCase
$color = new Color(100, 50, 50, 0);
$this->assertFalse($color->isTransparent());
}
public function testIsClear(): void
{
$color = new Color(0, 0, 0, 0);
$this->assertFalse($color->isClear());
}
}

View File

@@ -108,4 +108,10 @@ final class ColorTest extends BaseTestCase
$color = new Color(0, 1, 0);
$this->assertFalse($color->isTransparent());
}
public function testIsClear(): void
{
$color = new Color(0, 1, 0);
$this->assertFalse($color->isClear());
}
}

View File

@@ -108,4 +108,10 @@ final class ColorTest extends BaseTestCase
$color = new Color(1, 0, 0);
$this->assertFalse($color->isTransparent());
}
public function testIsClear(): void
{
$color = new Color(0, 1, 0);
$this->assertFalse($color->isClear());
}
}

View File

@@ -163,4 +163,19 @@ final class ColorTest extends BaseTestCase
$color = new Color(255, 255, 255, 0);
$this->assertTrue($color->isTransparent());
}
public function testIsClear(): void
{
$color = new Color(255, 255, 255);
$this->assertFalse($color->isClear());
$color = new Color(255, 255, 255, 255);
$this->assertFalse($color->isClear());
$color = new Color(255, 255, 255, 85);
$this->assertFalse($color->isClear());
$color = new Color(255, 255, 255, 0);
$this->assertTrue($color->isClear());
}
}

View File

@@ -48,7 +48,7 @@ final class ClonerTest extends BaseTestCase
);
}
public function testCLoneBlended(): void
public function testCloneBlended(): void
{
$gd = imagecreatefromgif($this->getTestResourcePath('gradient.gif'));
$clone = Cloner::cloneBlended($gd, new Color(255, 0, 255, 255));

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers\Gd\Decoders;
use Intervention\Image\Drivers\Gd\Decoders\EncodedImageObjectDecoder;
use Intervention\Image\Drivers\Gd\Driver;
use Intervention\Image\EncodedImage;
use Intervention\Image\Image;
use Intervention\Image\Tests\ImagickTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
#[RequiresPhpExtension('gd')]
#[CoversClass(EncodedImageObjectDecoder::class)]
class EncodedImageObjectDecoderTest extends ImagickTestCase
{
protected EncodedImageObjectDecoder $decoder;
protected function setUp(): void
{
$this->decoder = new EncodedImageObjectDecoder();
$this->decoder->setDriver(new Driver());
}
public function testDecode(): void
{
$result = $this->decoder->decode(new EncodedImage($this->getTestResourceData()));
$this->assertInstanceOf(Image::class, $result);
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Decoders;
use Intervention\Image\Drivers\Imagick\Decoders\EncodedImageObjectDecoder;
use Intervention\Image\Drivers\Imagick\Driver;
use Intervention\Image\EncodedImage;
use Intervention\Image\Image;
use Intervention\Image\Tests\ImagickTestCase;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
#[RequiresPhpExtension('imagick')]
#[CoversClass(EncodedImageObjectDecoder::class)]
class EncodedImageObjectDecoderTest extends ImagickTestCase
{
protected EncodedImageObjectDecoder $decoder;
protected function setUp(): void
{
$this->decoder = new EncodedImageObjectDecoder();
$this->decoder->setDriver(new Driver());
}
public function testDecode(): void
{
$result = $this->decoder->decode(new EncodedImage($this->getTestResourceData()));
$this->assertInstanceOf(Image::class, $result);
}
}