Skip to content

Commit 13e26b2

Browse files
ENGCOM-8020: Add suport of reading PNG JPEG Exif metadata #29576
2 parents bdde24b + 9648ffd commit 13e26b2

File tree

12 files changed

+229
-15
lines changed

12 files changed

+229
-15
lines changed

app/code/Magento/MediaGalleryMetadata/Model/GetIptcMetadata.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface;
1111
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterfaceFactory;
12-
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
1312

1413
/**
1514
* Get metadata from IPTC block
@@ -42,8 +41,8 @@ public function __construct(
4241
*/
4342
public function execute(string $data): MetadataInterface
4443
{
45-
$title = '';
46-
$description = '';
44+
$title = null;
45+
$description = null;
4746
$keywords = [];
4847

4948
if (is_callable('iptcparse')) {
@@ -65,7 +64,7 @@ public function execute(string $data): MetadataInterface
6564
return $this->metadataFactory->create([
6665
'title' => $title,
6766
'description' => $description,
68-
'keywords' => $keywords
67+
'keywords' => !empty($keywords) ? $keywords : null
6968
]);
7069
}
7170
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MediaGalleryMetadata\Model\Jpeg\Segment;
9+
10+
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface;
11+
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterfaceFactory;
12+
use Magento\MediaGalleryMetadataApi\Model\FileInterface;
13+
use Magento\MediaGalleryMetadataApi\Model\ReadMetadataInterface;
14+
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
15+
use Magento\Framework\Exception\LocalizedException;
16+
17+
/**
18+
* Jpeg EXIF Reader
19+
*/
20+
class ReadExif implements ReadMetadataInterface
21+
{
22+
private const EXIF_SEGMENT_NAME = 'APP1';
23+
private const EXIF_SEGMENT_START = "Exif\x00";
24+
private const EXIF_DATA_START_POSITION = 0;
25+
26+
/**
27+
* @var MetadataInterfaceFactory
28+
*/
29+
private $metadataFactory;
30+
31+
/**
32+
* @param MetadataInterfaceFactory $metadataFactory
33+
*/
34+
public function __construct(
35+
MetadataInterfaceFactory $metadataFactory
36+
) {
37+
$this->metadataFactory = $metadataFactory;
38+
}
39+
40+
/**
41+
* @inheritdoc
42+
*/
43+
public function execute(FileInterface $file): MetadataInterface
44+
{
45+
if (!is_callable('exif_read_data')) {
46+
throw new LocalizedException(
47+
__('exif_read_data() must be enabled in php configuration')
48+
);
49+
}
50+
51+
foreach ($file->getSegments() as $segment) {
52+
if ($this->isExifSegment($segment)) {
53+
return $this->getExifData($file->getPath());
54+
}
55+
}
56+
57+
return $this->metadataFactory->create([
58+
'title' => null,
59+
'description' => null,
60+
'keywords' => null
61+
]);
62+
}
63+
64+
/**
65+
* Parese exif data from segment
66+
*
67+
* @param string $filePath
68+
*/
69+
private function getExifData(string $filePath): MetadataInterface
70+
{
71+
$title = null;
72+
$description = null;
73+
$keywords = null;
74+
75+
$data = exif_read_data($filePath);
76+
77+
if (!empty($data)) {
78+
$title = isset($data['DocumentName']) ? $data['DocumentName'] : null;
79+
$description = isset($data['ImageDescription']) ? $data['ImageDescription'] : null;
80+
}
81+
82+
return $this->metadataFactory->create([
83+
'title' => $title,
84+
'description' => $description,
85+
'keywords' => $keywords
86+
]);
87+
}
88+
89+
/**
90+
* Does segment contain Exif data
91+
*
92+
* @param SegmentInterface $segment
93+
* @return bool
94+
*/
95+
private function isExifSegment(SegmentInterface $segment): bool
96+
{
97+
return $segment->getName() === self::EXIF_SEGMENT_NAME
98+
&& strncmp(
99+
substr($segment->getData(), self::EXIF_DATA_START_POSITION, 5),
100+
self::EXIF_SEGMENT_START,
101+
5
102+
) == 0;
103+
}
104+
}

app/code/Magento/MediaGalleryMetadata/Model/Jpeg/Segment/ReadIptc.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ public function execute(FileInterface $file): MetadataInterface
5656
}
5757
}
5858
return $this->metadataFactory->create([
59-
'title' => '',
60-
'description' => '',
61-
'keywords' => []
59+
'title' => null,
60+
'description' => null,
61+
'keywords' => null
6262
]);
6363
}
6464

app/code/Magento/MediaGalleryMetadata/Model/Jpeg/Segment/ReadXmp.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ public function execute(FileInterface $file): MetadataInterface
5454
}
5555
}
5656
return $this->metadataFactory->create([
57-
'title' => '',
58-
'description' => '',
59-
'keywords' => []
57+
'title' => null,
58+
'description' => null,
59+
'keywords' => null
6060
]);
6161
}
6262

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\MediaGalleryMetadata\Model\Png\Segment;
9+
10+
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface;
11+
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterfaceFactory;
12+
use Magento\MediaGalleryMetadataApi\Model\FileInterface;
13+
use Magento\MediaGalleryMetadataApi\Model\ReadMetadataInterface;
14+
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
15+
use Magento\Framework\Exception\LocalizedException;
16+
17+
/**
18+
* Jpeg EXIF Reader
19+
*/
20+
class ReadExif implements ReadMetadataInterface
21+
{
22+
private const EXIF_SEGMENT_NAME = 'eXIf';
23+
24+
/**
25+
* @var MetadataInterfaceFactory
26+
*/
27+
private $metadataFactory;
28+
29+
/**
30+
* @param MetadataInterfaceFactory $metadataFactory
31+
*/
32+
public function __construct(
33+
MetadataInterfaceFactory $metadataFactory
34+
) {
35+
$this->metadataFactory = $metadataFactory;
36+
}
37+
38+
/**
39+
* @inheritdoc
40+
*/
41+
public function execute(FileInterface $file): MetadataInterface
42+
{
43+
if (!is_callable('exif_read_data')) {
44+
throw new LocalizedException(
45+
__('exif_read_data() must be enabled in php configuration')
46+
);
47+
}
48+
49+
foreach ($file->getSegments() as $segment) {
50+
if ($this->isExifSegment($segment)) {
51+
return $this->getExifData($segment);
52+
}
53+
}
54+
55+
return $this->metadataFactory->create([
56+
'title' => null,
57+
'description' => null,
58+
'keywords' => null
59+
]);
60+
}
61+
62+
/**
63+
* Parese exif data from segment
64+
*
65+
* @param SegmentInterface $segment
66+
*/
67+
private function getExifData(SegmentInterface $segment): MetadataInterface
68+
{
69+
$title = null;
70+
$description = null;
71+
$keywords = [];
72+
73+
$data = exif_read_data('data://image/jpeg;base64,' . base64_encode($segment->getData()));
74+
75+
if ($data) {
76+
$title = isset($data['DocumentName']) ? $data['DocumentName'] : null;
77+
$description = isset($data['ImageDescription']) ? $data['ImageDescription'] : null;
78+
}
79+
80+
return $this->metadataFactory->create([
81+
'title' => $title,
82+
'description' => $description,
83+
'keywords' => !empty($keywords) ? $keywords : null
84+
]);
85+
}
86+
87+
/**
88+
* Does segment contain Exif data
89+
*
90+
* @param SegmentInterface $segment
91+
* @return bool
92+
*/
93+
private function isExifSegment(SegmentInterface $segment): bool
94+
{
95+
return strcmp($segment->getName(), self::EXIF_SEGMENT_NAME) === 0;
96+
}
97+
}

app/code/Magento/MediaGalleryMetadata/Model/Png/Segment/ReadXmp.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ public function execute(FileInterface $file): MetadataInterface
5555
}
5656
}
5757
return $this->metadataFactory->create([
58-
'title' => '',
59-
'description' => '',
60-
'keywords' => []
58+
'title' => null,
59+
'description' => null,
60+
'keywords' => null
6161
]);
6262
}
6363

app/code/Magento/MediaGalleryMetadata/Test/Integration/Model/ExtractMetadataTest.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,14 @@ protected function setUp(): void
3737
* @param string $fileName
3838
* @param string $title
3939
* @param string $description
40-
* @param array $keywords
40+
* @param null|array $keywords
4141
* @throws LocalizedException
4242
*/
4343
public function testExecute(
4444
string $fileName,
4545
string $title,
4646
string $description,
47-
array $keywords
47+
?array $keywords
4848
): void {
4949
$path = realpath(__DIR__ . '/../../_files/' . $fileName);
5050
$metadata = $this->extractMetadata->execute($path);
@@ -62,6 +62,18 @@ public function testExecute(
6262
public function filesProvider(): array
6363
{
6464
return [
65+
[
66+
'exif_image.png',
67+
'Exif title png imge',
68+
'Exif description png imge',
69+
null
70+
],
71+
[
72+
'exif-image.jpeg',
73+
'Exif Magento title',
74+
'Exif description metadata',
75+
null
76+
],
6577
[
6678
'macos-photos.jpeg',
6779
'Title of the magento image',
Loading
Loading
Loading
Loading

app/code/Magento/MediaGalleryMetadata/etc/di.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
<argument name="segmentReaders" xsi:type="array">
113113
<item name="xmp" xsi:type="object">Magento\MediaGalleryMetadata\Model\Png\Segment\ReadXmp</item>
114114
<item name="iptc" xsi:type="object">Magento\MediaGalleryMetadata\Model\Png\Segment\ReadIptc</item>
115+
<item name="exif" xsi:type="object">Magento\MediaGalleryMetadata\Model\Png\Segment\ReadExif</item>
115116
</argument>
116117
</arguments>
117118
</virtualType>
@@ -121,6 +122,7 @@
121122
<argument name="segmentReaders" xsi:type="array">
122123
<item name="xmp" xsi:type="object">Magento\MediaGalleryMetadata\Model\Jpeg\Segment\ReadXmp</item>
123124
<item name="iptc" xsi:type="object">Magento\MediaGalleryMetadata\Model\Jpeg\Segment\ReadIptc</item>
125+
<item name="exif" xsi:type="object">Magento\MediaGalleryMetadata\Model\Jpeg\Segment\ReadExif</item>
124126
</argument>
125127
</arguments>
126128
</virtualType>

0 commit comments

Comments
 (0)