Results 1 to 20 of 20

Thread: [RESOLVED] Issues with: Writing metadata to jpg using exiftool and -stay_open

  1. #1

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Resolved [RESOLVED] Issues with: Writing metadata to jpg using exiftool and -stay_open

    Hi all, I need your help!

    Got the inspiration for the code below from this address: Using stay_open and visual basic

    There are no indications that the code worked in and I’ve been toying with it for some time with no luck.

    Can any of you see what is incorrect with the code?
    What is it doing? Simple: Writing the string “Make it work” to the MWG group tag “Description” of the image file x.jpg.

    For the example to work, put the latest exiftool.exe and an image named x.jpg in the c:\tmp folder and run the code.

    Code:
    Public Sub testArgFile()
    Dim fso As Object, wso As Object, w As Object, fileobj As Object
    Dim ScriptObj As Object, ts As Object
    Dim sCommand As String, sArgFile As String, sEXE As String
    
        'init
             sArgFile = "C:\tmp\EXIF.arg"
             sEXE = "c:\tmp\exiftool.exe"
             sCommand = """" & sEXE & """ -stay_open True @ """ & sArgFile & """"
        
        'Create empty arg file, start exiftool, wait for args...
             Set fso = CreateObject("Scripting.FileSystemObject")
             Set w = fso.CreateTextFile(sArgFile, True, False)
             Set fileobj = fso.getfile(sArgFile)
             w.Close
             Set wso = CreateObject("WScript.Shell")
             Set ScriptObj = wso.exec(sCommand)
    
         'write to arg file and tell exiftool to execute
            Set ts = fileobj.OpenAsTextStream(8, -1) '8=forappending, -1=unicode
            ts.writeline "-mwg:description=""Make it work"""
            ts.writeline "C:\tmp\x.jpg"
            ts.writeline "-execute"
            ts.writeline vbLf
            ts.Close
    
        'Close exiftool
            Set ts = fileobj.OpenAsTextStream(8, -1)
            ts.writeline "-stay_open"
            ts.writeline "false"
            ts.writeline vbLf
            ts.Close
       
         'kill objects
            Set ts = Nothing:   Set ScriptObj = Nothing
            Set wso = Nothing:  Set fileobj = Nothing
            Set w = Nothing:    Set fso = Nothing
        
    End Sub
    I know I can write this value to the file simply by executing "exiftool -mwg:description='Make it work' c:\tmp\x.jpg", but I plan to write 15 different tags to 1000+ files in unicode. "-stay_open" is the fastest way of doing that, I understand.
    Last edited by JohnPotier; Nov 6th, 2022 at 06:58 PM.

  2. #2
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,116

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    I know nothing of this "exiftool", but in the interest of maybe clarifying how this is even a VB question, if you were to perform these steps manually, can you outline what those steps would be?

    Edit: Perhaps it is as simple as building the argfile first before executing the exiftool. Because, as written, I'm not seeing how it makes sense to do it in the order you are, unless exiftool sits around and waits for a potentially non-existent argfile to be created. Either that, or I'm not understanding what this code is doing, or what tool is doing or how it works, which is entirely possible, and I'm not motivated to take time to try to learn about it.
    Last edited by OptionBase1; Nov 6th, 2022 at 07:00 PM.

  3. #3

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Hi Optionbase1. Now that's a fair question.

    As I wrote above (edited as you replied I guess): I can write to the file on the command line simply by: exiftool -mwg:description='Make it work' c:\tmp\x.jpg

    I'm preparing a listview control with all tags and values. Writing to all the files in the fastest way is my quest.

    Exiftool can actually run and wait for arguments to be written to the sArgFile. "-stay_open false" terminates the execution of exiftool as I understand it. I would have written this question in the EXIFTOOL forum, only I assume the challenge is pure VB related, and I find more knowledge for that here I guess.

    Reading your question(s) multiple times, I understand you want the pseudo code version of my code above.
    Imaging my listview, one file per line and all the values for each EXIF tag (metadata about the image: creator, copyright, description, city, state, country, GPS-coordinates, and so on) in columns. I want to write all that to the files.
    This can be done by loading exiftool.exe in memory
    Set ScriptObj = wso.exec(sCommand)

    ...and instruct it to wait for commands in the argument file.
    -stay_open True @ """ & sArgFile & """"

    In my case I would iterate over the columns and add one argument at the time for each metatag to write
    ts.writeline "-mwg:description=""Make it work"""

    ...and end with pointing to the file to write to and say "execute". The idea is that everything since last execute is treated as one command line
    ts.writeline "C:\tmp\x.jpg"
    ts.writeline "-execute"
    ts.writeline vbLf


    And sure, a little background on what is exiftool and the stay_open argument is in place. If you want, you can find the documentation here in the "Advanced options" chapter, scroll down to "-stay_open FLAG" section. I understand the intricacies of exiftool, but am not sure how VB can perform what exiftool wants.

    I suspect the issue might be that the argument file is created incorrectly, or that ts = fileobj.OpenAsTextStream(8, -1) is incorrect at that point. It could even be that i'm not able to do
    5) Write -stay_open\nFalse\n (or -stay_open\n0\n) to ARGFILE when done. correctly. I've tried vbCr, vbLf, vbCrLf and nothing but with no luck.
    Last edited by JohnPotier; Nov 6th, 2022 at 07:32 PM.

  4. #4
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    You'll need to add this cExec.cls class to an empty Std-EXE project first and here is a snippet which controls exiftool through stdin (using "-@ -") and receives results through stdout so no persistent temp file used for the inter-process communication.

    The snippet just sends -ver command 10 times in a row without waiting for any results on each command (which is deliberate) but checks for successful completion on the last command and receives all previous commands results in one go (which is fast).

    Code:
    Option Explicit
    
    Private Sub Form_Load()
        Const JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE As Long = &H2000
        Const EXIFTOOL_EXE  As String = "D:\TEMP\exiftool-12.49\exiftool.exe"
        Dim oExec           As cExec
        Dim lNumCommands    As Long
        Dim lIdx            As Long
        Dim sOutput         As String
        
        Set oExec = New cExec
        oExec.Run EXIFTOOL_EXE, "-stay_open true -@ -", StartHidden:=True, LimitFlags:=JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
        lNumCommands = 10
        For lIdx = 1 To lNumCommands
            oExec.WriteInput "-ver" & vbCrLf & "-execute" & lIdx & vbCrLf
        Next
        sOutput = pvWaitForOutput(oExec, "{ready" & lNumCommands & "}")
        Debug.Print sOutput
        oExec.WriteInput "-stay_open" & vbCrLf & "false" & vbCrLf
        Set oExec = Nothing
    End Sub
    
    Private Function pvWaitForOutput(oExec As cExec, sText As String) As String
        Dim sOutput         As String
        
        sOutput = oExec.ReadPendingOutput
        Do While InStr(sOutput, sText) = 0
            sOutput = sOutput & oExec.ReadOutput(1) & oExec.ReadPendingOutput
        Loop
        pvWaitForOutput = sOutput
    End Function
    The idea to use -execute1, -execute2, ... -executeN so that each command receives unique {ready1}, {ready2}, ... {readyN} is from this thread on exiftool forums.

    cheers,
    </wqw>

  5. #5

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Quote Originally Posted by wqweto View Post
    You'll need to add this cExec.cls class to an empty Std-EXE project first and here is a snippet which controls exiftool through stdin (using "-@ -") and receives results through stdout so no persistent temp file used for the inter-process communication.
    Ah, progress. Thank you for your time and effort wqweto. Do I understand it correctly that I need to create a separate VB project (1) that starts exiftool.exe? How do I bake this in with my existing project (2) where I plan to write all the information to the files? Do I start (1) manually or start it from within my existing project (2)?

    How do I send the information from my project (2) to the "-stay_open" instance of exiftool.exe?

    And, are you saying that the way I started this will not work at all? I guess that in my project (2), with my current implementation, exiftool.exe terminates before I start writing to the ARGFILE? I forgot to check Task Manager for a running exiftool.exe while debugging yesterday :-).

  6. #6
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Why not use a standard library?

    Code:
    Option Explicit
    
    'Reference to: Microsoft Windows Image Acquisition Library v2.0
    
    Private Sub Main()
        Dim ImageFile As WIA.ImageFile
    
        Set ImageFile = New WIA.ImageFile
        ImageFile.LoadFile "sample.jpg"
        With New WIA.ImageProcess
            .Filters.Add .FilterInfos("Exif").FilterID
            With .Filters.Item(1).Properties
                .Item("Remove").Value = False
                .Item("ID").Value = 270 'Exif.Image.ImageDescription
                .Item("Type").Value = StringImagePropertyType
                .Item("Value").Value = "Yabba dabba doo!"
            End With
            .Apply(ImageFile).SaveFile "sample new.jpg"
        End With
    End Sub

  7. #7
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Quote Originally Posted by JohnPotier View Post
    Ah, progress. Thank you for your time and effort wqweto. Do I understand it correctly that I need to create a separate VB project (1) that starts exiftool.exe? How do I bake this in with my existing project (2) where I plan to write all the information to the files? Do I start (1) manually or start it from within my existing project (2)?

    How do I send the information from my project (2) to the "-stay_open" instance of exiftool.exe?

    And, are you saying that the way I started this will not work at all? I guess that in my project (2), with my current implementation, exiftool.exe terminates before I start writing to the ARGFILE? I forgot to check Task Manager for a running exiftool.exe while debugging yesterday :-).
    All I wanted was my post to include a complete sample code i.e. starting from a blank Std-EXE project you add cExec class, paste the snippet in Form1, fix EXIFTOOL_EXE constant to point to your exiftool.exe and press F5.

    I could have implemented it to search for x.jpg in C:\Tmp and set "description" just to be more precise but I read the complete OP code after posting the snippet so this is what it is now.

    cExec has several methods and properties which should be named self-explanatory without resorting to reading the source code.

    Its main feature (which is direly missing from stock WshScriptExec object) is the StartHidden parameter of Run method which allows talking to a hidden instance of a concurrently running console application (like exiftool or stockfish or language server) with WriteInput and ReadOutput methods.

    cheers,
    </wqw>

  8. #8

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    I've copied the code for the class, started a new project, added a new class, pasted the code (1) and pasted your code on the std form's code (2). Pasting the code in the class (1) fails to the extent that it shows up like this:

    Code:
    Option Explicit
    
    VERSION 1.0 CLASS '<-- Initial error
    
    BEGIN
      MultiUse = -1  'True
      Persistable = 0  'NotPersistable
      DataBindingBehavior = 0  'vbNone
      DataSourceBehavior = 0   'vbNone
      MTSTransactionMode = 0   'NotAnMTSObject
    End
    
    Attribute VB_Name = "cExec"
    Attribute VB_GlobalNameSpace = False
    Attribute VB_Creatable = True
    Attribute VB_PredeclaredId = False
    Attribute VB_Exposed = False
    
    'rest seems ok...

    In the IDE the red text is not understood, right? What am I doing wrong?
    When runing the project, the initial error is at the end of the "VERSION..." statement above and says:

    Compile error: Exception: end of statement

  9. #9

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Struck me as I hit 'save'. That's not the way to implement the code...

    I reversed everything I did with the class file, removed it from the (now called "EXIFserver") project, opened the cls file in notepad and pasted all code there. Added the class to the project again, pointed EXIFTOOL_EXE to the local exiftool.exe. Run!

    SUCCESS!!!

    It runs and in immediate window I see:
    {ready1}
    12.49
    {ready2}
    12.49
    {ready3}
    12.49

    ...and so on

    I'm still at loss on how to build on this. How do I incorporate this into my existing project?

    The existing project is a tool where I populate a listview with all values for all tags to write to the files (Original date & time, MWG:Location, MWG:City, MWG:State, MWG:Country, GPS coordinates, Event, People in image, Source, Description, Digitized date, Original filename, Photographer/artist, Copyright). The speed of writing to the files is my major concern.

    My earlier attempt of tagging jpg-files was by building a batch-file that called exiftool.exe for each file with all the arguments. this took easily 1 second or more per file. Running this for 100s of files would seem to take forever.... In addition I get codepage challenges by using batch files. I write in Norwegian with our funky 3 letters ÆØÅ :- )
    Last edited by JohnPotier; Nov 7th, 2022 at 08:18 AM.

  10. #10

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Quote Originally Posted by JohnPotier View Post
    I'm still at loss on how to build on this...
    No, I'm not. I think I just got it. I just substitute this command with my own:
    oExec.WriteInput "-ver" & vbCrLf & "-execute" & lIdx & vbCrLf


    I do instead write:
    oExec.WriteInput "-DateTimeOriginal#=""1988:11:18 : : """ & vbcrlf & _
    "-OffsetTimeOriginal=+01:00" & vbcrlf & _
    "-XMP: DateCreated=""1988:11:18""" & vbcrlf & _
    "-MWG:Keywords+=""Christmas"""
    "-MWG:Keywords+=""Party""" & vbcrlf & _
    "-XMP:PersonInImage+=""McClain, John""" & vbcrlf & _
    "-XMP:PersonInImage+=""Holly M. Gennero""" & vbcrlf & _
    "-GPSLatitude*=34.0551881" & vbcrlf & _
    "-GPSLongitude*=-118.4132764" & vbcrlf & _
    "c:\tmp\x.jpg" & vbcrlf & _
    "-execute" & lIdx & vbCrLf


    (Ignore any errors in typing and quotes) Can't wait to get back into the lab and test. Thanks.
    Last edited by JohnPotier; Nov 7th, 2022 at 08:12 AM.

  11. #11
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    What I would do is prepare a Collection with commands that need to be send to exiftool based on the data in your listview. Each row has to have multiple commands in a separate batch string in the Collection without the final -executeN command.

    Then Run exiftool and loop the batch strings and send each one with corresponding -executeN appended and after each (or several) WriteInput calls I would fetch ReadPendingOutput and check for "{readyN}" reply so that I can update the UI by showing some progress and allow cancellation.

    Btw, this is not trivial to do and there are some gotchas with UI being responsive and etc.

    cheers,
    </wqw>

  12. #12

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Quote Originally Posted by dilettante View Post
    Why not use a standard library? (Microsoft Windows Image Acquisition Library v2.0)
    Now that's a brilliant idea. I didn't know this was possible. Do you have any idea how this performs compared to going the exiftool.exe route?

  13. #13
    PowerPoster
    Join Date
    Feb 2006
    Posts
    24,482

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    No, I don't. Are you planning to give thousands of files the same description or something?

    You could always try using the GDI+ Flat API directly instead. More effort to write and debug but it should shave off some time.

  14. #14

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Hi wqweto

    Code:
    oExec.Run EXIFTOOL_EXE, "-stay_open true -@ -", StartHidden:=True
    Success: Have success with your code. I am able to write to four files in a loop (demo).
    !Success: The exiftool.exe lingers after the code run.

    Terminating exiftool.exe/-stay_open:
    As the exe stays open and waits for even more commands is just natural. It won't die until we tell it to (or I close down VB :- ). Executing another command like the first but with the false option doesn't seem to do the trick either as I guess it just opens a new process for the exe.
    Code:
        'oExec.Run EXIFTOOL_EXE, "-stay_open false" & vbCrLf, StartHidden:=True
        oExec.Run EXIFTOOL_EXE, "-stay_open false", StartHidden:=True
    I tried StartHidden:=False. The window is now visible and terminating it, kills exiftool.exe. How can I address the initial instance of exiftool.exe in the code? Would I need a handle to the process running the exe?

  15. #15

  16. #16

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    I do exactly that:

    Code:
       Set oExec = New cExec
        oExec.Run EXIFTOOL_EXE, "-stay_open true -@ -", StartHidden:=False 'True
        
        For i = 1 To 4
            oExec.WriteInput "-comment=c" & i & vbCrLf & _
                "-xmp:description=d" & i & vbCrLf & _
                "c:\tmp\a b\x" & i & ".jpg" & vbCrLf & _
                "-execute" & i & vbCrLf
        Next
        
        Debug.Print pvWaitForOutput(oExec, "{ready" & i & "}")
        Set oExec = Nothing
    Not that, nor stoping the application kills the exe. Exiting the IDE does though.
    Last edited by JohnPotier; Nov 7th, 2022 at 04:59 PM.

  17. #17
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,120

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    It turned out exiftool with the -stay_open option set spawns a second copy of itself so when you set oExec to Nothing this terminates the first copy only but leaves the spawned one lingering.

    The proper way to communicate termination with exiftool is to send "-stay_open" & vbCrLf & "false" & vbCrLf as a command before setting oExec to Nothing based on this thread in their forum (you can search their forums for answers too).

    I've updated the sample code above with this fix and additionally used the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE limit flag which is a nice precautious feature on Run. It instructs Windows to terminate all spawned processes if you application crashes so these do not remain lingering no matter how your app is terminated (normal exit or not).

    cheers,
    </wqw>

  18. #18

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Quote Originally Posted by wqweto View Post
    It turned out exiftool with the -stay_open option set spawns a second copy of itself so when you set oExec to Nothing this terminates the first copy only but leaves the spawned one lingering.

    The proper way to communicate termination with exiftool is to send "-stay_open" & vbCrLf & "false" & vbCrLf as a command before setting oExec to Nothing...
    Thank you, wqweto. Can't wait to get back and try this! :-) Cheers!

  19. #19

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: Issues with: Writing metadata to jpg using exiftool and -stay_open

    Works perfectly. Thanks for the skeleton!

  20. #20

    Thread Starter
    Junior Member JohnPotier's Avatar
    Join Date
    Sep 2007
    Location
    Norway
    Posts
    25

    Re: [RESOLVED] Issues with: Writing metadata to jpg using exiftool and -stay_open

    See answer #4 from wqweto on Nov 7th, 2022, 09:40 AM
    for the implementation that works


    Thank you everyone who participated with solving this

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width