diff --git a/src/Config.php b/src/Config.php index da8edf01..0bd1b3b7 100644 --- a/src/Config.php +++ b/src/Config.php @@ -14,13 +14,16 @@ class Config * @param bool $autoOrientation * @param bool $decodeAnimation * @param mixed $blendingColor + * @param bool $strip * @return void */ public function __construct( public bool $autoOrientation = true, public bool $decodeAnimation = true, public mixed $blendingColor = 'ffffff', + public bool $strip = false, ) { + // } /** diff --git a/src/Drivers/Imagick/Encoders/AvifEncoder.php b/src/Drivers/Imagick/Encoders/AvifEncoder.php index 32b8ef48..64cb4aeb 100644 --- a/src/Drivers/Imagick/Encoders/AvifEncoder.php +++ b/src/Drivers/Imagick/Encoders/AvifEncoder.php @@ -5,6 +5,7 @@ namespace Intervention\Image\Drivers\Imagick\Encoders; use Imagick; +use Intervention\Image\Drivers\Imagick\Modifiers\StripMetaModifier; use Intervention\Image\EncodedImage; use Intervention\Image\Encoders\AvifEncoder as GenericAvifEncoder; use Intervention\Image\Interfaces\EncodedImageInterface; @@ -18,6 +19,11 @@ public function encode(ImageInterface $image): EncodedImageInterface $format = 'AVIF'; $compression = Imagick::COMPRESSION_ZIP; + // strip meta data + if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) { + $image->modify(new StripMetaModifier()); + } + $imagick = $image->core()->native(); $imagick->setFormat($format); $imagick->setImageFormat($format); diff --git a/src/Drivers/Imagick/Encoders/HeicEncoder.php b/src/Drivers/Imagick/Encoders/HeicEncoder.php index 70e56004..471edb1f 100644 --- a/src/Drivers/Imagick/Encoders/HeicEncoder.php +++ b/src/Drivers/Imagick/Encoders/HeicEncoder.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Modifiers\StripMetaModifier; use Intervention\Image\EncodedImage; use Intervention\Image\Encoders\HeicEncoder as GenericHeicEncoder; use Intervention\Image\Interfaces\EncodedImageInterface; @@ -16,6 +17,11 @@ public function encode(ImageInterface $image): EncodedImageInterface { $format = 'HEIC'; + // strip meta data + if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) { + $image->modify(new StripMetaModifier()); + } + $imagick = $image->core()->native(); $imagick->setFormat($format); $imagick->setImageFormat($format); diff --git a/src/Drivers/Imagick/Encoders/Jpeg2000Encoder.php b/src/Drivers/Imagick/Encoders/Jpeg2000Encoder.php index 5c4bd59e..16f6593b 100644 --- a/src/Drivers/Imagick/Encoders/Jpeg2000Encoder.php +++ b/src/Drivers/Imagick/Encoders/Jpeg2000Encoder.php @@ -5,6 +5,7 @@ namespace Intervention\Image\Drivers\Imagick\Encoders; use Imagick; +use Intervention\Image\Drivers\Imagick\Modifiers\StripMetaModifier; use Intervention\Image\EncodedImage; use Intervention\Image\Encoders\Jpeg2000Encoder as GenericJpeg2000Encoder; use Intervention\Image\Interfaces\ImageInterface; @@ -18,6 +19,11 @@ public function encode(ImageInterface $image): EncodedImageInterface $format = 'JP2'; $compression = Imagick::COMPRESSION_JPEG; + // strip meta data + if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) { + $image->modify(new StripMetaModifier()); + } + $imagick = $image->core()->native(); $imagick->setImageBackgroundColor('white'); $imagick->setBackgroundColor('white'); diff --git a/src/Drivers/Imagick/Encoders/JpegEncoder.php b/src/Drivers/Imagick/Encoders/JpegEncoder.php index 72cab7e8..e2365f3c 100644 --- a/src/Drivers/Imagick/Encoders/JpegEncoder.php +++ b/src/Drivers/Imagick/Encoders/JpegEncoder.php @@ -5,6 +5,7 @@ namespace Intervention\Image\Drivers\Imagick\Encoders; use Imagick; +use Intervention\Image\Drivers\Imagick\Modifiers\StripMetaModifier; use Intervention\Image\EncodedImage; use Intervention\Image\Encoders\JpegEncoder as GenericJpegEncoder; use Intervention\Image\Interfaces\EncodedImageInterface; @@ -30,6 +31,12 @@ public function encode(ImageInterface $image): EncodedImageInterface // possible full transparent colors as black $background->setColorValue(Imagick::COLOR_ALPHA, 1); + // strip meta data + if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) { + $image->modify(new StripMetaModifier()); + } + + /** @var Imagick $imagick */ $imagick = $image->core()->native(); $imagick->setImageBackgroundColor($background); $imagick->setBackgroundColor($background); diff --git a/src/Drivers/Imagick/Encoders/TiffEncoder.php b/src/Drivers/Imagick/Encoders/TiffEncoder.php index a03e0ae3..46e66536 100644 --- a/src/Drivers/Imagick/Encoders/TiffEncoder.php +++ b/src/Drivers/Imagick/Encoders/TiffEncoder.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Modifiers\StripMetaModifier; use Intervention\Image\EncodedImage; use Intervention\Image\Encoders\TiffEncoder as GenericTiffEncoder; use Intervention\Image\Interfaces\ImageInterface; @@ -16,6 +17,11 @@ public function encode(ImageInterface $image): EncodedImageInterface { $format = 'TIFF'; + // strip meta data + if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) { + $image->modify(new StripMetaModifier()); + } + $imagick = $image->core()->native(); $imagick->setFormat($format); $imagick->setImageFormat($format); diff --git a/src/Drivers/Imagick/Encoders/WebpEncoder.php b/src/Drivers/Imagick/Encoders/WebpEncoder.php index 5ac09f4e..b65be3bc 100644 --- a/src/Drivers/Imagick/Encoders/WebpEncoder.php +++ b/src/Drivers/Imagick/Encoders/WebpEncoder.php @@ -6,6 +6,7 @@ use Imagick; use ImagickPixel; +use Intervention\Image\Drivers\Imagick\Modifiers\StripMetaModifier; use Intervention\Image\EncodedImage; use Intervention\Image\Encoders\WebpEncoder as GenericWebpEncoder; use Intervention\Image\Interfaces\EncodedImageInterface; @@ -19,6 +20,11 @@ public function encode(ImageInterface $image): EncodedImageInterface $format = 'WEBP'; $compression = Imagick::COMPRESSION_ZIP; + // strip meta data + if ($this->strip || (is_null($this->strip) && $this->driver()->config()->strip)) { + $image->modify(new StripMetaModifier()); + } + $imagick = $image->core()->native(); $imagick->setImageBackgroundColor(new ImagickPixel('transparent')); diff --git a/src/Drivers/Imagick/Modifiers/StripMetaModifier.php b/src/Drivers/Imagick/Modifiers/StripMetaModifier.php new file mode 100644 index 00000000..58d1e7a1 --- /dev/null +++ b/src/Drivers/Imagick/Modifiers/StripMetaModifier.php @@ -0,0 +1,34 @@ +core()->native()->getImageProfiles('icc'); + + // remove meta data + $image->core()->native()->stripImage(); + $image->setExif(new Collection()); + + if ($profiles !== []) { + // re-apply icc profiles + $image->core()->native()->profileImage("icc", $profiles['icc']); + } + return $image; + } +} diff --git a/src/Encoders/AvifEncoder.php b/src/Encoders/AvifEncoder.php index 7799950d..8a724247 100644 --- a/src/Encoders/AvifEncoder.php +++ b/src/Encoders/AvifEncoder.php @@ -12,9 +12,13 @@ class AvifEncoder extends SpecializableEncoder * Create new encoder object * * @param int $quality + * @param null|bool $strip Strip EXIF metadata * @return void */ - public function __construct(public int $quality = self::DEFAULT_QUALITY) - { + public function __construct( + public int $quality = self::DEFAULT_QUALITY, + public ?bool $strip = null + ) { + // } } diff --git a/src/Encoders/BmpEncoder.php b/src/Encoders/BmpEncoder.php index 2d25da20..46dbc9f5 100644 --- a/src/Encoders/BmpEncoder.php +++ b/src/Encoders/BmpEncoder.php @@ -10,5 +10,6 @@ class BmpEncoder extends SpecializableEncoder { public function __construct() { + // } } diff --git a/src/Encoders/GifEncoder.php b/src/Encoders/GifEncoder.php index 65f0224f..f088c759 100644 --- a/src/Encoders/GifEncoder.php +++ b/src/Encoders/GifEncoder.php @@ -16,5 +16,6 @@ class GifEncoder extends SpecializableEncoder */ public function __construct(public bool $interlaced = false) { + // } } diff --git a/src/Encoders/HeicEncoder.php b/src/Encoders/HeicEncoder.php index 2d129a35..965d07fa 100644 --- a/src/Encoders/HeicEncoder.php +++ b/src/Encoders/HeicEncoder.php @@ -12,9 +12,13 @@ class HeicEncoder extends SpecializableEncoder * Create new encoder object * * @param int $quality + * @param null|bool $strip Strip EXIF metadata * @return void */ - public function __construct(public int $quality = self::DEFAULT_QUALITY) - { + public function __construct( + public int $quality = self::DEFAULT_QUALITY, + public ?bool $strip = null + ) { + // } } diff --git a/src/Encoders/Jpeg2000Encoder.php b/src/Encoders/Jpeg2000Encoder.php index dea11ef2..8d89a070 100644 --- a/src/Encoders/Jpeg2000Encoder.php +++ b/src/Encoders/Jpeg2000Encoder.php @@ -12,9 +12,13 @@ class Jpeg2000Encoder extends SpecializableEncoder * Create new encoder object * * @param int $quality + * @param null|bool $strip Strip EXIF metadata * @return void */ - public function __construct(public int $quality = self::DEFAULT_QUALITY) - { + public function __construct( + public int $quality = self::DEFAULT_QUALITY, + public ?bool $strip = null + ) { + // } } diff --git a/src/Encoders/JpegEncoder.php b/src/Encoders/JpegEncoder.php index eaf520e1..cbc5bc3e 100644 --- a/src/Encoders/JpegEncoder.php +++ b/src/Encoders/JpegEncoder.php @@ -13,11 +13,14 @@ class JpegEncoder extends SpecializableEncoder * * @param int $quality * @param bool $progressive + * @param null|bool $strip Strip EXIF metadata * @return void */ public function __construct( public int $quality = self::DEFAULT_QUALITY, - public bool $progressive = false + public bool $progressive = false, + public ?bool $strip = null ) { + // } } diff --git a/src/Encoders/PngEncoder.php b/src/Encoders/PngEncoder.php index b3376e0d..c2530278 100644 --- a/src/Encoders/PngEncoder.php +++ b/src/Encoders/PngEncoder.php @@ -17,5 +17,6 @@ class PngEncoder extends SpecializableEncoder */ public function __construct(public bool $interlaced = false, public bool $indexed = false) { + // } } diff --git a/src/Encoders/TiffEncoder.php b/src/Encoders/TiffEncoder.php index 203baf8c..a5fe0c82 100644 --- a/src/Encoders/TiffEncoder.php +++ b/src/Encoders/TiffEncoder.php @@ -12,9 +12,13 @@ class TiffEncoder extends SpecializableEncoder * Create new encoder object * * @param int $quality + * @param null|bool $strip Strip EXIF metadata * @return void */ - public function __construct(public int $quality = self::DEFAULT_QUALITY) - { + public function __construct( + public int $quality = self::DEFAULT_QUALITY, + public ?bool $strip = null + ) { + // } } diff --git a/src/Encoders/WebpEncoder.php b/src/Encoders/WebpEncoder.php index 5530b6e6..7a9b570b 100644 --- a/src/Encoders/WebpEncoder.php +++ b/src/Encoders/WebpEncoder.php @@ -12,9 +12,12 @@ class WebpEncoder extends SpecializableEncoder * Create new encoder object * * @param int $quality + * @param null|bool $strip Strip EXIF metadata * @return void */ - public function __construct(public int $quality = self::DEFAULT_QUALITY) - { + public function __construct( + public int $quality = self::DEFAULT_QUALITY, + public ?bool $strip = null + ) { } } diff --git a/tests/Unit/ConfigTest.php b/tests/Unit/ConfigTest.php index 6a1683bd..06555c3a 100644 --- a/tests/Unit/ConfigTest.php +++ b/tests/Unit/ConfigTest.php @@ -24,11 +24,13 @@ public function testConstructor(): void autoOrientation: false, decodeAnimation: false, blendingColor: 'f00', + strip: true, ); $this->assertInstanceOf(Config::class, $config); $this->assertFalse($config->autoOrientation); $this->assertFalse($config->decodeAnimation); + $this->assertTrue($config->strip); $this->assertEquals('f00', $config->blendingColor); } @@ -37,12 +39,14 @@ public function testGetSetOptions(): void $config = new Config(); $this->assertTrue($config->autoOrientation); $this->assertTrue($config->decodeAnimation); + $this->assertFalse($config->strip); $this->assertEquals('ffffff', $config->blendingColor); $result = $config->setOptions( autoOrientation: false, decodeAnimation: false, blendingColor: 'f00', + strip: true, ); $this->assertFalse($config->autoOrientation); @@ -51,16 +55,19 @@ public function testGetSetOptions(): void $this->assertFalse($result->autoOrientation); $this->assertFalse($result->decodeAnimation); + $this->assertTrue($result->strip); $this->assertEquals('f00', $result->blendingColor); $result = $config->setOptions(blendingColor: '000'); $this->assertFalse($config->autoOrientation); $this->assertFalse($config->decodeAnimation); + $this->assertTrue($config->strip); $this->assertEquals('000', $config->blendingColor); $this->assertFalse($result->autoOrientation); $this->assertFalse($result->decodeAnimation); + $this->assertTrue($result->strip); $this->assertEquals('000', $result->blendingColor); } @@ -71,13 +78,16 @@ public function testSetOptionsWithArray(): void 'autoOrientation' => false, 'decodeAnimation' => false, 'blendingColor' => 'f00', + 'strip' => true, ]); $this->assertFalse($config->autoOrientation); $this->assertFalse($config->decodeAnimation); + $this->assertTrue($config->strip); $this->assertEquals('f00', $config->blendingColor); $this->assertFalse($result->autoOrientation); $this->assertFalse($result->decodeAnimation); + $this->assertTrue($result->strip); $this->assertEquals('f00', $result->blendingColor); } } diff --git a/tests/Unit/Drivers/Imagick/Encoders/AvifEncoderTest.php b/tests/Unit/Drivers/Imagick/Encoders/AvifEncoderTest.php index 59acc267..d24e5e3f 100644 --- a/tests/Unit/Drivers/Imagick/Encoders/AvifEncoderTest.php +++ b/tests/Unit/Drivers/Imagick/Encoders/AvifEncoderTest.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Driver; use Intervention\Image\Drivers\Imagick\Encoders\AvifEncoder; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\RequiresPhpExtension; @@ -17,6 +18,7 @@ public function testEncode(): void { $image = $this->createTestImage(3, 2); $encoder = new AvifEncoder(10); + $encoder->setDriver(new Driver()); $result = $encoder->encode($image); $this->assertMediaType('image/avif', $result); $this->assertEquals('image/avif', $result->mimetype()); diff --git a/tests/Unit/Drivers/Imagick/Encoders/HeicEncoderTest.php b/tests/Unit/Drivers/Imagick/Encoders/HeicEncoderTest.php index 31ff3836..fb7adf46 100644 --- a/tests/Unit/Drivers/Imagick/Encoders/HeicEncoderTest.php +++ b/tests/Unit/Drivers/Imagick/Encoders/HeicEncoderTest.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Driver; use Intervention\Image\Drivers\Imagick\Encoders\HeicEncoder; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\RequiresPhpExtension; @@ -17,6 +18,7 @@ public function testEncode(): void { $image = $this->createTestImage(3, 2); $encoder = new HeicEncoder(75); + $encoder->setDriver(new Driver()); $result = $encoder->encode($image); $this->assertMediaType('image/heic', $result); $this->assertEquals('image/heic', $result->mimetype()); diff --git a/tests/Unit/Drivers/Imagick/Encoders/Jpeg2000EncoderTest.php b/tests/Unit/Drivers/Imagick/Encoders/Jpeg2000EncoderTest.php index c9e4d0b8..353d2ef8 100644 --- a/tests/Unit/Drivers/Imagick/Encoders/Jpeg2000EncoderTest.php +++ b/tests/Unit/Drivers/Imagick/Encoders/Jpeg2000EncoderTest.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Driver; use Intervention\Image\Drivers\Imagick\Encoders\Jpeg2000Encoder; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\RequiresPhpExtension; @@ -17,6 +18,7 @@ public function testEncode(): void { $image = $this->createTestImage(3, 2); $encoder = new Jpeg2000Encoder(75); + $encoder->setDriver(new Driver()); $result = $encoder->encode($image); $this->assertMediaType('image/jp2', $result); $this->assertEquals('image/jp2', $result->mimetype()); diff --git a/tests/Unit/Drivers/Imagick/Encoders/JpegEncoderTest.php b/tests/Unit/Drivers/Imagick/Encoders/JpegEncoderTest.php index 7bbb91ad..f0fdf533 100644 --- a/tests/Unit/Drivers/Imagick/Encoders/JpegEncoderTest.php +++ b/tests/Unit/Drivers/Imagick/Encoders/JpegEncoderTest.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Decoders\FilePointerImageDecoder; use Intervention\Image\Drivers\Imagick\Driver; use Intervention\Image\Drivers\Imagick\Encoders\JpegEncoder; use PHPUnit\Framework\Attributes\CoversClass; @@ -37,4 +38,34 @@ public function testEncodeProgressive(): void $this->assertEquals('image/jpeg', $result->mimetype()); $this->assertTrue($this->isProgressiveJpeg($result)); } + + public function testEncodeStripExif(): void + { + $image = $this->readTestImage('exif.jpg'); + $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist')); + + $encoder = new JpegEncoder(strip: true); + $encoder->setDriver(new Driver()); + $result = $encoder->encode($image); + $this->assertMediaType('image/jpeg', $result); + $this->assertEquals('image/jpeg', $result->mimetype()); + + $this->assertEmpty(exif_read_data($result->toFilePointer())['IFD0.Artist'] ?? null); + } + + public function testEncodeStripExifKeepICCProfiles(): void + { + $image = $this->readTestImage('cmyk.jpg'); + $this->assertNotEmpty($image->core()->native()->getImageProfiles('icc')); + + $encoder = new JpegEncoder(strip: true); + $encoder->setDriver(new Driver()); + $result = $encoder->encode($image); + + $decoder = new FilePointerImageDecoder(); + $decoder->setDriver(new Driver()); + + $image = $decoder->decode($result->toFilePointer()); + $this->assertNotEmpty($image->core()->native()->getImageProfiles('icc')); + } } diff --git a/tests/Unit/Drivers/Imagick/Encoders/TiffEncoderTest.php b/tests/Unit/Drivers/Imagick/Encoders/TiffEncoderTest.php index 58a5dc4e..15086631 100644 --- a/tests/Unit/Drivers/Imagick/Encoders/TiffEncoderTest.php +++ b/tests/Unit/Drivers/Imagick/Encoders/TiffEncoderTest.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Driver; use Intervention\Image\Drivers\Imagick\Encoders\TiffEncoder; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\RequiresPhpExtension; @@ -17,6 +18,7 @@ public function testEncode(): void { $image = $this->createTestImage(3, 2); $encoder = new TiffEncoder(); + $encoder->setDriver(new Driver()); $result = $encoder->encode($image); $this->assertMediaType('image/tiff', $result); $this->assertEquals('image/tiff', $result->mimetype()); diff --git a/tests/Unit/Drivers/Imagick/Encoders/WebpEncoderTest.php b/tests/Unit/Drivers/Imagick/Encoders/WebpEncoderTest.php index 18bf38f2..456fdb08 100644 --- a/tests/Unit/Drivers/Imagick/Encoders/WebpEncoderTest.php +++ b/tests/Unit/Drivers/Imagick/Encoders/WebpEncoderTest.php @@ -4,6 +4,7 @@ namespace Intervention\Image\Tests\Unit\Drivers\Imagick\Encoders; +use Intervention\Image\Drivers\Imagick\Driver; use Intervention\Image\Drivers\Imagick\Encoders\WebpEncoder; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\RequiresPhpExtension; @@ -17,6 +18,7 @@ public function testEncode(): void { $image = $this->createTestImage(3, 2); $encoder = new WebpEncoder(75); + $encoder->setDriver(new Driver()); $result = $encoder->encode($image); $this->assertMediaType('image/webp', $result); $this->assertEquals('image/webp', $result->mimetype()); diff --git a/tests/Unit/Drivers/Imagick/Modifiers/StripMetaModifierTest.php b/tests/Unit/Drivers/Imagick/Modifiers/StripMetaModifierTest.php new file mode 100644 index 00000000..b03ab58b --- /dev/null +++ b/tests/Unit/Drivers/Imagick/Modifiers/StripMetaModifierTest.php @@ -0,0 +1,25 @@ +readTestImage('exif.jpg'); + $this->assertEquals('Oliver Vogel', $image->exif('IFD0.Artist')); + $image->modify(new StripMetaModifier()); + $this->assertNull($image->exif('IFD0.Artist')); + $result = $image->toJpeg(); + $this->assertEmpty(exif_read_data($result->toFilePointer())['IFD0.Artist'] ?? null); + } +}