diff --git a/MediaGalleryMetadata/Model/AddIptcMetadata.php b/MediaGalleryMetadata/Model/AddIptcMetadata.php
index 1bdc2372eedf..337e5c8f199f 100644
--- a/MediaGalleryMetadata/Model/AddIptcMetadata.php
+++ b/MediaGalleryMetadata/Model/AddIptcMetadata.php
@@ -10,6 +10,10 @@
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface;
use Magento\MediaGalleryMetadataApi\Model\FileInterface;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
+use Magento\MediaGalleryMetadata\Model\Jpeg\FileReader;
+use Magento\Framework\Filesystem\DriverInterface;
+use Magento\MediaGalleryMetadataApi\Model\FileInterfaceFactory;
+use Magento\Framework\Exception\LocalizedException;
/**
* Add metadata to the IPTC data
@@ -20,57 +24,141 @@ class AddIptcMetadata
private const IPTC_DESCRIPTION_SEGMENT = '2#120';
private const IPTC_KEYWORDS_SEGMENT = '2#025';
+ /**
+ * @var DriverInterface
+ */
+ private $driver;
+
+ /**
+ * @var FileReader
+ */
+ private $fileReader;
+
+ /**
+ * @var FileInterfaceFactory
+ */
+ private $fileFactory;
+
+ /**
+ * @param FileInterfaceFactory $fileFactory
+ * @param DriverInterface $driver
+ * @param FileReader $fileReader
+ */
+ public function __construct(
+ FileInterfaceFactory $fileFactory,
+ DriverInterface $driver,
+ FileReader $fileReader
+ ) {
+ $this->fileFactory = $fileFactory;
+ $this->driver = $driver;
+ $this->fileReader = $fileReader;
+ }
+
/**
* Write metadata
*
* @param FileInterface $file
* @param MetadataInterface $metadata
- * @param SegmentInterface $segment
- * @return string
+ * @param null|SegmentInterface $segment
*/
- public function execute(FileInterface $file, MetadataInterface $metadata, SegmentInterface $segment): string
+ public function execute(FileInterface $file, MetadataInterface $metadata, ?SegmentInterface $segment): FileInterface
{
- if (is_callable('iptcembed')) {
- $iptcData = iptcparse($segment->getData());
- if (!empty($metadata->getTitle())) {
- $iptcData[self::IPTC_TITLE_SEGMENT][0] = $metadata->getTitle();
- }
+ if (!is_callable('iptcembed') && !is_callable('iptcparse')) {
+ throw new LocalizedException(__('iptcembed() && iptcparse() must be enabled in php configuration'));
+ }
+
+ $iptcData = $segment ? iptcparse($segment->getData()) : [];
- if (!empty($metadata->getDescription())) {
- $iptcData[self::IPTC_DESCRIPTION_SEGMENT][0] = $metadata->getDescription();
- }
+ if (!empty($metadata->getTitle())) {
+ $iptcData[self::IPTC_TITLE_SEGMENT][0] = $metadata->getTitle();
+ }
- if (!empty($metadata->getKeywords())) {
- foreach ($metadata->getKeywords() as $key => $keyword) {
- $iptcData[self::IPTC_KEYWORDS_SEGMENT][$key] = $keyword;
- }
- }
+ if (!empty($metadata->getDescription())) {
+ $iptcData[self::IPTC_DESCRIPTION_SEGMENT][0] = $metadata->getDescription();
+ }
+
+ if (!empty($metadata->getKeywords())) {
+ $iptcData = $this->writeKeywords($metadata->getKeywords(), $iptcData);
+ }
- $newData = '';
+ $newData = '';
- foreach ($iptcData as $tag => $values) {
- foreach ($values as $value) {
- $newData .= $this->iptcMaketag(2, substr($tag, 2), $value);
- }
+ foreach ($iptcData as $tag => $values) {
+ foreach ($values as $value) {
+ $newData .= $this->iptcMaketag(2, (int) substr($tag, 2), $value);
}
- $content = iptcembed($newData, $file->getPath());
+ }
+
+ $this->writeFile($file->getPath(), iptcembed($newData, $file->getPath()));
+
+ $fileWithIptc = $this->fileReader->execute($file->getPath());
+
+ return $this->fileFactory->create([
+ 'path' => $fileWithIptc->getPath(),
+ 'segments' => $this->getSegmentsWithIptc($fileWithIptc, $file)
+ ]);
+ }
+
+ /**
+ * Return iptc segment from file.
+ *
+ * @param FileInterface $fileWithIptc
+ * @param FileInterface $originFile
+ */
+ private function getSegmentsWithIptc(FileInterface $fileWithIptc, $originFile): array
+ {
+ $segments = $fileWithIptc->getSegments();
+ $originFileSegments = $originFile->getSegments();
- return $content;
+ foreach ($segments as $key => $segment) {
+ if ($segment->getName() === 'APP13') {
+ $originFileSegments[$key] = $segments[$key];
+ return $originFileSegments;
+ }
+ }
+ return $originFileSegments;
+ }
+
+ /**
+ * Write keywords field to the iptc segment.
+ *
+ * @param array $keywords
+ * @param array $iptcData
+ */
+ private function writeKeywords(array $keywords, array $iptcData): array
+ {
+ foreach ($keywords as $key => $keyword) {
+ $iptcData[self::IPTC_KEYWORDS_SEGMENT][$key] = $keyword;
}
+ return $iptcData;
+ }
+
+ /**
+ * Write iptc data to the image directly to the file.
+ *
+ * @param string $filePath
+ * @param string $content
+ */
+ private function writeFile(string $filePath, string $content): void
+ {
+ $resource = $this->driver->fileOpen($filePath, 'wb');
+
+ $this->driver->fileWrite($resource, $content);
+ $this->driver->fileClose($resource);
}
/**
* Create new iptc tag text
*
* @param int $rec
- * @param string $tag
+ * @param int $tag
* @param string $value
*/
- private function iptcMaketag($rec, $tag, $value)
+ private function iptcMaketag(int $rec, int $tag, string $value)
{
//phpcs:disable Magento2.Functions.DiscouragedFunction
$length = strlen($value);
- $retval = chr(0x1C) . chr($rec) . chr((int)$tag);
+ $retval = chr(0x1C) . chr($rec) . chr($tag);
if ($length < 0x8000) {
$retval .= chr($length >> 8) . chr($length & 0xFF);
diff --git a/MediaGalleryMetadata/Model/Gif/FileReader.php b/MediaGalleryMetadata/Model/Gif/FileReader.php
index e109f36f2db4..1ca3941eef1e 100644
--- a/MediaGalleryMetadata/Model/Gif/FileReader.php
+++ b/MediaGalleryMetadata/Model/Gif/FileReader.php
@@ -144,7 +144,7 @@ private function getSegments($resource): array
if ($separator == $gifFrameSeparator) {
$segments[] = $this->segmentFactory->create([
'name' => 'frame',
- 'data' => $this->readFrame($resource)
+ 'data' => $gifFrameSeparator . $this->readFrame($resource)
]);
continue;
}
@@ -154,7 +154,6 @@ private function getSegments($resource): array
}
$segments[] = $this->getExtensionSegment($resource);
-
} while (!$this->driver->endOfFile($resource));
return $segments;
@@ -169,6 +168,7 @@ private function getSegments($resource): array
*/
private function getExtensionSegment($resource): SegmentInterface
{
+ $gifExtensionSeparator = pack("C", ord("!"));
$extensionCodeBinary = $this->read($resource, 1);
//phpcs:ignore Magento2.Functions.DiscouragedFunction
$extensionCode = unpack('C', $extensionCodeBinary)[1];
@@ -176,21 +176,21 @@ private function getExtensionSegment($resource): SegmentInterface
if ($extensionCode == 0xF9) {
return $this->segmentFactory->create([
'name' => 'Graphics Control Extension',
- 'data' => $extensionCodeBinary . $this->readBlock($resource)
+ 'data' => $gifExtensionSeparator . $extensionCodeBinary . $this->readBlock($resource)
]);
}
if ($extensionCode == 0xFE) {
return $this->segmentFactory->create([
'name' => 'comment',
- 'data' => $extensionCodeBinary . $this->readBlock($resource)
+ 'data' => $gifExtensionSeparator . $extensionCodeBinary . $this->readBlock($resource)
]);
}
if ($extensionCode != 0xFF) {
return $this->segmentFactory->create([
- 'name' => 'unknown',
- 'data' => $extensionCodeBinary . $this->readBlock($resource)
+ 'name' => 'Programm extension',
+ 'data' => $gifExtensionSeparator . $extensionCodeBinary . $this->readBlock($resource)
]);
}
@@ -206,14 +206,15 @@ private function getExtensionSegment($resource): SegmentInterface
if ($name == 'XMP DataXMP') {
return $this->segmentFactory->create([
'name' => $name,
- 'data' => $extensionCodeBinary . $blockLengthBinary
+ 'data' => $gifExtensionSeparator . $extensionCodeBinary . $blockLengthBinary
. $name . $this->readBlockWithSubblocks($resource)
]);
}
return $this->segmentFactory->create([
'name' => $name,
- 'data' => $extensionCodeBinary . $blockLengthBinary . $name . $this->readBlock($resource)
+ 'data' => $gifExtensionSeparator . $extensionCodeBinary . $blockLengthBinary
+ . $name . $this->readBlock($resource)
]);
}
@@ -300,17 +301,13 @@ private function readBlockWithSubblocks($resource): string
{
$data = '';
$subLength = $this->read($resource, 1);
- $blocks = 0;
while ($subLength !== "\0") {
- $blocks++;
- $data .= $subLength;
-
- $data .= $this->read($resource, ord($subLength));
+ $data .= $subLength . $this->read($resource, ord($subLength));
$subLength = $this->read($resource, 1);
}
- return $data;
+ return $data . $subLength;
}
/**
@@ -327,6 +324,6 @@ private function readBlock($resource): string
if ($blockLength == 0) {
return '';
}
- return $blockLength . $this->read($resource, $blockLength) . $this->read($resource, 1);
+ return $blockLengthBinary . $this->read($resource, $blockLength) . $this->read($resource, 1);
}
}
diff --git a/MediaGalleryMetadata/Model/Gif/FileWriter.php b/MediaGalleryMetadata/Model/Gif/FileWriter.php
new file mode 100644
index 000000000000..5357478e5ba0
--- /dev/null
+++ b/MediaGalleryMetadata/Model/Gif/FileWriter.php
@@ -0,0 +1,76 @@
+driver = $driver;
+ $this->segmentNames = $segmentNames;
+ }
+
+ /**
+ * Write file object to the filesystem
+ *
+ * @param FileInterface $file
+ * @throws LocalizedException
+ * @throws FileSystemException
+ */
+ public function execute(FileInterface $file): void
+ {
+ $resource = $this->driver->fileOpen($file->getPath(), 'wb');
+
+ $this->writeSegments($resource, $file->getSegments());
+ $this->driver->fileClose($resource);
+ }
+
+ /**
+ * Write gif segment
+ *
+ * @param resource $resource
+ * @param SegmentInterface[] $segments
+ */
+ private function writeSegments($resource, array $segments): void
+ {
+ foreach ($segments as $segment) {
+ $this->driver->fileWrite(
+ $resource,
+ $segment->getData()
+ );
+ }
+ $this->driver->fileWrite($resource, pack("C", ord(";")));
+ }
+}
diff --git a/MediaGalleryMetadata/Model/Gif/Segment/XmpReader.php b/MediaGalleryMetadata/Model/Gif/Segment/XmpReader.php
index 94515ca34ed2..da94a75ccca8 100644
--- a/MediaGalleryMetadata/Model/Gif/Segment/XmpReader.php
+++ b/MediaGalleryMetadata/Model/Gif/Segment/XmpReader.php
@@ -24,9 +24,9 @@ class XmpReader implements MetadataReaderInterface
/**
* see XMP Specification Part 3, 1.1.2 GIF
*/
- private const MAGIC_TRAILER_LENGTH = 257;
+ private const MAGIC_TRAILER_LENGTH = 258;
private const MAGIC_TRAILER_START = "\x01\xFF\xFE";
- private const MAGIC_TRAILER_END = "\x03\x02\x01\x00";
+ private const MAGIC_TRAILER_END = "\x03\x02\x01\x00\x00";
/**
* @var MetadataInterfaceFactory
@@ -84,10 +84,10 @@ private function isXmp(SegmentInterface $segment): bool
*/
private function getXmpData(SegmentInterface $segment): string
{
- $xmp = substr($segment->getData(), 13);
+ $xmp = substr($segment->getData(), 14);
if (substr($xmp, -self::MAGIC_TRAILER_LENGTH, 3) !== self::MAGIC_TRAILER_START
- || substr($xmp, -4) !== self::MAGIC_TRAILER_END
+ || substr($xmp, -5) !== self::MAGIC_TRAILER_END
) {
throw new LocalizedException(__('XMP data is corrupted'));
}
diff --git a/MediaGalleryMetadata/Model/Gif/Segment/XmpWriter.php b/MediaGalleryMetadata/Model/Gif/Segment/XmpWriter.php
new file mode 100644
index 000000000000..515bddb76f81
--- /dev/null
+++ b/MediaGalleryMetadata/Model/Gif/Segment/XmpWriter.php
@@ -0,0 +1,191 @@
+fileFactory = $fileFactory;
+ $this->segmentFactory = $segmentFactory;
+ $this->addXmpMetadata = $addXmpMetadata;
+ $this->xmpTemplate = $xmpTemplate;
+ }
+
+ /**
+ * Add metadata to the file
+ *
+ * @param FileInterface $file
+ * @param MetadataInterface $metadata
+ * @return FileInterface
+ */
+ public function execute(FileInterface $file, MetadataInterface $metadata): FileInterface
+ {
+ $gifSegments = $file->getSegments();
+ $xmpGifSegments = [];
+ foreach ($gifSegments as $key => $segment) {
+ if ($this->isSegmentXmp($segment)) {
+ $xmpGifSegments[$key] = $segment;
+ }
+ }
+
+ if (empty($xmpGifSegments)) {
+ return $this->fileFactory->create([
+ 'path' => $file->getPath(),
+ 'segments' => $this->insertXmpGifSegment($gifSegments, $this->createXmpSegment($metadata))
+ ]);
+ }
+
+ foreach ($xmpGifSegments as $key => $segment) {
+ $gifSegments[$key] = $this->updateSegment($segment, $metadata);
+ }
+
+ return $this->fileFactory->create([
+ 'path' => $file->getPath(),
+ 'segments' => $gifSegments
+ ]);
+ }
+
+ /**
+ * Insert XMP segment to gif image segments (at position 3)
+ *
+ * @param SegmentInterface[] $segments
+ * @param SegmentInterface $xmpSegment
+ * @return SegmentInterface[]
+ */
+ private function insertXmpGifSegment(array $segments, SegmentInterface $xmpSegment): array
+ {
+ return array_merge(array_slice($segments, 0, 4), [$xmpSegment], array_slice($segments, 4));
+ }
+
+ /**
+ * Return XMP template from string
+ *
+ * @param string $string
+ * @param string $start
+ * @param string $end
+ */
+ private function getXmpData(string $string, string $start, string $end): string
+ {
+ $string = ' ' . $string;
+ $ini = strpos($string, $start);
+ if ($ini == 0) {
+ return '';
+ }
+ $ini += strlen($start);
+ $len = strpos($string, $end, $ini) - $ini;
+
+ return substr($string, $ini, $len);
+ }
+
+ /**
+ * Write new segment metadata
+ *
+ * @param MetadataInterface $metadata
+ * @return SegmentInterface
+ */
+ public function createXmpSegment(MetadataInterface $metadata): SegmentInterface
+ {
+ $xmpData = $this->xmpTemplate->get();
+
+ $xmpSegment = pack("C", ord("!")) . pack("C", 255) . pack("C", 11).
+ self::XMP_SEGMENT_NAME . $this->addXmpMetadata->execute($xmpData, $metadata) . "\x01";
+
+ /**
+ * Write Magic trailer 258 bytes see XMP Specification Part 3, 1.1.2 GIF
+ */
+ $i = 255;
+ while ($i > 0) {
+ $xmpSegment .= pack("C", $i);
+ $i--;
+ }
+
+ return $this->segmentFactory->create([
+ 'name' => self::XMP_SEGMENT_NAME,
+ 'data' => $xmpSegment . "\0\0"
+ ]);
+ }
+
+ /**
+ * Add metadata to the segment
+ *
+ * @param SegmentInterface $segment
+ * @param MetadataInterface $metadata
+ * @return SegmentInterface
+ */
+ public function updateSegment(SegmentInterface $segment, MetadataInterface $metadata): SegmentInterface
+ {
+ $data = $segment->getData();
+ $start = substr($data, 0, self::XMP_DATA_START_POSITION);
+ $xmpData = $this->getXmpData($data, self::XMP_SEGMENT_NAME, "\x01");
+ $end = substr($data, strpos($data, "\x01"));
+
+ return $this->segmentFactory->create([
+ 'name' => $segment->getName(),
+ 'data' => $start . $this->addXmpMetadata->execute($xmpData, $metadata) . $end
+ ]);
+ }
+
+ /**
+ * Check if segment contains XMP data
+ *
+ * @param SegmentInterface $segment
+ * @return bool
+ */
+ private function isSegmentXmp(SegmentInterface $segment): bool
+ {
+ return $segment->getName() === self::XMP_SEGMENT_NAME;
+ }
+}
diff --git a/MediaGalleryMetadata/Model/Jpeg/Segment/IptcWriter.php b/MediaGalleryMetadata/Model/Jpeg/Segment/IptcWriter.php
index dcbb5b25e66c..df09ab989302 100644
--- a/MediaGalleryMetadata/Model/Jpeg/Segment/IptcWriter.php
+++ b/MediaGalleryMetadata/Model/Jpeg/Segment/IptcWriter.php
@@ -14,6 +14,7 @@
use Magento\MediaGalleryMetadataApi\Model\MetadataWriterInterface;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterfaceFactory;
+use Magento\MediaGalleryMetadata\Model\Jpeg\FileReader;
/**
* Jpeg IPTC Writer
@@ -21,9 +22,9 @@
class IptcWriter implements MetadataWriterInterface
{
private const IPTC_SEGMENT_NAME = 'APP13';
- private const IPTC_SEGMENT_START = 'Photoshop 3.0';
+ private const IPTC_SEGMENT_START = 'Photoshop 3.0\0x00';
private const IPTC_DATA_START_POSITION = 0;
-
+
/**
* @var SegmentInterfaceFactory
*/
@@ -39,19 +40,27 @@ class IptcWriter implements MetadataWriterInterface
*/
private $addIptcMetadata;
+ /**
+ * @var FileReader
+ */
+ private $fileReader;
+
/**
* @param FileInterfaceFactory $fileFactory
* @param SegmentInterfaceFactory $segmentFactory
* @param AddIptcMetadata $addIptcMetadata
+ * @param FileReader $fileReader
*/
public function __construct(
FileInterfaceFactory $fileFactory,
SegmentInterfaceFactory $segmentFactory,
- AddIptcMetadata $addIptcMetadata
+ AddIptcMetadata $addIptcMetadata,
+ FileReader $fileReader
) {
$this->fileFactory = $fileFactory;
$this->segmentFactory = $segmentFactory;
$this->addIptcMetadata = $addIptcMetadata;
+ $this->fileReader = $fileReader;
}
/**
@@ -64,36 +73,17 @@ public function __construct(
public function execute(FileInterface $file, MetadataInterface $metadata): FileInterface
{
$segments = $file->getSegments();
+ $iptcSegments = [];
foreach ($segments as $key => $segment) {
if ($this->isIptcSegment($segment)) {
- $segments[$key] = $this->updateSegment($segment, $metadata, $file);
+ $iptcSegments[$key] = $segment;
}
}
- return $this->fileFactory->create([
- 'path' => $file->getPath(),
- 'segments' => $segments
- ]);
- }
- /**
- * Add metadata to the segment
- *
- * @param SegmentInterface $segment
- * @param MetadataInterface $metadata
- * @param FileInterface $file
- * @return SegmentInterface
- */
- public function updateSegment(
- SegmentInterface $segment,
- MetadataInterface $metadata,
- FileInterface $file
- ): SegmentInterface {
- $data = $segment->getData();
- $start = substr($data, 0, self::IPTC_DATA_START_POSITION);
- return $this->segmentFactory->create([
- 'name' => $segment->getName(),
- 'data' => $start . $this->addIptcMetadata->execute($file, $metadata, $segment)
- ]);
+ foreach ($iptcSegments as $segment) {
+ return $this->addIptcMetadata->execute($file, $metadata, $segment);
+ }
+ return $this->addIptcMetadata->execute($file, $metadata, null);
}
/**
diff --git a/MediaGalleryMetadata/Model/Png/Segment/XmpWriter.php b/MediaGalleryMetadata/Model/Png/Segment/XmpWriter.php
index 2d97aa2ed139..e5e1c787f602 100644
--- a/MediaGalleryMetadata/Model/Png/Segment/XmpWriter.php
+++ b/MediaGalleryMetadata/Model/Png/Segment/XmpWriter.php
@@ -14,9 +14,10 @@
use Magento\MediaGalleryMetadataApi\Model\MetadataWriterInterface;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterfaceFactory;
+use Magento\MediaGalleryMetadata\Model\XmpTemplate;
/**
- * XMP Reader
+ * XMP Writer for png format
*/
class XmpWriter implements MetadataWriterInterface
{
@@ -38,23 +39,31 @@ class XmpWriter implements MetadataWriterInterface
*/
private $addXmpMetadata;
+ /**
+ * @var XmpTemplate
+ */
+ private $xmpTemplate;
+
/**
* @param FileInterfaceFactory $fileFactory
* @param SegmentInterfaceFactory $segmentFactory
* @param AddXmpMetadata $addXmpMetadata
+ * @param XmpTemplate $xmpTemplate
*/
public function __construct(
FileInterfaceFactory $fileFactory,
SegmentInterfaceFactory $segmentFactory,
- AddXmpMetadata $addXmpMetadata
+ AddXmpMetadata $addXmpMetadata,
+ XmpTemplate $xmpTemplate
) {
$this->fileFactory = $fileFactory;
$this->segmentFactory = $segmentFactory;
$this->addXmpMetadata = $addXmpMetadata;
+ $this->xmpTemplate = $xmpTemplate;
}
/**
- * Add metadata to the file
+ * Add xmp metadata to the png file
*
* @param FileInterface $file
* @param MetadataInterface $metadata
@@ -63,11 +72,24 @@ public function __construct(
public function execute(FileInterface $file, MetadataInterface $metadata): FileInterface
{
$segments = $file->getSegments();
+ $pngXmpSegments = [];
foreach ($segments as $key => $segment) {
if ($this->isXmpSegment($segment)) {
- $segments[$key] = $this->updateSegment($segment, $metadata);
+ $pngXmpSegments[$key] = $segment;
}
}
+
+ if (empty($pngXmpSegments)) {
+ return $this->fileFactory->create([
+ 'path' => $file->getPath(),
+ 'segments' => $this->insertPngXmpSegment($segments, $this->createPngXmpSegment($metadata))
+ ]);
+ }
+
+ foreach ($pngXmpSegments as $key => $segment) {
+ $segments[$key] = $this->updateSegment($segment, $metadata);
+ }
+
return $this->fileFactory->create([
'path' => $file->getPath(),
'segments' => $segments
@@ -75,7 +97,34 @@ public function execute(FileInterface $file, MetadataInterface $metadata): FileI
}
/**
- * Add metadata to the segment
+ * Insert XMP segment to image png segments (at position 1)
+ *
+ * @param SegmentInterface[] $segments
+ * @param SegmentInterface $xmpSegment
+ * @return SegmentInterface[]
+ */
+ private function insertPngXmpSegment(array $segments, SegmentInterface $xmpSegment): array
+ {
+ return array_merge(array_slice($segments, 0, 2), [$xmpSegment], array_slice($segments, 2));
+ }
+
+ /**
+ * Write new png segment metadata
+ *
+ * @param MetadataInterface $metadata
+ * @return SegmentInterface
+ */
+ public function createPngXmpSegment(MetadataInterface $metadata): SegmentInterface
+ {
+ $xmpData = $this->xmpTemplate->get();
+ return $this->segmentFactory->create([
+ 'name' => self::XMP_SEGMENT_NAME,
+ 'data' => self::XMP_SEGMENT_START . $this->addXmpMetadata->execute($xmpData, $metadata)
+ ]);
+ }
+
+ /**
+ * Add metadata to the png xmp segment
*
* @param SegmentInterface $segment
* @param MetadataInterface $metadata
diff --git a/MediaGalleryMetadata/Test/Integration/Model/AddMetadataTest.php b/MediaGalleryMetadata/Test/Integration/Model/AddMetadataTest.php
index f23cd025e7eb..55a8ff24f07e 100644
--- a/MediaGalleryMetadata/Test/Integration/Model/AddMetadataTest.php
+++ b/MediaGalleryMetadata/Test/Integration/Model/AddMetadataTest.php
@@ -142,8 +142,35 @@ public function filesProvider(): array
[
'magento2',
'community'
+ ],
+ ],
+ [
+ 'empty_xmp_image.png',
+ 'Title of the magento image',
+ 'Description of the magento image 2',
+ [
+ 'magento2',
+ 'community'
+ ],
+ ],
+ [
+ 'exiftool.gif',
+ 'Updated Title',
+ 'Updated Description',
+ [
+ 'magento2',
+ 'mediagallery'
+ ]
+ ],
+ [
+ 'empty_exiftool.gif',
+ 'Updated Title',
+ 'Updated Description',
+ [
+ 'magento2',
+ 'mediagallery'
]
- ]
+ ]
];
}
}
diff --git a/MediaGalleryMetadata/Test/Integration/Model/Gif/Segment/XmpTest.php b/MediaGalleryMetadata/Test/Integration/Model/Gif/Segment/XmpTest.php
new file mode 100644
index 000000000000..2f51a0a0b3d6
--- /dev/null
+++ b/MediaGalleryMetadata/Test/Integration/Model/Gif/Segment/XmpTest.php
@@ -0,0 +1,117 @@
+xmpWriter = Bootstrap::getObjectManager()->get(XmpWriter::class);
+ $this->xmpReader = Bootstrap::getObjectManager()->get(XmpReader::class);
+ $this->fileReader = Bootstrap::getObjectManager()->get(FileReader::class);
+ $this->driver = Bootstrap::getObjectManager()->get(DriverInterface::class);
+ $this->metadataFactory = Bootstrap::getObjectManager()->get(MetadataFactory::class);
+ }
+
+ /**
+ * Test for XMP reader and writer
+ *
+ * @dataProvider filesProvider
+ * @param string $fileName
+ * @param string $title
+ * @param string $description
+ * @param array $keywords
+ * @throws LocalizedException
+ */
+ public function testWriteReadGif(
+ string $fileName,
+ string $title,
+ string $description,
+ array $keywords
+ ): void {
+ $path = realpath(__DIR__ . '/../../../../_files/' . $fileName);
+ $file = $this->fileReader->execute($path);
+ $originalGifMetadata = $this->xmpReader->execute($file);
+
+ $this->assertEmpty($originalGifMetadata->getTitle());
+ $this->assertEmpty($originalGifMetadata->getDescription());
+ $this->assertEmpty($originalGifMetadata->getKeywords());
+ $updatedGifFile = $this->xmpWriter->execute(
+ $file,
+ $this->metadataFactory->create([
+ 'title' => $title,
+ 'description' => $description,
+ 'keywords' => $keywords
+ ])
+ );
+ $updatedGifMetadata = $this->xmpReader->execute($updatedGifFile);
+ $this->assertEquals($title, $updatedGifMetadata->getTitle());
+ $this->assertEquals($description, $updatedGifMetadata->getDescription());
+ $this->assertEquals($keywords, $updatedGifMetadata->getKeywords());
+ }
+
+ /**
+ * Data provider for testExecute
+ *
+ * @return array[]
+ */
+ public function filesProvider(): array
+ {
+ return [
+ [
+ 'empty_exiftool.gif',
+ 'Title of the magento image',
+ 'Description of the magento image 2',
+ [
+ 'magento2',
+ 'community'
+ ]
+ ]
+ ];
+ }
+}
diff --git a/MediaGalleryMetadata/Test/Integration/Model/Jpeg/Segment/IptcTest.php b/MediaGalleryMetadata/Test/Integration/Model/Jpeg/Segment/IptcTest.php
new file mode 100644
index 000000000000..94a9f78b65f4
--- /dev/null
+++ b/MediaGalleryMetadata/Test/Integration/Model/Jpeg/Segment/IptcTest.php
@@ -0,0 +1,134 @@
+varDirectory = Bootstrap::getObjectManager()->get(Filesystem::class)
+ ->getDirectoryWrite(DirectoryList::VAR_DIR);
+ $this->iptcWriter = Bootstrap::getObjectManager()->get(IptcWriter::class);
+ $this->iptcReader = Bootstrap::getObjectManager()->get(IptcReader::class);
+ $this->fileReader = Bootstrap::getObjectManager()->get(FileReader::class);
+ $this->driver = Bootstrap::getObjectManager()->get(DriverInterface::class);
+ $this->metadataFactory = Bootstrap::getObjectManager()->get(MetadataFactory::class);
+ }
+
+ /**
+ * Test for IPTC reader and writer
+ *
+ * @dataProvider filesProvider
+ * @param string $fileName
+ * @param string $title
+ * @param string $description
+ * @param array $keywords
+ * @throws LocalizedException
+ */
+ public function testWriteRead(
+ string $fileName,
+ string $title,
+ string $description,
+ array $keywords
+ ): void {
+ $path = realpath(__DIR__ . '/../../../../_files/' . $fileName);
+ $modifiableFilePath = $this->varDirectory->getAbsolutePath($fileName);
+ $this->driver->copy(
+ $path,
+ $modifiableFilePath
+ );
+ $modifiableFilePath = $this->fileReader->execute($modifiableFilePath);
+ $originalMetadata = $this->iptcReader->execute($modifiableFilePath);
+
+ $this->assertEmpty($originalMetadata->getTitle());
+ $this->assertEmpty($originalMetadata->getDescription());
+ $this->assertEmpty($originalMetadata->getKeywords());
+
+ $updatedFile = $this->iptcWriter->execute(
+ $modifiableFilePath,
+ $this->metadataFactory->create([
+ 'title' => $title,
+ 'description' => $description,
+ 'keywords' => $keywords
+ ])
+ );
+
+ $updatedMetadata = $this->iptcReader->execute($updatedFile);
+
+ $this->assertEquals($title, $updatedMetadata->getTitle());
+ $this->assertEquals($description, $updatedMetadata->getDescription());
+ $this->assertEquals($keywords, $updatedMetadata->getKeywords());
+ }
+
+ /**
+ * Data provider for testExecute
+ *
+ * @return array[]
+ */
+ public function filesProvider(): array
+ {
+ return [
+ [
+ 'empty_iptc.jpeg',
+ 'Updated Title',
+ 'Updated Description',
+ [
+ 'magento2',
+ 'mediagallery'
+ ]
+ ]
+ ];
+ }
+}
diff --git a/MediaGalleryMetadata/Test/_files/empty_exiftool.gif b/MediaGalleryMetadata/Test/_files/empty_exiftool.gif
new file mode 100644
index 000000000000..14cc6026b595
Binary files /dev/null and b/MediaGalleryMetadata/Test/_files/empty_exiftool.gif differ
diff --git a/MediaGalleryMetadata/Test/_files/empty_iptc.jpeg b/MediaGalleryMetadata/Test/_files/empty_iptc.jpeg
new file mode 100644
index 000000000000..144a56dac2d3
Binary files /dev/null and b/MediaGalleryMetadata/Test/_files/empty_iptc.jpeg differ
diff --git a/MediaGalleryMetadata/Test/_files/empty_xmp_image.png b/MediaGalleryMetadata/Test/_files/empty_xmp_image.png
new file mode 100644
index 000000000000..7e81891ebc0e
Binary files /dev/null and b/MediaGalleryMetadata/Test/_files/empty_xmp_image.png differ
diff --git a/MediaGalleryMetadata/Test/_files/macos-photos.jpeg b/MediaGalleryMetadata/Test/_files/macos-photos.jpeg
index 10c6ca9438ca..3a07b6abe788 100644
Binary files a/MediaGalleryMetadata/Test/_files/macos-photos.jpeg and b/MediaGalleryMetadata/Test/_files/macos-photos.jpeg differ
diff --git a/MediaGalleryMetadata/etc/di.xml b/MediaGalleryMetadata/etc/di.xml
index a35d7d38e38d..62c1407f95e3 100644
--- a/MediaGalleryMetadata/etc/di.xml
+++ b/MediaGalleryMetadata/etc/di.xml
@@ -25,6 +25,7 @@
- Magento\MediaGalleryMetadata\Model\Jpeg\AddMetadata
- Magento\MediaGalleryMetadata\Model\Png\AddMetadata
+ - Magento\MediaGalleryMetadata\Model\Gif\AddMetadata
@@ -47,6 +48,15 @@
+
+
+ Magento\MediaGalleryMetadata\Model\Gif\FileReader
+ Magento\MediaGalleryMetadata\Model\Gif\FileWriter
+
+ - Magento\MediaGalleryMetadata\Model\Gif\Segment\XmpWriter
+
+
+
Magento\MediaGalleryMetadata\Model\Gif\FileReader