1
0
mirror of https://github.com/Intervention/image.git synced 2025-08-29 08:40:33 +02:00

Implement image resolution management

This commit is contained in:
Oliver Vogel
2023-10-28 10:44:56 +02:00
parent a445ef3955
commit 0f846ce173
14 changed files with 202 additions and 0 deletions

View File

@@ -385,6 +385,13 @@ abstract class AbstractImage implements ImageInterface
return is_null($query) ? $this->exif : $this->exif->get($query);
}
public function setResolution(float $x, float $y): ImageInterface
{
return $this->modify(
$this->resolveDriverClass('Modifiers\ResolutionModifier', $x, $y)
);
}
public function destroy(): void
{
$this->modify(

View File

@@ -13,6 +13,8 @@ use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ProfileInterface;
use Intervention\Image\Interfaces\ResolutionInterface;
use Intervention\Image\Resolution;
use IteratorAggregate;
use Traversable;
@@ -78,6 +80,16 @@ class Image extends AbstractImage implements ImageInterface, IteratorAggregate
return imagesy($this->frame()->core());
}
/**
* {@inheritdoc}
*
* @see ImageInterface::resolution()
*/
public function resolution(): ResolutionInterface
{
return new Resolution(...imageresolution($this->frame()->core()));
}
public function pickColor(int $x, int $y, int $frame_key = 0): ColorInterface
{
return $this->integerToColor(

View File

@@ -0,0 +1,23 @@
<?php
namespace Intervention\Image\Drivers\Gd\Modifiers;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
class ResolutionModifier implements ModifierInterface
{
public function __construct(protected float $x, protected float $y)
{
//
}
public function apply(ImageInterface $image): ImageInterface
{
foreach ($image as $frame) {
imageresolution($frame->core(), $this->x, $this->y);
}
return $image;
}
}

View File

@@ -14,6 +14,10 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
public function apply(ImageInterface $image): ImageInterface
{
foreach ($image as $frame) {
// retain resolution because imagerotate() seems to reset density to 96dpi
$resolution = imageresolution($frame->core());
// rotate image
$frame->setCore(
imagerotate(
$frame->core(),
@@ -21,6 +25,9 @@ class RotateModifier extends AbstractRotateModifier implements ModifierInterface
$this->colorToInteger($this->backgroundColor())
)
);
// restore original image resolution
imageresolution($frame->core(), $resolution[0], $resolution[1]);
}
return $image;

View File

@@ -19,6 +19,8 @@ use Intervention\Image\Interfaces\ColorspaceInterface;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ProfileInterface;
use Intervention\Image\Interfaces\ResolutionInterface;
use Intervention\Image\Resolution;
use Iterator;
class Image extends AbstractImage implements ImageInterface, Iterator
@@ -134,6 +136,16 @@ class Image extends AbstractImage implements ImageInterface, Iterator
return $this->frame()->core()->getImageHeight();
}
/**
* {@inheritdoc}
*
* @see ImageInterface::resolution()
*/
public function resolution(): ResolutionInterface
{
return new Resolution(...$this->frame()->core()->getImageResolution());
}
/**
* {@inheritdoc}
*

View File

@@ -0,0 +1,26 @@
<?php
namespace Intervention\Image\Drivers\Imagick\Modifiers;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Traits\CanCheckType;
class ResolutionModifier implements ModifierInterface
{
use CanCheckType;
public function __construct(protected float $x, protected float $y)
{
//
}
public function apply(ImageInterface $image): ImageInterface
{
$imagick = $this->failIfNotClass($image, Image::class)->getImagick();
$imagick->setImageResolution($this->x, $this->y);
return $image;
}
}

View File

@@ -386,6 +386,22 @@ interface ImageInterface extends Traversable, Countable
*/
public function height(): int;
/**
* Return image resolution/density
*
* @return ResolutionInterface
*/
public function resolution(): ResolutionInterface;
/**
* Se the image resolution/density
*
* @param float $x
* @param float $y
* @return ImageInterface
*/
public function setResolution(float $x, float $y): ImageInterface;
/**
* Destroy current image instance and free up memory
*

View File

@@ -0,0 +1,9 @@
<?php
namespace Intervention\Image\Interfaces;
interface ResolutionInterface
{
public function x(): float;
public function y(): float;
}

23
src/Resolution.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
namespace Intervention\Image;
use Intervention\Image\Interfaces\ResolutionInterface;
class Resolution implements ResolutionInterface
{
public function __construct(protected float $x, protected float $y)
{
//
}
public function x(): float
{
return $this->x;
}
public function y(): float
{
return $this->y;
}
}

View File

@@ -11,6 +11,7 @@ use Intervention\Image\Interfaces\EncoderInterface;
use Intervention\Image\Interfaces\FrameInterface;
use Intervention\Image\Interfaces\ImageInterface;
use Intervention\Image\Interfaces\ModifierInterface;
use Intervention\Image\Resolution;
use Intervention\Image\Tests\TestCase;
use Mockery;

View File

@@ -12,6 +12,7 @@ use Intervention\Image\Colors\Rgb\Colorspace as RgbColorspace;
use Intervention\Image\Colors\Cmyk\Colorspace as CmykColorspace;
use Intervention\Image\Exceptions\NotSupportedException;
use Intervention\Image\Exceptions\AnimationException;
use Intervention\Image\Resolution;
/**
* @requires extension gd
@@ -152,4 +153,10 @@ class ImageTest extends TestCase
$this->expectException(NotSupportedException::class);
$this->image->setColorspace(new CmykColorspace());
}
public function testResolution(): void
{
$result = $this->image->resolution();
$this->assertInstanceOf(Resolution::class, $result);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Intervention\Image\Tests\Drivers\Gd\Modifiers;
use Intervention\Image\Drivers\Gd\Modifiers\ResolutionModifier;
use Intervention\Image\Tests\TestCase;
use Intervention\Image\Tests\Traits\CanCreateGdTestImage;
/**
* @requires extension gd
* @covers \Intervention\Image\Drivers\Gd\Modifiers\ResolutionModifier
*/
class ResolutionModifierTest extends TestCase
{
use CanCreateGdTestImage;
public function testResolutionChange(): void
{
$image = $this->createTestImage('test.jpg');
$this->assertEquals(72.0, $image->resolution()->x());
$this->assertEquals(72.0, $image->resolution()->y());
$image->modify(new ResolutionModifier(1, 2));
$this->assertEquals(1.0, $image->resolution()->x());
$this->assertEquals(2.0, $image->resolution()->y());
}
}

View File

@@ -12,6 +12,7 @@ use Intervention\Image\Drivers\Imagick\Image;
use Intervention\Image\Exceptions\AnimationException;
use Intervention\Image\Exceptions\ColorException;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Resolution;
use Intervention\Image\Tests\TestCase;
/**
@@ -155,4 +156,10 @@ class ImageTest extends TestCase
$this->expectException(ColorException::class);
$image->profile();
}
public function testResolution(): void
{
$result = $this->image->resolution();
$this->assertInstanceOf(Resolution::class, $result);
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace Intervention\Image\Tests\Drivers\Imagick\Modifiers;
use Intervention\Image\Drivers\Imagick\Modifiers\ResolutionModifier;
use Intervention\Image\Tests\TestCase;
use Intervention\Image\Tests\Traits\CanCreateImagickTestImage;
/**
* @requires extension gd
* @covers \Intervention\Image\Drivers\Imagick\Modifiers\ResolutionModifier
*/
class ResolutionModifierTest extends TestCase
{
use CanCreateImagickTestImage;
public function testResolutionChange(): void
{
$image = $this->createTestImage('test.jpg');
$this->assertEquals(72.0, $image->resolution()->x());
$this->assertEquals(72.0, $image->resolution()->y());
$image->modify(new ResolutionModifier(1, 2));
$this->assertEquals(1.0, $image->resolution()->x());
$this->assertEquals(2.0, $image->resolution()->y());
}
}