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 an object-oriented programmatic interface to work with iptc attributes as objects.
This package provides some helpers for Laravel.
IPTC specification describes locationCreated as a single element, but
Exiftool counts it as a bag and requires an 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.
Construct Exiftool with a path to exiftool binary and, optionally, with
path to a specification file.
use Codewiser\Exiftool\Exiftool;
// With the latest specification
$exiftool = new Exiftool('/bin/exiftool');
// Or with another
$exiftool = new Exiftool('/bin/exiftool', '/path/to/specification.json');You may find the latest specification on iptc.org repository.
Attention!!! Be sure, that
exiftoolbinary version is compliant with specification you use.
use Codewiser\Exiftool\Iptc;
public function read(string $filename): Iptc
{
return $this->exiftool()->read($filenme);
}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.
use Symfony\Component\Process\Process;
public function write(string $filename): Process
{
return $this->exiftool()->clear($filenme);
}You may create an empty metadata collection and fill it with fake values:
// empty collection
$empty = $exiftool->newMetadata();
// requires `fakerphp/faker`
$faked = $exiftool->newMetadata()->fake();Whole collection and every attribute are JsonSerializable: this
method exports metadata to JSON format.
$json = $data->jsonSerialize();The whole collection and every single attribute may be filled with JSON data:
$data->fromJson(['captionWriter' => 'me']);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 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 attribute keeps an 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 an 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 is a collection of attributes. All structures are 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 an empty object:
$data->locationCreated = $exiftool->newStructure()->location();
$data->locationCreated->city = 'London';Multiple attribute is array of other attributes of any type. It is
Iterator, ArrayAccess and Countable, so you may handle it as a 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'],
];Read https://exiftool.org/under.html
Without enabling $exiftool->printConv() all values is human-readable. For
example, GPSLatitude may have 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 have
value 45.3363888888889.
This is very important in context of enum attributes — that must use
values from a limited list. Exiftool will reject value if it is not from a list.
Read more below.
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 the attribute specification for its 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 an array. If you call enum() on attribute with enabled
printConv, you will gat keys of such an array.
Some attributes, such as sceneCodes, subjectCodes and some others,
should use values from external controlled vocabularies, called
NewsCodes.