codewiser / exiftool
Light-weight IPTC reader/writer
Installs: 4
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 2
Forks: 0
Open Issues: 1
pkg:composer/codewiser/exiftool
Requires
- php: ^8.1
- ext-intl: *
- symfony/process: ^7.1
Requires (Dev)
- fakerphp/faker: ^1.23
- laravel/framework: ^11.26
- phpunit/phpunit: ^10
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 an 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 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.
Configuration
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.
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); }
Fake or empty metadata
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();
Properties
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
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 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
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
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'], ];
Print Conv
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.
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 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.
Controlled Vocabularies
Some attributes, such as sceneCodes, subjectCodes and some others,
should use values from external controlled vocabularies, called
NewsCodes.