Closed bnjmnrsh closed 3 months ago
This issue is derived from the following SO discussion: https://stackoverflow.com/questions/78564547/exiftool-vendored-structured-tags With thanks to StarGeek for helping to clarify CLI flags.
Thanks for taking the time to explain the situation!
I'm currently in favor of solution #2 as well, but I think there may be nuances here that I'm currently oblivious to.
If you could provide me an example source file, the exiftool commands you expect this library to use for reading and writing, and the expected final file, that might ensure we're on the same page here.
I'm going to release add424c just to ease your testing. If it handles your use case, excellent--but please do send me examples so I can add unit tests exercising this new code.
Thanks so much for this addition. I've added my test jpg as an example; I believe that's what you're asking for.
For context and future readers, here are some reduced examples of the output before add424c.
// Behaviour of exif.write() with `-struct` prior to add424c
// Structured data is returned
{
"Creator": [
"CREATOR"
],
"AuthorsPosition": "CREATOR JOB TITLE",
"CreatorContactInfo": {
"CiAdrCity": "CREATOR CITY",
"CiAdrCtry": "CREATOR COUNTRY",
"CiAdrExtadr": "CREATOR ADDRESS",
"CiAdrPcode": "CREATOR POST CODE",
"CiAdrRegion": "CREATOR STATE/PROVINCE",
"CiEmailWork": "CREATOR EMAIL(S)",
"CiTelWork": "CREATOR PHONE(S)",
"CiUrlWork": "CREATOR WEBSITE(S)"
},
"Headline": "HEADLINE",
"Description": "DESCRIPTION",
"AltTextAccessibility": "ALT TEXT",
"ExtDescrAccessibility": "EXTENDED DESCRIPTION",
"Subject": [
"SOME KEYWORDS"
],
...
}
// ExifTool default behaviour (flattened tags returned instead of structured data) no flags passed. Tags like 'Creator' and 'Subject' are now flattened strings instead of arrays.
{
"Creator": "CREATOR",
"AuthorsPosition": "CREATOR JOB TITLE",
"CreatorAddress": "CREATOR ADDRESS",
"CreatorCity": "CREATOR CITY",
"CreatorRegion": "CREATOR STATE/PROVINCE",
"CreatorPostalCode": "CREATOR POST CODE",
"CreatorCountry": "CREATOR COUNTRY",
"CreatorWorkTelephone": "CREATOR PHONE(S)",
"CreatorWorkEmail": "CREATOR EMAIL(S)",
"CreatorWorkURL": "CREATOR WEBSITE(S)",
"Headline": "HEADLINE",
"Description": "DESCRIPTION",
"AltTextAccessibility": "ALT TEXT",
"ExtDescrAccessibility": "EXTENDED DISCRIPTION",
"Subject": "SOME KEYWORDS",
...
}
// equivalent to '-api struct=0'
{
"Creator": "CREATOR",
"AuthorsPosition": "CREATOR JOB TITLE",
"CreatorAddress": "CREATOR ADDRESS",
"CreatorCity": "CREATOR CITY",
"CreatorRegion": "CREATOR STATE/PROVINCE",
"CreatorPostalCode": "CREATOR POST CODE",
"CreatorCountry": "CREATOR COUNTRY",
"CreatorWorkTelephone": "CREATOR PHONE(S)",
"CreatorWorkEmail": "CREATOR EMAIL(S)",
"CreatorWorkURL": "CREATOR WEBSITE(S)",
"Headline": "HEADLINE",
"Description": "DESCRIPTION",
"AltTextAccessibility": "ALT TEXT",
"ExtDescrAccessibility": "EXTENDED DISCRIPTION",
"Subject": "SOME KEYWORDS",
...
}
// equivalent to '-api struct=1'
{
"Creator": [
"CREATOR"
],
"AuthorsPosition": "CREATOR JOB TITLE",
"CreatorContactInfo": {
"CiAdrCity": "CREATOR CITY",
"CiAdrCtry": "CREATOR COUNTRY",
"CiAdrExtadr": "CREATOR ADDRESS",
"CiAdrPcode": "CREATOR POST CODE",
"CiAdrRegion": "CREATOR STATE/PROVINCE",
"CiEmailWork": "CREATOR EMAIL(S)",
"CiTelWork": "CREATOR PHONE(S)",
"CiUrlWork": "CREATOR WEBSITE(S)"
},
"Headline": "HEADLINE",
"Description": "DESCRIPTION",
"AltTextAccessibility": "ALT TEXT",
"ExtDescrAccessibility": "EXTENDED DISCRIPTION",
"Subject": [
"SOME KEYWORDS"
],
...
}
// equivalent to '-api struct=2'
{
"Creator": [
"CREATOR"
],
"AuthorsPosition": "CREATOR JOB TITLE",
"CreatorContactInfo": {
"CiAdrCity": "CREATOR CITY",
"CiAdrCtry": "CREATOR COUNTRY",
"CiAdrExtadr": "CREATOR ADDRESS",
"CiAdrPcode": "CREATOR POST CODE",
"CiAdrRegion": "CREATOR STATE/PROVINCE",
"CiEmailWork": "CREATOR EMAIL(S)",
"CiTelWork": "CREATOR PHONE(S)",
"CiUrlWork": "CREATOR WEBSITE(S)"
},
"CreatorAddress": "CREATOR ADDRESS",
"CreatorCity": "CREATOR CITY",
"CreatorRegion": "CREATOR STATE/PROVINCE",
"CreatorPostalCode": "CREATOR POST CODE",
"CreatorCountry": "CREATOR COUNTRY",
"CreatorWorkTelephone": "CREATOR PHONE(S)",
"CreatorWorkEmail": "CREATOR EMAIL(S)",
"CreatorWorkURL": "CREATOR WEBSITE(S)",
"Headline": "HEADLINE",
"Description": "DESCRIPTION",
"AltTextAccessibility": "ALT TEXT",
"ExtDescrAccessibility": "EXTENDED DESCRIPTION",
"Subject": [
"SOME KEYWORDS"
],
...
}
In working with https://github.com/photostructure/exiftool-vendored.js/commit/add424c92a9b45606f69aaefe724db23d1612e41, I believe, given the documented options for the new struct
property, that undefined
is not behaving as expected, at least in the .read()
operations Ive tried.
From the ExifTool docs:
undef = Same as 0 for reading and 2 for copying
undef
in ExifTool is the default behaviour; however, in my tests, passing the undefined
global property, or quoted as a string, produces the same results as 1
in that no flattened tags are returned.
Here is my setup
export const exifExtract = new ExifTool({
struct: undefined // undefined | 0 | 1 | 2
})
Skimming over ReadTask.ts It looks like a culprit is on line 104
console.log(opts.struct) // 1 not undefined!
if (opts.struct != null) {
args.push("-api", "struct=" + opts.struct)
}
The undefined
value has been overwritten at this stage. Regardless, I believe there would be an issue with the strictness of the null check against undefined
. However even if the string 'undefined'
or 'undef'
are passed the output still doesn't include flattened tags, so something else downstream is at issue.
Generally, I'd say that following the ExifTools pattern using the string 'undef'
as a check would sidestep a lot of strict check complexity and bring the API into closer alignment to ExifTools.
It might also be worth mentioning in the docs/ts def that exiftool-vendored defaults to 1
/ -struct
output for backward compat reasons, while ExifTool produces flattened tags by default. I, for one, spent a long time bumping into that difference before realising it was a false assumption on my part.
In the long term, i.e., the next major version number, it may be worth considering making undef
the default behaviour to better align this project with ExifTool's default behaviour.
Ah, crap! I didn't think about the undefined
getting overwritten by the default options. I took your resolution suggestion: https://github.com/photostructure/exiftool-vendored.js/commit/ece7bcd11d2c3c1dc8af0fbd57d768220f0dd243
I'm not going to change the default value for struct to be "undef"
-- that would break literally all existing library users.
I'll check out the test image you attached.
Describe the bug
According to the ExifTool docs regarding Structured Information:
To my understanding, this would imply that 'Flattened' tags such as
CreatorAddress
should appear in the object returned byexiftool-vendored
.i.e., Adobe Bridge's IPTC Core section of field setting 'Creator: Address' saves the data to the Structured Dataset
CreatorContactInfo.CiAdrExtadr
. However, the documented behaviour above would imply that the Flattened TagCreatorAddress
would be returned by ExifTool and, by extension, exiftool-vendored (but its not)In reading further reading the EXIF Documentation, the output returned from exiftool-vendored appears to strip out flattened tags, as if the
-struct
flag were passed.I tried to override this behaviour by not using the provided
exiftools
instance but created my own:-api
is an advanced option that enables the use of other options such asstruct
, which I can only find documented through its Perl implementation.Digging deeper into ReadTasks.ts, I can see that
-json
and indeed-struct
flags are passed, and are not overwritten by subsequent optional arguments.To Reproduce
exiftool.read(absFilePath)
Expected behaviour
The notes in the Structured Information docs state that before 8.44, ExifTools "accepted only flattened tags as input" eg default is now to return them in output as well.
Ideally, exiftool-vendored would follow ExifTool defaults; however, this may not be possible for backwards compat reasons. However, hard-coding
-struct
into the.read()
method appears to prevent the modifying of returned output by passing in our own arguments via a new instance ofExifTool
(Or perhaps more likely, Im misunderstanding whatexiftoolArgs
param is for).Unless Im missing some combination of settings to get the output im wanting (in which case please forgive this issue entirely), I see several possible solutions:
1)
ReadTask
: could pass'-api', 'struct=2'
instead of-struct
. This shouldn't cause any downstream regressions, as the flattened tags are added to the output in addition to structured data.2) Create an additional option like
exiftoolArgs
to specify flattened tags [exiftools default], structured tags [current default], or both.Option two is preferable but more invasive.
Environment: