Skip to content

Commit

Permalink
Merge pull request #1230 from franmomu/use_autorotate_from_imagine
Browse files Browse the repository at this point in the history
Use Autorotate Filter from Imagine library
  • Loading branch information
michellesanver authored Oct 4, 2019
2 parents 88775aa + 552c7f4 commit 1104665
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 238 deletions.
82 changes: 3 additions & 79 deletions Imagine/Filter/Loader/AutoRotateFilterLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

namespace Liip\ImagineBundle\Imagine\Filter\Loader;

use Imagine\Filter\Basic\Autorotate;
use Imagine\Image\ImageInterface;

/**
Expand All @@ -20,90 +21,13 @@
*/
class AutoRotateFilterLoader implements LoaderInterface
{
protected $orientationKeys = [
'exif.Orientation',
'ifd0.Orientation',
];

/**
* {@inheritdoc}
*/
public function load(ImageInterface $image, array $options = [])
{
if (null !== $orientation = $this->getOrientation($image)) {
if ($orientation < 1 || $orientation > 8) {
return $image;
}

// Rotates if necessary.
$degree = $this->calculateRotation($orientation);
if (0 !== $degree) {
$image->rotate($degree);
}

// Flips if necessary.
if ($this->isFlipped($orientation)) {
$image->flipHorizontally();
}
}
$filter = new Autorotate();

return $image;
}

/**
* calculates to rotation degree from the EXIF Orientation.
*
* @param int $orientation
*
* @return int
*/
private function calculateRotation($orientation)
{
switch ($orientation) {
case 1:
case 2:
return 0;
case 3:
case 4:
return 180;
case 5:
case 6:
return 90;
case 7:
case 8:
return -90;
}
}

/**
* @param ImageInterface $image
*
* @return int|null
*/
private function getOrientation(ImageInterface $image)
{
foreach ($this->orientationKeys as $orientationKey) {
$orientation = $image->metadata()->offsetGet($orientationKey);

if ($orientation) {
$image->metadata()->offsetSet($orientationKey, '1');

return (int) $orientation;
}
}

return null;
}

/**
* Returns true if the image is flipped, false otherwise.
*
* @param int $orientation
*
* @return bool
*/
private function isFlipped($orientation)
{
return \in_array((int) $orientation, [2, 4, 5, 7], true);
return $filter->apply($image);
}
}
164 changes: 5 additions & 159 deletions Tests/Imagine/Filter/Loader/AutoRotateFilterLoaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,170 +19,16 @@
*/
class AutoRotateFilterLoaderTest extends AbstractTest
{
private $orientationKey = 'exif.Orientation';

/*
* Possible rotation values
* 1: 0°
* 2: 0° flipped horizontally
* 3: 180°
* 4: 180° flipped horizontally
* 5: 90° flipped horizontally
* 6: 90°
* 7: -90° flipped horizontally
* 8: -90°
* No metadata means no rotation nor flip.
*/

/**
* 1: no rotation.
*/
public function testLoadExif1()
{
$this->loadExif('1', null, false);
}

/**
* 2: no rotation flipped horizontally.
*/
public function testLoadExif2()
{
$this->loadExif('2', null, true);
}

/**
* 3: 180°.
*/
public function testLoadExif3()
{
$this->loadExif('3', 180, false);
}

/**
* 4: 180° flipped horizontally.
*/
public function testLoadExif4()
{
$this->loadExif('4', 180, true);
}

/**
* 5: 90° flipped horizontally.
*/
public function testLoadExif5()
{
$this->loadExif('5', 90, true);
}

/**
* 6: 90°.
*/
public function testLoadExif6()
{
$this->loadExif('6', 90, false);
}

/**
* 7: -90° flipped horizontally.
*/
public function testLoadExif7()
{
$this->loadExif('7', -90, true);
}

/**
* 8: -90°.
*/
public function testLoadExif8()
{
$this->loadExif('8', -90, false);
}

/**
* Theoretically Orientation is `short` (uint16), so it could be anything
* from [0; 65535].
*/
public static function getInvalidOrientations()
{
return [[0, 9, 255, 65535]];
}

/**
* @dataProvider getInvalidOrientations
*
* @param string $orientation
*/
public function testLoadExifInvalid($orientation)
{
$this->loadExif($orientation, null, false);
}

/**
* No rotation info: no rotation nor flip.
*/
public function testLoadExifNull()
{
$this->loadExif(null, null, false);
}

/**
* Starts a test with expected results.
*
* @param string $exifValue The exif value to be returned by the metadata mock
* @param int|null $expectCallRotateValue {null|number} The expected rotation value, null if no rotation is expected
* @param bool $expectCallFlip True if a horizontal flip is expected, false otherwise
*/
private function loadExif($exifValue, $expectCallRotateValue, $expectCallFlip)
public function testUseAutorotateFromImagine(): void
{
$loader = new AutoRotateFilterLoader();

// Mocks the image and makes it use the fake meta data.
$image = $this->getImageInterfaceMock();

if (method_exists('\Imagine\Image\ImageInterface', 'metadata')) {
// Mocks the metadata and makes it return the expected exif value for the rotation.
// If $exifValue is null, it means the image doesn't contain any metadata.
$metaData = $this->getMetadataBagMock();

$metaData
->expects($this->atLeastOnce())
->method('offsetGet')
->willReturn($exifValue);

if ($exifValue && $exifValue > '1' && $exifValue <= 8) {
$metaData
->expects($this->once())
->method('offsetSet')
->with($this->orientationKey, '1');
}

$image
->expects($this->atLeastOnce())
->method('metadata')
->willReturn($metaData);
} else {
$jpg = file_get_contents(__DIR__.'/../../../Fixtures/assets/pixel_1x1_orientation_at_0x30.jpg');
// The byte with orientation is at offset 0x30 for this image
$jpg[0x30] = \chr((int) $exifValue);

$image
->expects($this->once())
->method('get')
->with('jpg')
->willReturn($jpg);
}

// Checks that rotate is called with $expectCallRotateValue, or not called at all if $expectCallRotateValue is null.
$image
->expects(null !== $expectCallRotateValue ? $this->once() : $this->never())
->method('rotate')
->with($expectCallRotateValue);

// Checks that rotate is called if $expectCallFlip is true, not called if $expectCallFlip is false.
$image
->expects($expectCallFlip ? $this->once() : $this->never())
->method('flipHorizontally');
$image->expects($this->once())
->method('metadata')
;

$loader->load($image);

}
}

0 comments on commit 1104665

Please sign in to comment.