0

What I'm trying to do:

  1. Batch export
  2. Optiimize for web (Jpeg)

My layers structure:

Layer1 --- Logo
Layer2 --- Adjustment layer (Brightness and Control)
Folder-A
~~ Layer3 -- image
~~ Layer4 -- image
~~ Layer5 -- image
~~ ..... (more layers)
Folder-B
~~ Layer6 -- image
~~ Layer7 -- image
~~ Layer8 -- image
~~ ..... (more layers)

I want to batch export the image layers to individual files and optimized each image for web. I figured I could export layers into individual files and use automate batch action to optimize for web.

I use Export layers as PNG but it doesn't merge the logo layer with the image layer. I need the logo to appear on each image layer. Is there a way to achieve this?

6
  • I think I've made a script that does what you want... or at least almost (Image): Export document for each layer inside selected group.jsx — The only thing is it only supports one source folder at a time.
    – Joonas
    Commented May 20, 2021 at 11:52
  • Hi @Joonas, Thanks! Just to make sure I understand how it works, will it merge Logo layer + Image layer 1 = combined-jpeg-1, Logo Layer + Image layer 2 = combined-jpeg-2 , Logo layer + image layer 3 = combined-jpeg3 ..... etc Commented May 20, 2021 at 12:04
  • I believe you go it. Depending on how you look at it, it doesn't really merge anything. It simply saves the entire document for each layer inside the selected group. It starts by hiding every layer inside the selected group, then one by one it selects each layer in turn, makes the layer visible and saves the document. So basically everything outside of the selected group appears in every single image the script saves.
    – Joonas
    Commented May 20, 2021 at 12:07
  • @Joonas Works like a charm! Thanks! Can you provide this as an answer? Commented May 20, 2021 at 12:31
  • 1
    If you change this line to say = 12
    – Joonas
    Commented May 20, 2021 at 12:45

1 Answer 1

2

I've made a script that does almost exactly that (in terms of end result... It doesn't really merge anything). The thing is, it only supports one source folder at a time.

Export document for each layer inside selected group.jsx.

enter image description here

The way it works:

  1. First it hides all layers in the first level of the selected folder
  2. Then it loops through each of those layers performing these actions on each layer:
    1. Shows the current layer (which can also be a group)
    2. Saves the document
    3. Hides the current layer

So anything outside of the selected group is visible in every single output image.

// Name: Export document for each layer inside selected group.jsx
// Formerly: Export Layers Inside Selected Group.jsx

// Description: Photoshop script that saves the whole document for each top level layer inside the selected group.
// Image example: https://user-images.githubusercontent.com/1164476/49152494-aef8af00-f31b-11e8-80ff-d774e3103eae.png

// https://gist.github.com/joonaspaakko/013a223e94ba0fb9a2a0

#target photoshop

try {
  var doc = app.activeDocument;
    var n = 0;
    var duplicates = {};
}
catch (e) {
  alert( 'Open a document first...' );
}

function processLayers( options) {
    
    var group       = doc.activeLayer;
    var groupLength = group.layers.length;
    
    var visibleArray = [];
    
    // HIDE ALL LAYERS
    for ( var i = 0; i < groupLength; i++ ) {
        visibleArray.push( group.layers[i].visible );
        group.layers[i].visible = false;
    }
    
    // START SAVING
    options.docName = doc.name.split('.')[0]; // Assumes filename contains only one period before the extion.
    for ( var i = 0; i < groupLength; i++ ) {
        
        var layer = group.layers[ i ];
        
        options.layerName = layer.name;
        options.layerIndex = i+1;
        
        layer.visible = true;
        save.file( options );
        layer.visible = false;
        
    }
    
    // RESTORE VISIBILITY
    for ( var i = 0; i < groupLength; i++ ) {
        group.layers[i].visible = visibleArray[i];
    }
    
    doc.activeLayer = group;

    alert('Done!'); // There's no error check so who am I to say if the files were saved, but at least the script is done...
    
}

var save = {
    file: function( options ) {
        
        var saveOptions = {};
        
        for ( var i=0; i < options.fileFormats.length; i++ ) {
            
            var fileformat = options.fileFormats[i];
            var destinationFolder = options.destination + "/" + fileformat.toUpperCase();
            
            makeFolder( destinationFolder ); // If it doesn't exist already...
            
            var filename = '';
            filename += options.prefix;
            filename += options.useLayerName ? options.layerName : options.custonName;
            filename += options.suffix;
            
            // IF FILENAME CONTAINS A DOLLAR SIGN
            if ( filename.match(/\$/) !== null ) {
                filename =  filename.replace('$',options.layerIndex);
            }
            // IF FILENAME DOESN'T HAVE THE DOLLAR SIGN AND A
            // DUPLICATE FILENAME IS FOUND, ADD A NUMBER ANYWAYS.
            else {
                
                if ( typeof duplicates[ fileformat ] == 'undefined' ) {
                    duplicates[ fileformat ] = {};
                }
                
                var duplicateNumber = '';
                if ( typeof duplicates[ fileformat ][ filename ] === 'object' ) {
                    duplicateNumber = ' ' + duplicates[ fileformat ][ filename ].length;
                    duplicates[ fileformat ][ filename ].push( filename );
                }
                else {
                    duplicates[ fileformat ][ filename ] = [ filename ];
                }
                
                filename += duplicateNumber;
            }
            
            doc.saveAs( File( destinationFolder + "/" + filename ), save[ fileformat ](), true );
            
        }
        
    },
    psd: function() {
        
        var psd_saveOpts = new PhotoshopSaveOptions();
        
        psd_saveOpts.layers            = true;
        psd_saveOpts.embedColorProfile = true;
        psd_saveOpts.annotations       = true;
        psd_saveOpts.alphaChannels     = true;
        
        return psd_saveOpts;
        
    },
    pdf: function() {
        
        var presetName = '[High Quality Print]';
        
        var pdf_SaveOpts = new PDFSaveOptions();
        
        pdf_SaveOpts.pDFPreset = presetName;
        
        return pdf_SaveOpts;
        
    },
    jpeg: function() {
        
        var jpg_SaveOpts = new JPEGSaveOptions();
        
        jpg_SaveOpts.matte   = MatteType.WHITE;
        jpg_SaveOpts.quality = 10;
        jpg_SaveOpts.formatOptions.STANDARDBASELINE;
        
        return jpg_SaveOpts;
        
    },
    png: function() {
        
        var png_SaveOpts = new PNGSaveOptions();
        
        png_SaveOpts.compression = 9;
        png_SaveOpts.interlaced = false;
        
        return png_SaveOpts;
        
    },
    tiff: function() {
        
        var tiff_SaveOpts = new TiffSaveOptions();
        
        tiff_SaveOpts.alphaChannels      = true;
        tiff_SaveOpts.annotations        = true;
        tiff_SaveOpts.imageCompression   = TIFFEncoding.JPEG;
        tiff_SaveOpts.interleaveChannels = true;
        tiff_SaveOpts.jpegQuality        = 10;
        tiff_SaveOpts.layers             = true;
        tiff_SaveOpts.layerCompression   = LayerCompression.ZIP;
        tiff_SaveOpts.transparency       = true;
        
        return tiff_SaveOpts;
        
    }
};

function makeFolder( path ) {
  var newFolder = Folder( path );
  if( !newFolder.exists ) newFolder.create();
}

if ( app.documents.length > 0 ) {
  if ( app.activeDocument.activeLayer.layers ) {
        init();
  }
  else {
    alert( "Error: \nSelect a parent group of the layers you want to export.")
  }
}

function init() {
    
    /*
    Code for Import https://scriptui.joonas.me — (Triple click to select):
    {"items":{"item-0":{"id":0,"type":"Dialog","parentId":false,"style":{"text":"Export document for each layer inside selected group.jsx","preferredSize":[0,0],"margins":16,"orientation":"column","spacing":10,"alignChildren":["center","top"]}},"item-1":{"id":1,"type":"Checkbox","parentId":6,"style":{"text":"PSD","preferredSize":[0,0],"alignment":null}},"item-2":{"id":2,"type":"Checkbox","parentId":6,"style":{"text":"TIFF","preferredSize":[0,0],"alignment":null}},"item-3":{"id":3,"type":"Checkbox","parentId":6,"style":{"text":"JPEG","preferredSize":[0,0],"alignment":null,"checked":true}},"item-4":{"id":4,"type":"Checkbox","parentId":6,"style":{"text":"PNG","preferredSize":[0,0],"alignment":null}},"item-5":{"id":5,"type":"Checkbox","parentId":6,"style":{"text":"PDF","preferredSize":[0,0],"alignment":null}},"item-6":{"id":6,"type":"Panel","parentId":9,"style":{"text":"","preferredSize":[0,0],"margins":10,"orientation":"row","spacing":10,"alignChildren":["center","top"],"alignment":null}},"item-7":{"id":7,"type":"Panel","parentId":9,"style":{"text":"","preferredSize":[0,0],"margins":10,"orientation":"column","spacing":10,"alignChildren":["left","top"],"alignment":null}},"item-8":{"id":8,"type":"EditText","parentId":14,"style":{"text":"","preferredSize":[90,0],"alignment":null}},"item-9":{"id":9,"type":"Group","parentId":0,"style":{"preferredSize":[0,0],"margins":0,"orientation":"column","spacing":10,"alignChildren":["fill","top"],"alignment":null}},"item-10":{"id":10,"type":"Group","parentId":0,"style":{"preferredSize":[0,0],"margins":[15,0,10,0],"orientation":"row","spacing":10,"alignChildren":["left","top"],"alignment":null}},"item-11":{"id":11,"type":"Button","parentId":10,"style":{"text":"Save","justify":"center","preferredSize":[0,0],"alignment":null}},"item-12":{"id":12,"type":"Button","parentId":10,"style":{"text":"Cancel","justify":"center","preferredSize":[0,0],"alignment":null}},"item-13":{"id":13,"type":"StaticText","parentId":14,"style":{"text":"Prefix:","justify":"left","preferredSize":[0,0],"alignment":null}},"item-14":{"id":14,"type":"Group","parentId":22,"style":{"preferredSize":[0,0],"margins":0,"orientation":"column","spacing":10,"alignChildren":["left","top"],"alignment":null}},"item-15":{"id":15,"type":"Checkbox","parentId":7,"style":{"text":"Use layer name","preferredSize":[0,0],"alignment":null,"checked":false}},"item-16":{"id":16,"type":"Group","parentId":22,"style":{"preferredSize":[0,0],"margins":0,"orientation":"column","spacing":10,"alignChildren":["left","top"],"alignment":null}},"item-17":{"id":17,"type":"StaticText","parentId":16,"style":{"text":"Custom name:","justify":"left","preferredSize":[0,0],"alignment":null}},"item-18":{"id":18,"type":"EditText","parentId":16,"style":{"text":"File Name ","preferredSize":[160,0],"alignment":null}},"item-19":{"id":19,"type":"Group","parentId":22,"style":{"preferredSize":[0,0],"margins":0,"orientation":"column","spacing":10,"alignChildren":["left","top"],"alignment":null}},"item-20":{"id":20,"type":"StaticText","parentId":19,"style":{"text":"Suffix:","justify":"left","preferredSize":[0,0],"alignment":null}},"item-21":{"id":21,"type":"EditText","parentId":19,"style":{"text":"","preferredSize":[90,0],"alignment":null}},"item-22":{"id":22,"type":"Group","parentId":7,"style":{"preferredSize":[0,0],"margins":0,"orientation":"row","spacing":10,"alignChildren":["left","center"],"alignment":null}},"item-23":{"id":23,"type":"Divider","parentId":7,"style":false},"item-24":{"id":24,"type":"StaticText","parentId":7,"style":{"text":"Dollar symbol ($) is replaced with incremental numbers","justify":"left","preferredSize":[0,0],"alignment":"center"}}},"order":[0,9,7,15,23,22,14,13,8,16,17,18,19,20,21,24,6,3,4,1,5,2,10,12,11],"activeId":10}
    */

    // DIALOG
    // ======
    var dialog = new Window("dialog");
        dialog.text = "Export document for each layer inside selected group.jsx";
        dialog.orientation = "column";
        dialog.alignChildren = ["center","top"];
        dialog.spacing = 10;
        dialog.margins = 16;

    // GROUP1
    // ======
    var group1 = dialog.add("group");
        group1.orientation = "column";
        group1.alignChildren = ["fill","top"];
        group1.spacing = 10;
        group1.margins = 0;

    // PANEL1
    // ======
    var panel1 = group1.add("panel");
        panel1.orientation = "column";
        panel1.alignChildren = ["left","top"];
        panel1.spacing = 10;
        panel1.margins = 10;

    var checkbox1 = panel1.add("checkbox");
        checkbox1.text = "Use layer name";

    var divider1 = panel1.add("panel");
        divider1.alignment = "fill";

    // GROUP2
    // ======
    var group2 = panel1.add("group");
        group2.orientation = "row";
        group2.alignChildren = ["left","center"];
        group2.spacing = 10;
        group2.margins = 0;

    // GROUP3
    // ======
    var group3 = group2.add("group");
        group3.orientation = "column";
        group3.alignChildren = ["left","top"];
        group3.spacing = 10;
        group3.margins = 0;

    var statictext1 = group3.add("statictext");
        statictext1.text = "Prefix:";

    var edittext1 = group3.add("edittext");
        edittext1.minimumSize.width = 90;

    // GROUP4
    // ======
    var group4 = group2.add("group");
        group4.orientation = "column";
        group4.alignChildren = ["left","top"];
        group4.spacing = 10;
        group4.margins = 0;

    var statictext2 = group4.add("statictext");
        statictext2.text = "Custom name:";

    var edittext2 = group4.add("edittext");
        edittext2.text = "File Name ";
        edittext2.minimumSize.width = 160;

    // GROUP5
    // ======
    var group5 = group2.add("group");
        group5.orientation = "column";
        group5.alignChildren = ["left","top"];
        group5.spacing = 10;
        group5.margins = 0;

    var statictext3 = group5.add("statictext");
        statictext3.text = "Suffix:";

    var edittext3 = group5.add("edittext");
        edittext3.minimumSize.width = 90;

    // PANEL1
    // ======
    var statictext4 = panel1.add("statictext");
        statictext4.text = "Dollar symbol ($) is replaced with incremental numbers";
        statictext4.alignment = ["center","top"];

    // PANEL2
    // ======
    var panel2 = group1.add("panel");
        panel2.orientation = "row";
        panel2.alignChildren = ["center","top"];
        panel2.spacing = 10;
        panel2.margins = 10;

    var checkbox2 = panel2.add("checkbox");
        checkbox2.text = "JPEG";
        checkbox2.value = true;

    var checkbox3 = panel2.add("checkbox");
        checkbox3.text = "PNG";

    var checkbox4 = panel2.add("checkbox");
        checkbox4.text = "PSD";

    var checkbox5 = panel2.add("checkbox");
        checkbox5.text = "PDF";

    var checkbox6 = panel2.add("checkbox");
        checkbox6.text = "TIFF";

    // GROUP6
    // ======
    var group6 = dialog.add("group");
        group6.orientation = "row";
        group6.alignChildren = ["left","top"];
        group6.spacing = 10;
        group6.margins = [0,15,0,10];

    var button1 = group6.add("button", undefined, undefined, {name:"cancel"});
        button1.text = "Cancel";
        button1.justify = "center";

    var button2 = group6.add("button", undefined, undefined, {name:"ok"});
        button2.text = "Save";
        button2.justify = "center";
  
    
    // DIALOG CUSTOMIZATION
    var filename = edittext2;
    filename.text = app.activeDocument.name.split()[0]; // Assumes filename contains only one period before the extion.
    filename.active = true;
    
  var useLayerName = checkbox1;
  useLayerName.onClick = function() {
    var check = this.value;
    var customName = edittext2;
    if ( check ) customName.enabled = !check;
    else customName.enabled = !check;
  };
  
  var cancelBtn = button1;
  cancelBtn.onClick = function() {
        dialog.close();
  };
  
  var saveBtn = button2;
  saveBtn.onClick = function() {
        n = ++n;
        if ( n === 1 ) {
            
        var formatsArray = [];
        var formats = panel2.children;
        for (var i = 0; i < formats.length; i++) {
                var format = formats[i];
                if ( format.value ) {
                    formatsArray.push( format.text.toLowerCase() );
                }
        }
            
            var path = '';
            try { path = doc.path; } catch(e) {}
            
        var options = {
          useLayerName: useLayerName.value,
          fileFormats: formatsArray,
          prefix: edittext1.text,
          custonName: edittext2.text,
          suffix: edittext3.text,
                destination: Folder.selectDialog( 'Select destination folder...', path )
        };
        
        dialog.close();
        
            if ( options.destination ) {
                processLayers( options );
            }
            
        }
  };
    
    dialog.show();
    
}
2
  • 1
    I have another script that is for batch replacing the contents in a mockup PSD, but this could be used to achieve the same end result... if each of the layers inside the group have been saved as files: Batch Mockup Smart Object Replacement.jsx Photoshop script + it can only resize images using fit or fill. — Here's a specific example for this type of scenario: github.com/joonaspaakko/…
    – Joonas
    Commented May 21, 2021 at 12:00
  • Accidentally posted the same url twice. This is the script page github.com/joonaspaakko/… (though I did leave a link to it on that example page too)
    – Joonas
    Commented May 22, 2021 at 8:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.