straight-shoota
5/21/2017 - 4:45 PM

Create Slideshow with Panzoom Effect in Adobe After Effects

Create Slideshow with Panzoom Effect in Adobe After Effects

//
// Copyright 2017 Johannes Müller <straightshoota@gmail.com>
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// 
// 
// This is a scipt for After Effects. Run it to create a composition containing
// a slideshow of images you select via a file chooser dialog.
// 
// 

// time span, a slide should be visible
var SLIDE_DURATION = 3; // in seconds
var TRANSITION_DURATION = 0.5; // in seconds
var TOTAL_DURATION = SLIDE_DURATION + TRANSITION_DURATION;

writeConsole("SLIDE_DURATION=" + SLIDE_DURATION);
writeConsole("TRANISTION_DURATION=" + TRANSITION_DURATION);

function createPanZoom(comp,layer) {
  var rulesOfThirdsPoints = [[1/3,1/3],[2/3,1/3],[1/3,2/3],[2/3,2/3]]; // points of interest in image
  var zoomModes = ["IN","OUT"];
    
  var rdIdx = Math.floor(Math.random() * rulesOfThirdsPoints.length);
  var f = rulesOfThirdsPoints[rdIdx];
  var deltaZoomPoint =  [f[0] * comp.width, f[1] * comp.height] - [comp.width/2,comp.height/2];
  
  var rdIdx = Math.floor(Math.random() * zoomModes.length);
  var zoomMode = zoomModes[rdIdx];

  var keyTimes = [0, TOTAL_DURATION];
  var keyValues;

  switch(zoomMode) {
    case "IN": 
      keyValues = [[100,100],[107,107]]; 
      break;
    case "OUT":
      keyValues = [[109,109],[100,100]]; 
      break;
    default: 
      break;
  }
  
  var nullL = comp.layers.addNull();
  
  layer.scale.expression = 
  "sx = 100 * thisComp.width / width; \r" +
  "sy = 100 * thisComp.height / height; \r" +
  "s = Math.max(sx,sy); \r" +
  "[s,s];";
  
  layer.parent = nullL;
  
  nullL.anchorPoint.setValue(nullL.anchorPoint.value + deltaZoomPoint);
  nullL.position.setValue(nullL.position.value + deltaZoomPoint);
  nullL.scale.setValuesAtTimes(keyTimes,keyValues);
}

function isInArray(array, element) {
  var found = false;
  for (var i = 0; !found && i < array.length; i++) {      
    if (array[i] == element) found = true;
  }   
  return found; 
}

function isImageFile(fileName) {  
  var ext = fileName.split(".").pop().toUpperCase();    
  var imageFormats = ["BMP", "CIN", "IIF", "EXR", "GIF", "JPG", "JPEG", "PCX", "PCT", "PNG", "PSD", "PXR", "HDR", "SGI", "TIF", "TGA"]; 
  return isInArray(imageFormats, ext);
}

function run() {
  var imagesFolder = defaultFolder.selectDlg("Select images folder:");
  if (imagesFolder) {
    defaultFolder = imagesFolder;
    
    app.beginUndoGroup("PanZoom.jsx");
    
    var assetFolder = app.project.items.addFolder("PanZoom Assets  - " + File.decode(imagesFolder.name));
    
    var comps = [];
    
    var files = imagesFolder.getFiles();
    
    clearOutput();
    
    for (var i = 0; i < files.length; i++) {
      if (isImageFile(files[i].fsName)) {
        clearOutput();
          
        var io = new ImportOptions();
        var item;
        try
        {
          io.file = files[i];
          if (io.canImportAs(ImportAsType.FOOTAGE)) {
            io.importAs = ImportAsType.FOOTAGE;
          }
          item = app.project.importFile(io);
        } catch(e) {
          item = app.project.importPlaceholder(files[i].name,1920,1080,25,3600);
        }
            
        if (item) {
          item.selected = false;
          
          writeLn((i+1) + "/" + files.length + ": " + item.name);
            
          var comp = app.project.items.addComp(item.name,item.width,item.height,item.pixelAspect,TOTAL_DURATION,25);
          var layer = comp.layers.add(item);
          createPanZoom(comp,layer);
          
          item.parentFolder = assetFolder;
          comp.parentFolder = assetFolder;
          
          comps.push(comp);
        }
      }
    }
    
    // create final comp
    if (comps.length > 0)
    {     
      var finalComp = app.project.items.addComp("Final - " + File.decode(imagesFolder.name),1920,1080,1,comps.length * SLIDE_DURATION,25),
          next_slide_animation_index = 5,
          slide_animation_distance = 6
      
      for (var i = 0; i < comps.length; i++) {
        writeLn("Final Comp, Layer: " + (i+1) + "/" + comps.length);

        var layer = finalComp.layers.add(comps[i]);

        // scale to cover composition size
        layer.scale.expression = 
        "sx = 100 * thisComp.width / width; \r" +
        "sy = 100 * thisComp.height / height; \r" +
        "s = Math.max(sx,sy); \r" +
        "[s,s];";

        var startTime = i * SLIDE_DURATION - TRANSITION_DURATION;
        layer.startTime = startTime;

        // add a white effect every six slides for some 
        if(i == next_slide_animation_index){
          var keyTimes = [startTime, startTime + TRANSITION_DURATION];
          var keyValues = [100,0];
          layer.Effects.addProperty("Linear Wipe");
          var wipe = layer.Effects.property("Linear Wipe");
          wipe.property("Wipe Angle").setValue(0);
          wipe.property("Transition Completion").setValuesAtTimes(keyTimes, keyValues);
          //wipe.property("Feather").setValue(80);
          next_slide_animation_index = i + slide_animation_distance
        }
      }

      finalComp.workAreaDuration = Math.max(finalComp.frameDuration, startTime);
      finalComp.selected = true;
    }
    
    if (assetFolder.numItems < 1)
      assetFolder.remove();
    
    writeLn("Done !");
    
    app.endUndoGroup();   
  }
}

var defaultFolder;
if (defaultFolder == null) {
  defaultFolder = Folder.current;
}

run();