Skip to content

Commit

Permalink
Implement image resolution management
Browse files Browse the repository at this point in the history
  • Loading branch information
olivervogel committed Oct 28, 2023
1 parent a445ef3 commit 0f846ce
Show file tree
Hide file tree
Showing 14 changed files with 202 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/Drivers/Abstract/AbstractImage.php
Expand Up @@ -385,6 +385,13 @@ public function exif(?string $query = null): mixed
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(
Expand Down
12 changes: 12 additions & 0 deletions src/Drivers/Gd/Image.php
Expand Up @@ -13,6 +13,8 @@
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;

Expand Down Expand Up @@ -78,6 +80,16 @@ public function height(): int
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(
Expand Down
23 changes: 23 additions & 0 deletions src/Drivers/Gd/Modifiers/ResolutionModifier.php
@@ -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;
}
}
7 changes: 7 additions & 0 deletions src/Drivers/Gd/Modifiers/RotateModifier.php
Expand Up @@ -14,13 +14,20 @@ 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(),
$this->rotationAngle(),
$this->colorToInteger($this->backgroundColor())
)
);

// restore original image resolution
imageresolution($frame->core(), $resolution[0], $resolution[1]);
}

return $image;
Expand Down
12 changes: 12 additions & 0 deletions src/Drivers/Imagick/Image.php
Expand Up @@ -19,6 +19,8 @@
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
Expand Down Expand Up @@ -134,6 +136,16 @@ public function height(): int
return $this->frame()->core()->getImageHeight();
}

/**
* {@inheritdoc}
*
* @see ImageInterface::resolution()
*/
public function resolution(): ResolutionInterface
{
return new Resolution(...$this->frame()->core()->getImageResolution());
}

/**
* {@inheritdoc}
*
Expand Down
26 changes: 26 additions & 0 deletions src/Drivers/Imagick/Modifiers/ResolutionModifier.php
@@ -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;
}
}
16 changes: 16 additions & 0 deletions src/Interfaces/ImageInterface.php
Expand Up @@ -386,6 +386,22 @@ public function width(): int;
*/
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
*
Expand Down
9 changes: 9 additions & 0 deletions src/Interfaces/ResolutionInterface.php
@@ -0,0 +1,9 @@
<?php

namespace Intervention\Image\Interfaces;

interface ResolutionInterface
{
public function x(): float;
public function y(): float;
}
23 changes: 23 additions & 0 deletions src/Resolution.php
@@ -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;
}
}
1 change: 1 addition & 0 deletions tests/Drivers/Abstract/AbstractImageTest.php
Expand Up @@ -11,6 +11,7 @@
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;

Expand Down
7 changes: 7 additions & 0 deletions tests/Drivers/Gd/ImageTest.php
Expand Up @@ -12,6 +12,7 @@
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
Expand Down Expand Up @@ -152,4 +153,10 @@ public function testSetColorspace(): void
$this->expectException(NotSupportedException::class);
$this->image->setColorspace(new CmykColorspace());
}

public function testResolution(): void
{
$result = $this->image->resolution();
$this->assertInstanceOf(Resolution::class, $result);
}
}
26 changes: 26 additions & 0 deletions tests/Drivers/Gd/Modifiers/ResolutionModifierTest.php
@@ -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());
}
}
7 changes: 7 additions & 0 deletions tests/Drivers/Imagick/ImageTest.php
Expand Up @@ -12,6 +12,7 @@
use Intervention\Image\Exceptions\AnimationException;
use Intervention\Image\Exceptions\ColorException;
use Intervention\Image\Geometry\Rectangle;
use Intervention\Image\Resolution;
use Intervention\Image\Tests\TestCase;

/**
Expand Down Expand Up @@ -155,4 +156,10 @@ public function testRemoveProfile(): void
$this->expectException(ColorException::class);
$image->profile();
}

public function testResolution(): void
{
$result = $this->image->resolution();
$this->assertInstanceOf(Resolution::class, $result);
}
}
26 changes: 26 additions & 0 deletions tests/Drivers/Imagick/Modifiers/ResolutionModifierTest.php
@@ -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());
}
}

0 comments on commit 0f846ce

Please sign in to comment.