Skip to content

Commit da09b4c

Browse files
authored
Fix failing auto rotation with sequential access (#89)
1 parent e82935d commit da09b4c

File tree

3 files changed

+47
-6
lines changed

3 files changed

+47
-6
lines changed

src/Decoders/NativeObjectDecoder.php

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Intervention\Image\Drivers\SpecializableDecoder;
88
use Intervention\Image\Drivers\Vips\Core;
9+
use Intervention\Image\Drivers\Vips\Modifiers\AlignRotationModifier;
910
use Intervention\Image\Exceptions\DecoderException;
1011
use Intervention\Image\Exceptions\RuntimeException;
1112
use Intervention\Image\Image;
@@ -35,17 +36,17 @@ public function decode(mixed $input): ImageInterface|ColorInterface
3536
throw new DecoderException('Unable to decode input');
3637
}
3738

38-
// auto-rotate
39-
if ($this->driver()->config()->autoOrientation === true) {
40-
$input = $input->autorot();
41-
}
42-
4339
// build image instance
4440
$image = new Image(
4541
$this->driver(),
4642
new Core($input)
4743
);
4844

45+
// auto-rotate
46+
if ($this->driver()->config()->autoOrientation === true && $this->exifRotation($input) > 1) {
47+
$image->modify(new AlignRotationModifier());
48+
}
49+
4950
// set media type on origin
5051
if ($mediaType = $this->vipsMediaType($input)) {
5152
$image->origin()->setMediaType($mediaType);
@@ -96,4 +97,22 @@ protected function vipsMediaType(VipsImage $vips): ?MediaType
9697
default => null
9798
};
9899
}
100+
101+
/**
102+
* Return the exif rotation of the given image or null if there isn't any
103+
*/
104+
protected function exifRotation(VipsImage $vips): ?int
105+
{
106+
if (!in_array('orientation', $vips->getFields())) {
107+
return null;
108+
}
109+
110+
try {
111+
$orientation = $vips->get('orientation');
112+
} catch (VipsException) {
113+
return null;
114+
}
115+
116+
return is_int($orientation) ? $orientation : null;
117+
}
99118
}

src/Modifiers/AlignRotationModifier.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Intervention\Image\Drivers\Vips\Modifiers;
66

7+
use Intervention\Image\Drivers\Vips\Core;
78
use Intervention\Image\Interfaces\ImageInterface;
89
use Intervention\Image\Interfaces\SpecializedInterface;
910
use Intervention\Image\Modifiers\AlignRotationModifier as GenericAlignRotationModifier;
@@ -18,7 +19,8 @@ class AlignRotationModifier extends GenericAlignRotationModifier implements Spec
1819
public function apply(ImageInterface $image): ImageInterface
1920
{
2021
$image->core()->setNative(
21-
$image->core()->native()->autorot()
22+
// autorot() does not seem to work with the default sequential access of this library
23+
Core::ensureInMemory($image->core())->native()->autorot()
2224
);
2325

2426
return $image;

tests/Unit/Modifiers/AlignRotationModifierTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,29 @@ public function testApply(): void
1515
$image = (new ImageManager(Driver::class, autoOrientation: false))->read(
1616
$this->getTestResourcePath('orientation.jpg')
1717
);
18+
1819
$this->assertColor(250, 2, 3, 255, $image->pickColor(3, 3));
1920
$result = $image->orient();
2021
$this->assertColor(1, 0, 254, 255, $image->pickColor(3, 3));
2122
$this->assertColor(1, 0, 254, 255, $result->pickColor(3, 3));
2223
}
24+
25+
/**
26+
* According to libvips/libvips#4475 you can't use autorot with
27+
* orientated JPEGs and sequential access. This test checks the negative
28+
* scenario, before the fix.
29+
*/
30+
public function testAutoOrientationSave(): void
31+
{
32+
$tmpFile = sys_get_temp_dir() . '/out.jpg';
33+
34+
(new ImageManager(Driver::class, autoOrientation: true))->read(
35+
$this->getTestResourcePath('orientation.jpg')
36+
)->save($tmpFile);
37+
38+
$this->assertFileExists($tmpFile);
39+
40+
// remove tmp file
41+
unlink($tmpFile);
42+
}
2343
}

0 commit comments

Comments
 (0)