Skip to content

Add suport of reading PNG JPEG Exif metadata #29576

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 19, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface;
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterfaceFactory;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;

/**
* Get metadata from IPTC block
Expand Down Expand Up @@ -42,8 +41,8 @@ public function __construct(
*/
public function execute(string $data): MetadataInterface
{
$title = '';
$description = '';
$title = null;
$description = null;
$keywords = [];

if (is_callable('iptcparse')) {
Expand All @@ -65,7 +64,7 @@ public function execute(string $data): MetadataInterface
return $this->metadataFactory->create([
'title' => $title,
'description' => $description,
'keywords' => $keywords
'keywords' => !empty($keywords) ? $keywords : null
]);
}
}
104 changes: 104 additions & 0 deletions app/code/Magento/MediaGalleryMetadata/Model/Jpeg/Segment/ReadExif.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\MediaGalleryMetadata\Model\Jpeg\Segment;

use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface;
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterfaceFactory;
use Magento\MediaGalleryMetadataApi\Model\FileInterface;
use Magento\MediaGalleryMetadataApi\Model\ReadMetadataInterface;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
use Magento\Framework\Exception\LocalizedException;

/**
* Jpeg EXIF Reader
*/
class ReadExif implements ReadMetadataInterface
{
private const EXIF_SEGMENT_NAME = 'APP1';
private const EXIF_SEGMENT_START = "Exif\x00";
private const EXIF_DATA_START_POSITION = 0;

/**
* @var MetadataInterfaceFactory
*/
private $metadataFactory;

/**
* @param MetadataInterfaceFactory $metadataFactory
*/
public function __construct(
MetadataInterfaceFactory $metadataFactory
) {
$this->metadataFactory = $metadataFactory;
}

/**
* @inheritdoc
*/
public function execute(FileInterface $file): MetadataInterface
{
if (!is_callable('exif_read_data')) {
throw new LocalizedException(
__('exif_read_data() must be enabled in php configuration')
);
}

foreach ($file->getSegments() as $segment) {
if ($this->isExifSegment($segment)) {
return $this->getExifData($file->getPath());
}
}

return $this->metadataFactory->create([
'title' => null,
'description' => null,
'keywords' => null
]);
}

/**
* Parese exif data from segment
*
* @param string $filePath
*/
private function getExifData(string $filePath): MetadataInterface
{
$title = null;
$description = null;
$keywords = null;

$data = exif_read_data($filePath);

if (!empty($data)) {
$title = isset($data['DocumentName']) ? $data['DocumentName'] : null;
$description = isset($data['ImageDescription']) ? $data['ImageDescription'] : null;
}

return $this->metadataFactory->create([
'title' => $title,
'description' => $description,
'keywords' => $keywords
]);
}

/**
* Does segment contain Exif data
*
* @param SegmentInterface $segment
* @return bool
*/
private function isExifSegment(SegmentInterface $segment): bool
{
return $segment->getName() === self::EXIF_SEGMENT_NAME
&& strncmp(
substr($segment->getData(), self::EXIF_DATA_START_POSITION, 5),
self::EXIF_SEGMENT_START,
5
) == 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ public function execute(FileInterface $file): MetadataInterface
}
}
return $this->metadataFactory->create([
'title' => '',
'description' => '',
'keywords' => []
'title' => null,
'description' => null,
'keywords' => null
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ public function execute(FileInterface $file): MetadataInterface
}
}
return $this->metadataFactory->create([
'title' => '',
'description' => '',
'keywords' => []
'title' => null,
'description' => null,
'keywords' => null
]);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\MediaGalleryMetadata\Model\Png\Segment;

use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterface;
use Magento\MediaGalleryMetadataApi\Api\Data\MetadataInterfaceFactory;
use Magento\MediaGalleryMetadataApi\Model\FileInterface;
use Magento\MediaGalleryMetadataApi\Model\ReadMetadataInterface;
use Magento\MediaGalleryMetadataApi\Model\SegmentInterface;
use Magento\Framework\Exception\LocalizedException;

/**
* Jpeg EXIF Reader
*/
class ReadExif implements ReadMetadataInterface
{
private const EXIF_SEGMENT_NAME = 'eXIf';

/**
* @var MetadataInterfaceFactory
*/
private $metadataFactory;

/**
* @param MetadataInterfaceFactory $metadataFactory
*/
public function __construct(
MetadataInterfaceFactory $metadataFactory
) {
$this->metadataFactory = $metadataFactory;
}

/**
* @inheritdoc
*/
public function execute(FileInterface $file): MetadataInterface
{
if (!is_callable('exif_read_data')) {
throw new LocalizedException(
__('exif_read_data() must be enabled in php configuration')
);
}

foreach ($file->getSegments() as $segment) {
if ($this->isExifSegment($segment)) {
return $this->getExifData($segment);
}
}

return $this->metadataFactory->create([
'title' => null,
'description' => null,
'keywords' => null
]);
}

/**
* Parese exif data from segment
*
* @param SegmentInterface $segment
*/
private function getExifData(SegmentInterface $segment): MetadataInterface
{
$title = null;
$description = null;
$keywords = [];

$data = exif_read_data('data://image/jpeg;base64,' . base64_encode($segment->getData()));

if ($data) {
$title = isset($data['DocumentName']) ? $data['DocumentName'] : null;
$description = isset($data['ImageDescription']) ? $data['ImageDescription'] : null;
}

return $this->metadataFactory->create([
'title' => $title,
'description' => $description,
'keywords' => !empty($keywords) ? $keywords : null
]);
}

/**
* Does segment contain Exif data
*
* @param SegmentInterface $segment
* @return bool
*/
private function isExifSegment(SegmentInterface $segment): bool
{
return strcmp($segment->getName(), self::EXIF_SEGMENT_NAME) === 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ public function execute(FileInterface $file): MetadataInterface
}
}
return $this->metadataFactory->create([
'title' => '',
'description' => '',
'keywords' => []
'title' => null,
'description' => null,
'keywords' => null
]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ protected function setUp(): void
* @param string $fileName
* @param string $title
* @param string $description
* @param array $keywords
* @param null|array $keywords
* @throws LocalizedException
*/
public function testExecute(
string $fileName,
string $title,
string $description,
array $keywords
?array $keywords
): void {
$path = realpath(__DIR__ . '/../../_files/' . $fileName);
$metadata = $this->extractMetadata->execute($path);
Expand All @@ -62,6 +62,18 @@ public function testExecute(
public function filesProvider(): array
{
return [
[
'exif_image.png',
'Exif title png imge',
'Exif description png imge',
null
],
[
'exif-image.jpeg',
'Exif Magento title',
'Exif description metadata',
null
],
[
'macos-photos.jpeg',
'Title of the magento image',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions app/code/Magento/MediaGalleryMetadata/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<argument name="segmentReaders" xsi:type="array">
<item name="xmp" xsi:type="object">Magento\MediaGalleryMetadata\Model\Png\Segment\ReadXmp</item>
<item name="iptc" xsi:type="object">Magento\MediaGalleryMetadata\Model\Png\Segment\ReadIptc</item>
<item name="exif" xsi:type="object">Magento\MediaGalleryMetadata\Model\Png\Segment\ReadExif</item>
</argument>
</arguments>
</virtualType>
Expand All @@ -121,6 +122,7 @@
<argument name="segmentReaders" xsi:type="array">
<item name="xmp" xsi:type="object">Magento\MediaGalleryMetadata\Model\Jpeg\Segment\ReadXmp</item>
<item name="iptc" xsi:type="object">Magento\MediaGalleryMetadata\Model\Jpeg\Segment\ReadIptc</item>
<item name="exif" xsi:type="object">Magento\MediaGalleryMetadata\Model\Jpeg\Segment\ReadExif</item>
</argument>
</arguments>
</virtualType>
Expand Down