skip to Main Content

I have a doc with about 400 layers in it, and another layer that is a modified flattened version of those layers on top (so that only that is visible). My goal is to simplify saving the pieces of the flattened version in the same shape/size as the original pieces.

I’m doing it manually by ctrl-clicking the layer I want, copying its layer name to the clipboard, cropping the image to the selection, exporting as png, pasting the layer name into the dialogue and saving, and then undoing my crop in the history before moving on to the next layer.

I’m not very familiar with scripting languages, but I’ve managed to smoosh together three scripts that i found with some digging (see below).

So far, what it seems to do is load the selection, open the cropped version as a new document, copy the layer name to the clipboard, and then open the export as png dialogue, wait for input, and close the new doc after saving.

Where I’ve hit a snag is that the layer name should be from the original document, and the process of opening the crop as a new document overwrites the clipboard if I put it before that point – and then I haven’t figured out how to paste what’s in the clipboard anyway.

Is there…

  1. an easier way to script my above workflow?
  2. a way to just crop the file instead of pasting the crop in a new doc?
  3. a way to carry over the layer name to the cropped doc, if not?
  4. a quick and easy paste-the-clipboard thing I can add to the end of what I have?
app.displayDialogs = DialogModes.NO;

var id1268 = charIDToTypeID( "setd" );
var desc307 = new ActionDescriptor();
var id1269 = charIDToTypeID( "null" );
var ref257 = new ActionReference();
var id1270 = charIDToTypeID( "Chnl" );
var id1271 = charIDToTypeID( "fsel" );
ref257.putProperty( id1270, id1271 );
desc307.putReference( id1269, ref257 );
var id1272 = charIDToTypeID( "T   " );
var ref258 = new ActionReference();
var id1273 = charIDToTypeID( "Chnl" );
var id1274 = charIDToTypeID( "Chnl" );
var id1275 = charIDToTypeID( "Trsp" );
ref258.putEnumerated( id1273, id1274, id1275 );
desc307.putReference( id1272, ref258 );
executeAction( id1268, desc307, DialogModes.NO )

var pngSaveOptions = new PNGSaveOptions();
pngSaveOptions.compression = 9;
pngSaveOptions.interlaced = false;

var hasSelection;
var docRef;
var artLayer;
var width = app.activeDocument.width;
var height = app.activeDocument.height;

try {
    hasSelection = !!app.activeDocument.selection.bounds;    
} catch (err) {
    hasSelection = false;
}

if (hasSelection) {
    //copy merged
    app.activeDocument.selection.copy(true);

    //create new RGB document with transperant background
    docRef = app.documents.add(width, height, 72, null, NewDocumentMode.RGB, DocumentFill.TRANSPARENT)
    artLayer = docRef.paste();
    
    //crop the image to pasted bounds
    docRef.crop(artLayer.bounds);
} else {
    docRef = app.activeDocument;
}

// Copy Active Layer Name to Clipboard.jsx
#target photoshop 
var doc = activeDocument;
var aLayer = doc.activeLayer.name;
var d = new ActionDescriptor();  
d.putString(stringIDToTypeID("textData"), aLayer);  
executeAction(stringIDToTypeID("textToClipboard"), d, DialogModes.NO); 

var file = File.saveDialog("Export as PNG to...");
if (file && ((file.exists && confirm("Overwrite " + file +"?")) || !file.exists)) {
    docRef.saveAs(file, pngSaveOptions, !hasSelection, Extension.LOWERCASE);
    if (hasSelection) {
    docRef.close(SaveOptions.DONOTSAVECHANGES);
    }
}

2

Answers


  1. Here are a couple of code snippets that might help you. I’m not certain, but I think you might have two documents open to start with.

    // call the source document
    var srcDoc = app.activeDocument;
    var docName = srcDoc.name;
    alert("Current photoshop document: " + docName);
    
    // run a loop for all the open documents
    for (var i = 0; i < app.documents.length;  i++)
    {
      alert(app.documents[i].name);
    }
    
    select_rectangle_and_crop(10, 10, 100, 200);
    
    
    function select_rectangle_and_crop(top, left, bottom, right)
    {
      // Note: co-ordinates are same as script listener
      // and not so human-friendly as t,l,r,b.
    
      var id1 = charIDToTypeID( "setd" );
      var desc1 = new ActionDescriptor();
      var id2 = charIDToTypeID( "null" );
      var ref1 = new ActionReference();
      var id3 = charIDToTypeID( "Chnl" );
      var id4 = charIDToTypeID( "fsel" );
      ref1.putProperty( id3, id4 );
      desc1.putReference( id2, ref1 );
      var id5 = charIDToTypeID( "T   " );
      var desc2 = new ActionDescriptor();
      var id6 = charIDToTypeID( "Top " );
      var id7 = charIDToTypeID( "#Pxl" );
      desc2.putUnitDouble( id6, id7, top );
      var id8 = charIDToTypeID( "Left" );
      var id9 = charIDToTypeID( "#Pxl" );
      desc2.putUnitDouble( id8, id9, left );
      var id10 = charIDToTypeID( "Btom" );
      var id11 = charIDToTypeID( "#Pxl" );
      desc2.putUnitDouble( id10, id11, bottom );
      var id12 = charIDToTypeID( "Rght" );
      var id13 = charIDToTypeID( "#Pxl" );
      desc2.putUnitDouble( id12, id13, right );
      var id16 = charIDToTypeID( "Rctn" );
      desc1.putObject( id5, id16, desc2 );
      executeAction( id1, desc1, DialogModes.NO );
    
        // crop to selection
      executeAction( charIDToTypeID( "Crop" ), new ActionDescriptor(), DialogModes.NO );
    
    }
    

    As for the clipboard – not sure what you’re trying to do.

    Login or Signup to reply.
  2. The method used by the OP for saving, File.saveDialog, has a big brother known as saveDlg:

    File saveDlg (String prompt, any filter);
    

    The latter is used with a File instance, and will prefill the save field with any filepath you wish, foregoing any copy/paste clipboard voodoo. The method returns a new File object you can use to do the actual save when the save dialog returns, or null if canceled by the user, and handles the "overwrite file" prompt for you.

    var doc = app.activeDocument;
    var layer = doc.activeLayer;
    var dlgFile = new File("my/file/path/" + layer.name);
    var saveFile = dlgFile.saveDlg("Save layer: " + layer.name, "[*.png,*.jpg]") // with optional png/jpg filetype filters
    
    if (saveFile != null) {
        // init our PngSaveOptions here...
        doc.saveAs(saveFile, pngSaveOptions, true, Extension.LOWERCASE);
    }
    

    If you save a reference to your initial document (or layer) before leaving that document, just use that to get the layer name when ready to save (var layer just above). Or, just name your new document the same as the layer it’s saving, and use the document name. Flip a coin.

    Here’s a modified version of your script that walks through all top-level layers (it doesn’t recurse into layersets), skipping the first layer. Save dialog is only shown if the file already exists; otherwise, it saves the cropped image as the layer name before closing the new doc and moving on to the next layer.

    #target photoshop
    app.bringToFront();
    
    var cachedDialogMode = app.displayDialogs;
    app.displayDialogs = DialogModes.NO;
    
    var mainDoc = app.activeDocument;
    mainDoc.layers[0].visible = true;
    
    for (var i = 1; i < mainDoc.layers.length; i++) {
        mainDoc.activeLayer = mainDoc.layers[i];
        saveLayerPng();
        app.activeDocument = mainDoc;
    }
    
    app.displayDialogs = cachedDialogMode;
    
    function saveLayerPng() {
        var id1268 = charIDToTypeID("setd");
        var desc307 = new ActionDescriptor();
        var id1269 = charIDToTypeID("null");
        var ref257 = new ActionReference();
        var id1270 = charIDToTypeID("Chnl");
        var id1271 = charIDToTypeID("fsel");
        ref257.putProperty(id1270, id1271);
        desc307.putReference(id1269, ref257);
        var id1272 = charIDToTypeID("T   ");
        var ref258 = new ActionReference();
        var id1273 = charIDToTypeID("Chnl");
        var id1274 = charIDToTypeID("Chnl");
        var id1275 = charIDToTypeID("Trsp");
        ref258.putEnumerated(id1273, id1274, id1275);
        desc307.putReference(id1272, ref258);
        executeAction(id1268, desc307, DialogModes.NO)
    
        var doc = app.activeDocument;
        var lyr = doc.activeLayer;
    
        try {
            var fpath = Folder(doc.fullName.parent);
            if (!!doc.selection.bounds) {
                doc.selection.copy(true);
                var newDoc = app.documents.add(doc.width, doc.height, doc.resolution, lyr.name, NewDocumentMode.RGB, DocumentFill.TRANSPARENT)
                var pasteLayer = newDoc.paste();
                newDoc.crop(pasteLayer.bounds);
    
                var file = new File(fpath + "/" + lyr.name + ".png");
                if (file.exists)
                    file = file.saveDlg("Export" + lyr.name + " as PNG", "*.png");
                if (file != null) {
                    var pngSaveOptions = new PNGSaveOptions();
                    pngSaveOptions.compression = 9;
                    pngSaveOptions.interlaced = false;
                    newDoc.saveAs(file, pngSaveOptions, true, Extension.LOWERCASE);
                }
            }
        } catch (e) {
            alert("Exception on line " + e.line + ":nn" + e);
            alert("No selection; canceled saving layer: " + lyr.name);
        }
    
        if (app.activeDocument == newDoc)
            newDoc.close(SaveOptions.DONOTSAVECHANGES);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search