Skip navigation
Currently Being Moderated

4000. + a question re external files.

Jun 12, 2009 5:57 AM

Hey folks, seeing as I hang here most, I figure it's the best place for my 4000th post on Adobe Forums (get a life!).

 

Does anyone have a little tutorial on passing the rendered photos to an external file? I want it inside a normal plugin, not as a post process action.

 

It's for an entirely personal project, passing images to ffmpeg to have my timelapse movies created with an export from Lightroom.

 
Replies
  • Currently Being Moderated
    Jun 12, 2009 4:26 PM   in reply to Seán McCormack

    Sean - Are you looking for sample code that sets up a command line and then launches an external app? I have this for ImageMagick's convert which I can post here along with comments. My code does this once per exported image though rather than build a list of the images and pass them all at once which is what it sounds like you're trying to do. Not that adding that extra bit should be hard. Let me know and I'll share if relevant.

     

    Dave

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 12:55 AM   in reply to Seán McCormack

    Does this snippet from my exiftool plugin help? It's sending mulitple variables to the selected thumbnail (effectively extending Ctrl/Cmd S) .

     

    John

     

     

    if WIN_ENV == true then
    command = '"' .. LrPathUtils.child(LrPathUtils.child( _PLUGIN.path, "win"), "exiftool.exe") .. '" ' .. newUrgency .. ' "' .. phoPath .. '" ' .. newOverwrite
    quotedCommand = '"' .. command .. '"'
    else command = '"' .. LrPathUtils.child(LrPathUtils.child(_PLUGIN.path, "mac"), "exiftool") .. '" ' .. newUrgency .. ' "' .. phoPath .. '" ' .. newOverwrite quotedCommand = command
    end
     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 4:58 AM   in reply to Seán McCormack

    John's reply shows what to do in essential form. With no offense intended to John, I think this can be improved upon in two ways. I find that all of the concatenation operators make things hard to read. I also find that keeping entirely separate versions for Windows vs. Mac is potentially error prone when the only thing that actually changes is the name of the executable.

     

    What I prefer to do is make a table for the parameters, insert them one by one, then concatenate the table contents at the end. Here is an abridged version of the code I use with edits for your app (this formatting stinks - John,  how did you get your code to look like that in the embedded window?):

     

    local params = {}


    if WIN_ENV == true then
        table.insert( params, '"ffmpeg.exe"')
    else
        table.insert( params, '"ffmpeg"')
    end


    table.insert( params, "-r " .. exportPresetFields.fr )
    table.insert( params, "-b " .. exportPresetFields.br )
    table.insert( params, "-i " .. exportPresetFields.moviename )


    -- combine params into one string with a space inbetween

    local execString = table.concat( params, " " )


    logmsg ( "Running app with shell command: " .. execString )


    local result = LrTasks.execute( execString )
    logmsg( "The result is: " .. result );
    if ( result ~= 0 ) then
        logmsg( "ERROR: " .. result )
    end

     

    The logmsg() function is just my wrapper around a LR logging function. This is all a bit simplified from my actual code for clarity. For instance, to collect the output of the application into a file, I actually have this as the very last thing inserted into the table:

     

    if ( debugMode ) then
        table.insert( params, ">> debugLog.txt 2>&1" )
    end

     

    This redirects the normal and error output into debugLog.txt. If I recall, you're on a Mac. I'm on Windows and I can offer up another trick or two about managing the console window that appears (or not), etc. but maybe not important since this is a plugin for yourself.

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 5:36 AM   in reply to DFBurns

    No offence taken, Dave. I'm now picking up speed with this Lua stuff and am very confident I'm doing some things in a crude and inelegant manner!

     

    To get the code looking OK here, I switched to HTML view and then use the pre HTML tag.

     

    John

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 7:21 AM   in reply to Seán McCormack

    Sean - I have no access to a Mac so please let me know if the code works as expected there. Especially the redirect to a file. It comes down to how Adobe has chosen to launch other apps from LR on the Mac. If they're launching it via the default command shell (which I believe is bash on a Mac) then that redirect should work. This is useful for me as well since when it comes time to make a plugin available to the community, it's one less reason for me to go buy a Mac just to test it. :-)

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 8:24 AM   in reply to DFBurns

    FYI The reason for that Mac/Win code was originally because of these shell differences. On PC, I could use LrShell to launch a PDF directly - just sending its name launched it in Acrobat Reader. That default app approach failed on Mac and I was forced to point LrTasks at Preview.

    John

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 1:46 PM   in reply to Seán McCormack

    In your processRenderedPhotos(), you have a loop where you go through all of the exportContext:renditions one by one (standard stuff for almost all export plugins). You're probably launching the app within that loop. Move it after the loop so it launches a single time once all photos are rendered.

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 5:41 PM   in reply to DFBurns

    DFBurns wrote:

    ...

    local params = {}

     

    if WIN_ENV == true then
        table.insert( params, '"ffmpeg.exe"')
    else
        table.insert( params, '"ffmpeg"')
    end

     

    table.insert( params, "-r " .. exportPresetFields.fr )
    ...

    Thanks for sharing!  This approach is much more elegant than what I had been using up until now.

     

    Matt

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 10:19 PM   in reply to Seán McCormack

    That's probably a matter of choosing the right options for ffmpeg. I've never used it myself but I've heard that it's pretty decent. When I've done time-lapse movies, I did it manually using Quicktime Pro. A quick Google around shows that there is a scripting interface for QT at least on Windows using COM. You can write that script (sort of like VBScript) to a file then launch that script to do the work. A kludge but it'd probably work. :-) See here for info:

     

    http://www.xsi-blog.com/archives/103

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 13, 2009 10:22 PM   in reply to Matt Dawson

    Matt - It really keeps things sane when you have 18 command line options to pass to ImageMagick like my code does. When/if you need to reorder options is cleaner with this technique as well. Just cut the line and paste it in the new location. Cheers,

     

    Dave

     
    |
    Mark as:
  • Currently Being Moderated
    Jun 15, 2009 2:31 AM   in reply to Seán McCormack

    Good advice to build your argument string using a table and then concat the table at the end - as well as tidier code, this is faster than building strings using 'x .. y'.  You can make that faster still by using:

     

    myTable[#myTable + 1] = "some text"

     

    rather than:

     

    table.insert(myTable, "some text")

     

    An inline expression is generally faster than calling a function.

     

    Sean, on your question of finding the last photo from filterContext:renditions - if you know all the files are the same size, can't you get your values once and not call the two functions again - i.e. get the first photo's data rather than try to get the last.

     
    |
    Mark as:

More Like This

  • Retrieving data ...

Bookmarked By (0)

Answers + Points = Status

  • 10 points awarded for Correct Answers
  • 5 points awarded for Helpful Answers
  • 10,000+ points
  • 1,001-10,000 points
  • 501-1,000 points
  • 5-500 points