Skip to content

Commit 9406561

Browse files
committed
Striping metadata
- added applicator `StripMeta` - applicators now yielding values instead of returning an image or null - cached image is now stored without exif data if the image has been modified by any other applicator
1 parent 3cca3ad commit 9406561

13 files changed

Lines changed: 155 additions & 49 deletions

src/Bridge/Nette/DI/ImageStorageExtension.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ public function getConfigSchema(): Schema
147147
[
148148
new Statement(Applicator\Orientation::class),
149149
new Statement(Applicator\Resize::class),
150-
new Statement(Applicator\Format::class), # must be last
150+
new Statement(Applicator\Format::class),
151+
new Statement(Applicator\StripMeta::class), # must be last
151152
],
152153
);
153154

src/Modifier/Applicator/Format.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
use Intervention\Image\Image;
99
use SixtyEightPublishers\FileStorage\Config\ConfigInterface;
1010
use SixtyEightPublishers\FileStorage\PathInfoInterface;
11-
use SixtyEightPublishers\ImageStorage\Config\Config;
1211
use SixtyEightPublishers\ImageStorage\Exception\InvalidArgumentException;
1312
use SixtyEightPublishers\ImageStorage\Helper\SupportedType;
1413
use SixtyEightPublishers\ImageStorage\Modifier\Collection\ModifierValues;
@@ -17,7 +16,7 @@
1716

1817
final class Format implements ModifierApplicatorInterface
1918
{
20-
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): ?Image
19+
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): iterable
2120
{
2221
$extension = $this->getFileExtension($image, $pathInfo);
2322
$quality = $values->getOptional(Quality::class);
@@ -29,7 +28,7 @@ public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues
2928
}
3029

3130
if (!$needEncode) {
32-
return null;
31+
return;
3332
}
3433

3534
if (in_array($extension, ['jpg', 'pjpg'], true)) {
@@ -43,7 +42,12 @@ public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues
4342
}
4443
}
4544

46-
return $image->encode($extension, (int) ($quality ?? $config[Config::ENCODE_QUALITY]));
45+
yield self::OutImage => $image;
46+
yield self::OutFormat => $extension;
47+
48+
if (null !== $quality) {
49+
yield self::OutQuality => (int) $quality;
50+
}
4751
}
4852

4953
private function getFileExtension(Image $image, PathInfoInterface $pathInfo): string

src/Modifier/Applicator/ModifierApplicatorInterface.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,19 @@
1111

1212
interface ModifierApplicatorInterface
1313
{
14+
public const OutImage = 'image';
15+
public const OutFormat = 'format';
16+
public const OutQuality = 'quality';
17+
1418
/**
15-
* Returns NULL of image is not modified
19+
* Allowed outputs:
20+
* "image": Image
21+
* "format": string
22+
* "quality": int
23+
*
24+
* If nothing changed, then nothing should be returned.
25+
*
26+
* @return iterable<string, mixed>
1627
*/
17-
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): ?Image;
28+
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): iterable;
1829
}

src/Modifier/Applicator/Orientation.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,24 @@
1414

1515
final class Orientation implements ModifierApplicatorInterface
1616
{
17-
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): ?Image
17+
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): iterable
1818
{
1919
$orientation = $values->getOptional(OrientationModifier::class);
2020

2121
if (!is_string($orientation) && !is_numeric($orientation)) {
22-
return null;
22+
return;
2323
}
2424

2525
if ('auto' === $orientation) {
2626
$exifOrientation = $image->exif('Orientation');
2727

2828
if (2 <= $exifOrientation && 8 >= $exifOrientation) {
29-
return $image->orientate();
29+
yield self::OutImage => $image->orientate();
3030
}
3131

32-
return null;
32+
return;
3333
}
3434

35-
return $image->rotate((float) $orientation);
35+
yield self::OutImage => $image->rotate((float) $orientation);
3636
}
3737
}

src/Modifier/Applicator/Resize.php

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
final class Resize implements ModifierApplicatorInterface
2929
{
30-
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): ?Image
30+
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): iterable
3131
{
3232
$width = $values->getOptional(Width::class);
3333
$height = $values->getOptional(Height::class);
@@ -70,28 +70,24 @@ public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues
7070
$height = (int) ($height * $pd);
7171

7272
if ($width === $imageWidth && $height === $imageHeight) {
73-
return null;
73+
return;
7474
}
7575

76-
switch ($fit) {
77-
case Fit::CONTAIN:
78-
return $image->resize($width, $height, static function (Constraint $constraint) {
79-
$constraint->aspectRatio();
80-
});
81-
82-
case Fit::STRETCH:
83-
return $image->resize($width, $height);
84-
case Fit::FILL:
85-
return $image->resize($width, $height, static function (Constraint $constraint) {
86-
$constraint->aspectRatio();
87-
$constraint->upsize();
88-
})->resizeCanvas($width, $height, 'center');
89-
}
90-
91-
if (0 === strncmp($fit, 'crop-', 5)) {
92-
$fit = substr($fit, 5);
93-
}
94-
95-
return $image->fit($width, $height, null, $fit);
76+
yield self::OutImage => match ($fit) {
77+
Fit::CONTAIN => $image->resize($width, $height, static function (Constraint $constraint) {
78+
$constraint->aspectRatio();
79+
}),
80+
Fit::STRETCH => $image->resize($width, $height),
81+
Fit::FILL => $image->resize($width, $height, static function (Constraint $constraint) {
82+
$constraint->aspectRatio();
83+
$constraint->upsize();
84+
})->resizeCanvas($width, $height, 'center'),
85+
default => $image->fit(
86+
$width,
87+
$height,
88+
null,
89+
0 === strncmp($fit, 'crop-', 5) ? substr($fit, 5) : $fit,
90+
),
91+
};
9692
}
9793
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SixtyEightPublishers\ImageStorage\Modifier\Applicator;
6+
7+
use Imagick;
8+
use ImagickException;
9+
use Intervention\Image\Image;
10+
use SixtyEightPublishers\FileStorage\Config\ConfigInterface;
11+
use SixtyEightPublishers\FileStorage\PathInfoInterface;
12+
use SixtyEightPublishers\ImageStorage\Modifier\Collection\ModifierValues;
13+
14+
final class StripMeta implements ModifierApplicatorInterface
15+
{
16+
/**
17+
* @throws ImagickException
18+
*/
19+
public function apply(Image $image, PathInfoInterface $pathInfo, ModifierValues $values, ConfigInterface $config): iterable
20+
{
21+
if (true !== $values->getOptional('__stripMeta', false)) {
22+
return [];
23+
}
24+
25+
$core = $image->getCore();
26+
27+
if (!($core instanceof Imagick)) {
28+
return [];
29+
}
30+
31+
$profiles = $core->getImageProfiles('icc');
32+
33+
$core->stripImage();
34+
35+
if (isset($profiles['icc'])) {
36+
$core->profileImage('icc', $profiles['icc']);
37+
}
38+
39+
return [];
40+
}
41+
}

src/Modifier/Collection/ModifierValues.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function getOptional(string $name, mixed $default = null): mixed
4444
return $this->has($name) ? $this->values[$name] : $default;
4545
}
4646

47-
private function add(string $name, mixed $value): void
47+
public function add(string $name, mixed $value): void
4848
{
4949
$this->values[$name] = $value;
5050
}

src/Modifier/Facade/ModifierFacade.php

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public function getCodec(): CodecInterface
102102
return $this->codec;
103103
}
104104

105-
public function modifyImage(Image $image, PathInfoInterface $info, string|array $modifiers): ModifyResult
105+
public function modifyImage(Image $image, PathInfoInterface $info, string|array $modifiers, bool $stripMeta = false): ModifyResult
106106
{
107107
if (!is_array($modifiers)) {
108108
$modifiers = $this->getCodec()->decode(new PresetValue($modifiers));
@@ -114,24 +114,46 @@ public function modifyImage(Image $image, PathInfoInterface $info, string|array
114114

115115
$values = $this->modifierCollection->parseValues($modifiers);
116116

117+
if ($stripMeta) {
118+
$values->add('__stripMeta', true);
119+
}
120+
117121
foreach ($this->validators as $validator) {
118122
$validator->validate($values, $this->config);
119123
}
120124

121125
$modified = false;
126+
$encodeFormat = null;
127+
$encodeQuality = null;
122128

123129
foreach ($this->applicators as $applicator) {
124-
$modifiedImage = $applicator->apply($image, $info, $values, $this->config);
130+
foreach ($applicator->apply($image, $info, $values, $this->config) as $key => $value) {
131+
if (ModifierApplicatorInterface::OutImage === $key && $value instanceof Image) {
132+
$image = $value;
133+
$modified = true;
134+
135+
continue;
136+
}
137+
138+
if (ModifierApplicatorInterface::OutFormat === $key) {
139+
$encodeFormat = $value;
140+
$modified = true;
141+
142+
continue;
143+
}
125144

126-
if (null !== $modifiedImage) {
127-
$image = $modifiedImage;
128-
$modified = true;
145+
if (ModifierApplicatorInterface::OutQuality === $key) {
146+
$encodeQuality = $value;
147+
$modified = true;
148+
}
129149
}
130150
}
131151

132152
return new ModifyResult(
133153
image: $image,
134154
modified: $modified,
155+
encodeFormat: $encodeFormat,
156+
encodeQuality: $encodeQuality,
135157
);
136158
}
137159
}

src/Modifier/Facade/ModifierFacadeInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,5 @@ public function getCodec(): CodecInterface;
4141
/**
4242
* @param string|array<string, string|numeric|bool> $modifiers
4343
*/
44-
public function modifyImage(Image $image, PathInfoInterface $info, string|array $modifiers): ModifyResult;
44+
public function modifyImage(Image $image, PathInfoInterface $info, string|array $modifiers, bool $stripMeta = false): ModifyResult;
4545
}

src/Modifier/Facade/ModifyResult.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@ final class ModifyResult
1111
public function __construct(
1212
public readonly Image $image,
1313
public readonly bool $modified,
14+
public readonly ?string $encodeFormat,
15+
public readonly ?int $encodeQuality,
1416
) {}
1517
}

0 commit comments

Comments
 (0)