codewiser/exiftool

Light-weight IPTC reader/writer

v1.0.0-RC 2024-10-10 06:56 UTC

This package is auto-updated.

Last update: 2024-12-17 14:04:48 UTC


README

Using Exiftool. Using IPTC specification.

This lightweight package based on machine-readable specification of IPTC provided by iptc.org.

As specification describes how exiftool exports/imports metadata, describes every attribute and every structure — this package uses json-version of specification as a framework.

This package provides object-oriented programmatic interface to work with iptc attributes as objects.

This package provides some helpers for Laravel.

Known issues

IPTC specification describes locationCreated as single element, but Exiftool counts it as a bag and requires array of Location structures.

IPTC specification describes ProductWGtin.identifiers as multiple element (array), but Exiftool requires single element.

Exiftool doesnt import GPSAltitudeRef as GPSAltitude may be positive or negative — this is enough.

This library overrides IPTC specification, making locationCreated multiple and ProductWGtin.identifiers single. And ignores GPSAltitudeRef.

Configuration

Construct Exiftool with path to exiftool binary and, optionally, with path to specification file.

use Codewiser\Exiftool\Exiftool;

// With latest specification
$exiftool = new Exiftool('/bin/exiftool');

// Or with another
$exiftool = new Exiftool('/bin/exiftool', '/path/to/specification.json');

Read metadata

use Codewiser\Exiftool\Iptc;

public function read(string $filename): Iptc
{
    return $this->exiftool()->read($filenme);
}

Embed metadata

use Codewiser\Exiftool\Iptc;
use Symfony\Component\Process\Process;

public function write(string $filename, Iptc $data): Process
{
    return $this->exiftool()->write($filenme, $data);
}

Method returns Process object for you to inspect possible error output.

Clear metadata

use Symfony\Component\Process\Process;

public function write(string $filename): Process
{
    return $this->exiftool()->clear($filenme, $data);
}

Fake or empty metadata

You may create empty metadata collection and fill it with fake values:

// empty collection
$empty = $exiftool->newMetadata();

// requires `fakerphp/faker`
$faked = $exiftool->newMetadata()->fake();

Properties

Whole collection and every attribute are JsonSerializable: this method exports metadata to json format.

$json = $data->jsonSerialize();

Whole collection and every single attribute may be filled with json data:

$data->fromJson(['captionWriter' => 'me']);

Plain

Plain attribute is Stringable and has toString method, that is used to get attribute scalar value.

(string) $data->captionWriter;
// the same as
$data->captionWriter?->toString();

$data->captionWriter = 'me';

DateTime

DateTime attribute is Stringable and has toDateTime method, that is used to get DateTimeInterface value.

(string) $data->dateCreated;
// the same as
$data->dateCreated?->toDateTime()->format('c');

$data->dateCreated = time();
$data->dateCreated = new \DateTime();

AltLang

AltLang attribute keeps array of strings, each for different locale. Default current locale is en. You may change it:

use Codewiser\Exiftool\Attributes\AltLangAttribute;

AltLangAttribute::useLocale('de');

When importing data, AltLang stores default value to current locale. When exporting, AltLang current locale value will be embedded as default.

If exiftool export is:

[
    "AltTextAccessibility" => "Value 1",
    "AltTextAccessibility-es" => "Value 2",
    "AltTextAccessibility-de" => "Value 3",
]

and current locale is `en` — the result will be:

[
    "en" => "Value 1",
    "es" => "Value 2",
    "de" => "Value 3",
]

AltLang attribute is Stringable and has toString method, that is used to get attribute value in current locale.

(string) $data->description;
// the same as
$data->description?->toString();

$data->description = 'about';

It has toArray method te get all localized values.

$data->description?->toArray();

It implements ArrayAccess, so you can access values using locale as key.

isset($data->description['cn']);

$data->description['en'] = 'about';

When your backend-end responds with metadata to a front-end, the AltLang attribute responds as array. Sometimes you may want to collapse AltLang values to a string with current locale (or best matched) value. To do that instruct attribute to collapse values before respond.

use Codewiser\Exiftool\Attributes\AltLangAttribute;

AltLangAttribute::collapse();

return json_encode($data->jsonSerialized());

Structure

Structure is a collection of attributes. All structures well documented with all their attributes. Every attribute may be any of types.

$data->creatorContactInfo?->address?->toString();

$data->locationCreated?->name['en']

To add structure fill it with a json:

$data->locationCreated = ['city' => 'London', 'country' => 'UK'];

Or use factory to create empty object:

$data->locationCreated = $exiftool->newStructure()->location();
$data->locationCreated->city = 'London';

Multiple

Multiple attribute is array of other attributes of any type. It is Iterator, ArrayAccess and Countable, so you may handle it as true array.

foreach ($data->keywords as $keyword) {
    //
}

count($data->keywords);

(string) $data->keywords[0];

$data->keywords = ['value 1', 'value 2'];

// etc.

Of course, Multiple may consist of structures:

$data->locationsShown = [
    ['city' => 'London', 'country' => 'UK'],
    ['city' => 'Paris', 'country' => 'France'],
];

Print Conv

Read https://exiftool.org/under.html

Without enabling $exiftool->printConv() all values is human-readable. For example, GPSLatitude may has value 45 deg 20' 11.00".

If you call $exiftool->printConv() before importing/exporting IPTC metadata, you should use dirty values. For example, GPSLatitude may has value 45.3363888888889.

This is very important in context of enum attributes — that must use values from limited list. Exiftool will reject value if it is not from a list.

Read more below.

Enum values

Some attributes, such as dataMining, modelReleaseStatus, rbShape and some others, require their values from a limited list.

For example, Exiftool internally keeps dataMining values as DMI-UNSPECIFIED, DMI-ALLOWED etc., but exports it as Unspecified - no prohibition defined, Allowed etc. Conversely, you should import this attribute with values Unspecified - no prohibition defined, Allowed etc.

However, with enabled $exiftool->printConv() we will export/import it with keys (DMI-UNSPECIFIED, DMI-ALLOWED etc.) instead of values.

You may inspect attribute specification for it enum values:

use Codewiser\Exiftool\Exiftool;

$exiftool = new Exiftool($bin);

$values = $exiftool->specification()->topLevel()
    ->getAttributeByJsonName('dataMining')->enum();

For example, this is enum values for modelReleaseStatus attribute:

[
    'MR-NON' => 'None',
    'MR-NAP' => 'Not Applicable',
    'MR-UMR' => 'Unlimited Model Releases',
    'MR-LMR' => 'Limited or Incomplete Model Releases',
]

If you call enum() on attribute without enabling printConv, you will gat values of such array. If you call enum() on attribute with enabled printConv, you will gat keys of such array.

Controlled Vocabularies

Some attributes, such as sceneCodes, subjectCodes and some others, should use values from external controlled vocabularies, called NewsCodes.

Read more