Skip to main content
Inspiring
March 23, 2023
Answered

Does exportFramePNG() still work??

  • March 23, 2023
  • 3 replies
  • 1036 views

I'm aware this is part of the QE DOM which isn't (for some reason) officially supported - shame because it seems to be able to do a lot of useful things!

 

I want a script I can run which will iterate through the current timeline, and for any track items whose name includes "preview", output a thumbnail frame of that clip to a folder. (I'm working with a lot of temp stock, and when the time comes to swap out all the items the client's chosen, it's a huge drag to compile a list manually that I can send to the person who's buying the stock. I want thumbnails not just names, to minimise the problem of them buying the wrong clip.)

 

QE seems to have a exportFramePNG() function, referenced here. That code suggests it takes two parameters: a timecode, in the format HH_MM_SS_FF, and a file path. So I'd expect something like this to work, on Windows - but it doesn't.

 

 

function secsToTimecode(sq, tm, d) { // hacky way to return a timecode with underscores
    if (d == '') d = ":";
    tps = 254016000000;
    tb = sq.timebase; // ticks per frame
    fps = tps/tb;
    // frames
    ff = Math.round((tm - Math.floor(tm)) * fps);
    if (ff < 10) ff = '0' + ff;
    
    // secs
    ss = Math.floor(tm)%60;
    if (ss < 10) ss = '0' + ss;
    
    // mins
    mm = Math.floor(tm/60)%60;
    if (mm < 10) mm = '0' + mm;
    
    // hrs
    hh = Math.floor(tm/3600)%60;
    if (hh < 10) hh = '0' + hh;
    
    return hh + d + mm + d + ss + d + ff;
}

app.enableQE();
sqq = qe.project.getActiveSequence(); // QE version!
op = sqq.outPoint;
sq = app.project.activeSequence;
videoTracks = sq.videoTracks;
var outputPath = new File("C:\Users\Username\Desktop\frames");

for (i = 0; i < videoTracks.numTracks; i++) {
    trk = videoTracks[i];
    for(j = 0; j  < trk.clips.numItems; j++) {
        nm = trk.clips[j].name ;
        if (nm.toUpperCase().indexOf("PREVIEW") != -1) { // Preview clip
            if (trk.clips[j].start.seconds < op.secs) { // ignore any clips after end of work area
                $.writeln(nm + ", T: " + trk.clips[j].start.seconds + ", Dur: " + trk.clips[j].duration.seconds); // This works as expected
                tm = secsToTimecode(sq, trk.clips[j].start.seconds + (trk.clips[j].duration.seconds/2), '_'); // pick an export point that's halfway through the clip
                sqq.exportFramePNG(tm, outputPath.fsName + '\\' + nm + ".png"); // This does nothing!
            } 
        }
    }
}

 

 

This topic has been closed for replies.
Correct answer Bruce Bullis

I reached out directly to Nick, with some questions and suggestions. 

3 replies

DefeiSoft
Participant
January 31, 2024

Still work, but there is a small mistak in github example.

I have revised the mistake and the following code will work.

exportCurrentFrameAsPNG();
function exportCurrentFrameAsPNG() {
    app.enableQE();
    var activeSequence = qe.project.getActiveSequence();
    if (activeSequence) {
        var time = activeSequence.CTI.timecode; // CTI = Current Time Indicator.
        var removeThese = /:|;/ig;  // Why? Because Windows chokes on colons in file names.
        var timewin = time.replace(removeThese, '_'); //defei revised
        var outputPath = new File("~/Desktop");
        var outputFileName = outputPath.fsName + getSep() + timewin + '_' + activeSequence.name; //defei revised
        activeSequence.exportFramePNG(time, outputFileName);
    } else {
        alert("No active sequence.");
    }
}
function getSep() {
    if (Folder.fs === 'Macintosh') {
        return '/';
    } else {
        return '\\';
    }
}
Inspiring
March 24, 2023

Classic mistake here. I didn't escape the backslashes, so the outputPath should have been

"C:\\Users\\Username\\Desktop\\frames"

Changing the rest of the code to conform with what's in PProPanel means it now works.

Bruce Bullis
Community Manager
Community Manager
March 23, 2023
Inspiring
March 23, 2023

Thanks Bruce. I can't make that work, though. Here's the adapted (hacky as hell) code, but although it looks like it's stepping through the timeline and adjusting the in/out points as it goes, it's not outputting anything:

sq = app.project.activeSequence;
videoTracks = sq.videoTracks;
op = sq.getOutPointAsTime();
tps = 254016000000;
tb = sq.timebase;
oneframe = tb/tps; // should be the duration of one frame, in seconds
$.writeln("End: " + op.seconds);
var outputPath		= new File("C:\Users\Username\Desktop\frames");

var oldInPoint = sq.getInPointAsTime();
var oldOutPoint = sq.getOutPointAsTime();

for (i = 0; i < videoTracks.numTracks; i++) {
    trk = videoTracks[i];
    for(j = 0; j  < trk.clips.numItems; j++) {
        nm = trk.clips[j].name ;
        if (nm.toUpperCase().indexOf("PREVIEW") != -1) {
            if (trk.clips[j].start.seconds < op.seconds) {
                $.writeln(nm + ", T: " + trk.clips[j].start.seconds + ", Dur: " + trk.clips[j].duration.seconds);
                tm = secsToTimecode(sq, trk.clips[j].start.seconds + (trk.clips[j].duration.seconds/2), '_');
                sq.setInPoint(trk.clips[j].start.seconds + (trk.clips[j].duration.seconds/2));
                sq.setOutPoint(trk.clips[j].start.seconds + (trk.clips[j].duration.seconds/2));
                
                var removeUponCompletion 	= 0;
                var startQueueImmediately 	= true;
                var jobID_InToOut = app.encoder.encodeSequence(sq, outputPath.fsName + '\\' + nm + ".png", "C:\Users\Username\Documents\Adobe\Adobe Media Encoder\23.0\Presets\jpeg-frame.epr", app.encoder.ENCODE_IN_TO_OUT, removeUponCompletion, startQueueImmediately);
            }
        }
    }
}

sq.setInPoint(oldInPoint.seconds);
sq.setOutPoint(oldOutPoint.seconds);

The .epr file is one I made for this, so it exists.

Inspiring
March 23, 2023

also this looks like it'll encode via AME? Or will it come direct from Premiere? (In some ways I'd rather it comes direct from Premiere and locks the program up for a minute or two, rather than exporting dozens of queue items to AME.)