Jump to content
Claris Engage 2025 - March 25-26 Austin Texas ×

Best solution to access container EXIF data from FM?


Recommended Posts

Posted (edited)

Hello,

I want to be able to read and write to the EXIF tag -imagedescrption in JPG files stored in a container by reference from within FM.  It looks like FM natively supports only reading the data from a few tags - like filename, make, model, ... the options in GetContainerAttribute.  I see a few plugin options - Trio, MBS (MonkeyBread), MediaManager but cant' tell easily from the documentation whether they can do this.  There are other references in this FM plugin list but many seem stale.  I've used Phil Harvey's EXIFTools some so maybe I could make use of that from within FM somehow?

Has anybody done this in a while who can lead me to the best solution.  Note that I'm a hobbyist (retired) working on a one-off solution for a nonprofit HOA.  Thus I have a limited budget, and prefer shareware or open source solutions.

Thanks so much.

Platform: Windows 11, FM 21 (2024), single machine (no Server)

Edited by BAleiHi
Add tags, add platform info
Link to comment
Share on other sites

46 minutes ago, BAleiHi said:

I've used Phil Harvey's EXIFTools some so maybe I could make use of that from within FM somehow?

It appears that this is (or at least can be) a command-line tool. On macOS you should be able to run it from FMP via AppleScript. On Windows you might want to try the (free) BaseElements plugin that can perform a command line script:
https://docs.baseelementsplugin.com/article/524-beexecutesystemcommand 

 

Link to comment
Share on other sites

I've figured out how to use FMP to write EXIF data to a jpg file in Windows and have written a "SetEXIFTag" script that relies on FMPs SendEvent function to execute.  The code is below.  The parameter tagToSet will be overwritten by either direct text or by the contents of another EXIF field, depending on the switch setFromTag.  The problem that I now face is that the command sent to Windows takes some amount of time to complete and SendEvent returns before it's done.  The FMP code continues and takes certain actions that are incorrect because the tag hasn't been changed by the time they execute.  Apparently Mac has a SendEvent option "Wait for event to complete before returning" which is not available in Windows.  Ugh.

My hypothetical workaround for this would be to pass in the original value of the tagToSet, then add a loop at the end that reads it until it has changed.  But that requires that I can read an EXIF tag into FMP.  Does anyone know how to do that?  The only way I know would be to pass in the Container object that contains the file and use GetContainerAttribute.  This, of course, would limit the user to tags that GetContainerAttribute supports.  In my case, that will work but I'm hoping there's another solution.

I did try BaseElements' BE_ExecuteSystemCommand, which is supposed to wait for completion by default, but couldn't get it to do anything.  I'd just as soon avoid the plugin if possible.

Thanks for your thoughts.

Platform: Windows 11, FM 21 (2024), EXIFTools 12.85, single machine (no Server)

#------------------------------------------------------------------------------------------------------------------
# SetEXIFTag
# Sets an EXIF tag to the value passed in. Parameters:
# > filename - the full path and name of the image file to edit. Expected to be a JOG file.
# > tagtoSet - name of the EXIF tag to set. Not preceded by a -
# > newValue - the text string to set the tag to.
# > overWriteOriginal (Optional) - Yes/<>0 to overwrite the original file, no to save a copy of it. Default is Yes/<>0 (overwrite!)
# > setFromTag (Optional)- Boolean. Yes/<>0 to interpret newValue as another tagname from which to extract the newValue to write.
# No to interpret it as direct text. Default is No/0 (direct text).
# Examples:
# Perform Script [ By name "SetEXIFTag"; List("C:/users/blah/IMG_2304.jpg"; "model";"213-23-This is a test") ]
# Perform Script [ By name "SetEXIFTag"; List("C:/users/blah/IMG_2304.jpg"; "model";"imagedescription");;1 ]
#------------------------------------------------------------------------------------------------------------------
Set Variable [ $filename; Value:GetValue ( Get(ScriptParameter); 1)]
Set Variable [ $tagToSet; Value:GetValue ( Get(ScriptParameter); 2)]
Set Variable [ $newValue; Value:GetValue ( Get(ScriptParameter); 3)]
Set Variable [ $overwriteOriginal; Value:If(IsEmpty(GetValue ( Get(ScriptParameter); 4));1;GetValue ( Get(ScriptParameter); 4))]
Set Variable [ $setFromTag; Value:If(IsEmpty(GetValue ( Get(ScriptParameter); 5));0;GetValue ( Get(ScriptParameter); 5))]
# Probably want some integrity checking here!
If [ $setFromTag = True]
# Set tag to the contents of another tag
Set Variable [ $cmdToRun; Value:"cmd.exe /C exiftool "&
If($overwriteOriginal=1;"-overwrite_original ";"")&
"\"-model<${imagedescription;}\" \"" & $filename & "\"" ]
Else
# Set tag directly to entered text
Set Variable [ $cmdToRun; Value:"cmd.exe /C exiftool "&
If($overwriteOriginal=1;"-overwrite_original ";"")&
"-"&$tagtoSet&"=\""&$newValue&"\" \"" & $filename & "\"" ]
End If
# Execute the FMP command
Send Event [ open document/application; $cmdToRun ]
Exit Script [ ]

 

Link to comment
Share on other sites

1 hour ago, BAleiHi said:

I did try BaseElements' BE_ExecuteSystemCommand, which is supposed to wait for completion by default, but couldn't get it to do anything. 

I am surprised to hear that. I use the command several times a day - albeit on macOS. And the plugin is indispensable to me for other uses too.

 

1 hour ago, BAleiHi said:

My hypothetical workaround for this would be to pass in the original value of the tagToSet, then add a loop at the end that reads it until it has changed. 

I know very little about Windows scripting, but I believe you should be able to make it call a Filemaker script using the fmp URL protocol or perhaps through ActiveX Automation. So instead of looping break your script into two parts.

Another option is to pause the script long enough for the command to execute.

 

Link to comment
Share on other sites

Headaches abound trying to implement a wait loop.  So going back to BaseElements, perhaps you can shed some light there.  Since BE are only functions that are accessible through a calculation, I tried Set Variable( $test, BE_ExecuteSystemCommand, $cmd).  [An aside: what's the preferred way to call a BE function when I don't really care about what it returns?]  The $cmd I constructed works using SendEvent as long as I wait long enough.  It's cmd.exe /C exiftool  -overwrite_original "-model<${imagedescription;}" "<fullpath to filename>"

Any insights greatly appreciated.

Link to comment
Share on other sites

3 minutes ago, BAleiHi said:

I tried Set Variable( $test, BE_ExecuteSystemCommand, $cmd).

I actually do care about the returned result, even if it is just an error message, so I typically use:

Set Field [ Table::Result ; BE_ExecuteSystemCommand ( $command ) ]

But setting a variable should work too. However your posted code is invalid, and I am not sure if that's a real problem or just carelessness on your part. There also may be problems with how you handled the quotes and field references in the $cmd variable. Perhaps you should practice on a simple command first.

 

Link to comment
Share on other sites

Thanks for the hints...Turns out the issue is not with the set field vs. set variable.  Both behave the same.

It could certainly be with my syntax, but if so, it's not clear why.  I have been anything but careless and I bristle at the suggestion (after hours of testing to get it correct). You say the posted code is invalid.  If so, please specify what you think is invalid about it...that may be the issue (BTW, I use <> to show a variable file path - it's not literal text.)  Here is exactly what works in cmd,:

exiftool -overwrite_original "-model<${imagedescription;}" "G:/My Drive/IMG_2191.jpg"

Here is exactly what returns file not found in BE:

cmd.exe /C exiftool -overwrite_original "-model<${imagedescription;}" "G:/My Drive/IMG_2191.jpg"

I do note that there is a space in the path name that doesn't bother SendEvent but might trip up BE.  So I tried a path with no spaces.  Still no luck.  BE seems to be doing something with the ", <. $. {, or ; in the command line that SendEvent does not.  Any ideas?  Everything works when I set the tag to a literal text string so I know that the image file is OK.  I got the replace and indirection syntax straight from Phil Harvey along with double quotes, curly brackets and the semicolon (a trick to remove illegal windows filename characters from a string.  But he's not a FM or BE expert...  If you see a flaw, I'd love to know what it is.

Thanks!

 

 

Link to comment
Share on other sites

I would start by writing the command in a text field, and avoid any references to fields or variables. Just spell everything out, until you get the basic form working using:

Set Variable [ $test ; BE_ExecuteSystemCommand ( YourTable::Textfield ) ]

AFAIK, a path with a space must be quoted  (try using single quotes instead of double). And I doubt you need the "cmd.exe" part (again, I'm not on Windows, so I don't know).

Once you get something working, you can take it to next level by replacing hard-coded values with variables. I am not familiar with the method you describe, and I don't understand where the variable referenced in the command is supposed to be initialized. I certainly would not expect a variable reference in a command line to get the value from a variable defined in Filemaker script. My approach is to use placeholders in the command text and replace them using the Substitute() function before sending the command to be executed.

 

3 hours ago, BAleiHi said:

You say the posted code is invalid.  If so, please specify what you think is invalid about it...

I was referring to:

8 hours ago, BAleiHi said:

I tried Set Variable( $test, BE_ExecuteSystemCommand, $cmd). 

which needs to be:

Set Variable [ $test; BE_ExecuteSystemCommand ( $cmd ) ]

in order to be valid.

 

Link to comment
Share on other sites

Thank you comment for your patience and ideas.  I see that I was careless writing the post and not using the FMP syntax..will be more careful next time.  But to the main point, your suggestion to remove the cmd.exe /C part seems to have done the trick.  It tripped me up because when I set the tag with a literal text string "test me" it worked fine.  But with the more complex replacement syntax, it failed.  The /C after the command is a switch presumably implemented inside FMP's native SendEvent to say whether to return and close the window or leave the window open.  I'm not clear on why BE_ExecuteSystemCommand would behave differently for the two cases, but I can move forward!

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.