Skip to main content
Known Participant
July 25, 2024
Question

Continously creating mockups

  • July 25, 2024
  • 1 reply
  • 316 views

Hello friends, i need help. I Have Man.psd with this layout ;

And inside smart object i have this

I need to write script to continously search C:\Mockups\NotGenerated, if any image is on there i want to create new mockup with this PSD file and save png to ; _output folder and remove old file at C:\Mockups\NotGenerated
i tried but cant make it work.

 

// 2024, use it at your own risk;
if (app.documents.length > 0) { main(); }

function main() {
    try {
        var basePath = "C:/Mockups/NotGenerated";
        var outputPath = basePath + "/_output";
        var psdFile = new File("C:/Mockups/Man.psd");

        if (!psdFile.exists) {
            alert("PSD file not found.");
            return;
        }

        var theFiles = getAllPngFiles(basePath);
        var theLayers = collectLayersByName("Placeholder", psdFile);
        
        if (theLayers.length === 0) {
            alert("No layer named 'Placeholder' found.");
            return;
        }

        var theSO = openSmartObject(psdFile);
        
        if (theSO) {
            for (var m = 0; m < theFiles.length; m++) {
                var thisOne = theFiles[m];
                replaceContents(thisOne, theSO.activeLayer);
                theSO.save();
                activeDocument = psdFile;
                savePng(outputPath, new File(thisOne).name.match(/(.*)\.[^\.]+$/)[1]);
                activeDocument = theSO;
            }
            theSO.close();
        } else {
            alert("Failed to open Smart Object.");
        }

        deleteOldFiles(basePath, theFiles);
    }
    catch (e) {
        alert("Something is wrong: " + e.message);
    }
}

// Open smart object from PSD file
function openSmartObject(psdFile) {
    app.open(psdFile);
    var idplacedLayerEditContents = stringIDToTypeID("placedLayerEditContents");
    var desc2 = new ActionDescriptor();
    executeAction(idplacedLayerEditContents, desc2, DialogModes.NO);
    return app.activeDocument;
}

// Replace contents of the smart object
function replaceContents(newFile, theSO) {
    app.activeDocument.activeLayer = theSO;
    var idplacedLayerReplaceContents = stringIDToTypeID("placedLayerReplaceContents");
    var desc3 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    desc3.putPath(idnull, new File(newFile));
    var idPgNm = charIDToTypeID("PgNm");
    desc3.putInteger(idPgNm, 1);
    executeAction(idplacedLayerReplaceContents, desc3, DialogModes.NO);
}

// Get all PNG files from the base directory
function getAllPngFiles(basePath) {
    var folder = new Folder(basePath);
    var files = folder.getFiles("*.png");
    return files;
}

// Save as PNG
function savePng(outputPath, theNewName) {
    var pngOptions = new PNGSaveOptions();
    pngOptions.compression = 9;
    pngOptions.interlaced = false;
    activeDocument.saveAs(new File(outputPath + "/" + theNewName + ".png"), pngOptions, true);
}

// Collect layers by name from a specific PSD file
function collectLayersByName(aName, psdFile) {
    app.open(psdFile);
    var myDocument = app.activeDocument;
    var ref = new ActionReference();
    ref.putProperty(stringIDToTypeID('property'), stringIDToTypeID('numberOfLayers'));
    ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
    var applicationDesc = executeActionGet(ref);
    var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
    var theLayers = [];
    
    for (var m = 0; m < theNumber; m++) {
        try {
            var ref = new ActionReference();
            ref.putIndex(charIDToTypeID("Lyr "), m);
            var layerDesc = executeActionGet(ref);
            var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
            var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
            if (layerSet != "layerSectionEnd" && !isBackground) {
                var theName = layerDesc.getString(stringIDToTypeID('name'));
                var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
                var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
                if (theName == aName) {
                    theLayers.push([theName, theIndex, theID]);
                }
            }
        } catch (e) {}
    }
    return theLayers;
}

// Delete old files
function deleteOldFiles(basePath, files) {
    for (var i = 0; i < files.length; i++) {
        var file = new File(files[i].toString());
        if (file.exists) {
            file.remove();
        }
    }
}

// Select layer by ID
function selectLayerByID(id, add) {
    add = (add === undefined) ? false : add;
    var ref = new ActionReference();
    ref.putIdentifier(charIDToTypeID("Lyr "), id);
    var desc = new ActionDescriptor();
    desc.putReference(charIDToTypeID("null"), ref);
    if (add) {
        desc.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
    }
    desc.putBoolean(charIDToTypeID("MkVs"), false);
    try {
        executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
    } catch (e) {
        alert(e.message);
    }
}

 

1 reply

Stephen Marsh
Community Expert
Community Expert
July 25, 2024

I believe that you'll either need to use an Adobe Bridge script to monitor the folder and trigger the script in Photoshop, or perhaps UXP scripting or perhaps a third party hot/watch folder utility.

 

https://github.com/Paul-Riggott/PS-Scripts/blob/master/Bridge%20Hot%20Folder.jsx

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/reminder-to-save/m-p/10466042

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/photoshop-interval-function-in-scripting/m-p/12145044

Known Participant
July 25, 2024

Yes i just created watcher.js which checks file change detections on spesific folder and calls open jsx file if trigger.

const chokidar = require('chokidar');
const { exec } = require('child_process');
const path = require('path');

const watcher = chokidar.watch('C:/Mockups/NotGenerated', { persistent: true });
const scriptPath = path.resolve('C:/Mockups/a.jsx');

// Zamanlayıcı için bir değişken
let timeout;
let hasChanges = false;

// Photoshop komutunu çalıştıran fonksiyon
function runPhotoshopScript() {
  // Photoshop komutunu oluştur
  const command = `"C:\\Program Files\\Adobe\\Adobe Photoshop 2024\\Photoshop.exe" -r "${scriptPath}"`;

  exec(command, (err, stdout, stderr) => {
    if (err) {
      console.error(`exec error: ${err.message}`);
      console.error(`stderr: ${stderr}`);
      return;
    }
    console.log(`stdout: ${stdout}`);
  });
}

// Dosya eklenme olayını dinleme
watcher.on('add', function(filePath) {
  console.log('File', filePath, 'has been added');
  
  // Zamanlayıcı varsa temizle
  if (timeout) {
    clearTimeout(timeout);
  }

  // Yeni dosya eklenme olayının olduğunu işaretle
  hasChanges = true;

  // 1 saniye (1000 ms) sonra komutu çalıştır
  timeout = setTimeout(() => {
    if (hasChanges) {
      runPhotoshopScript();
      hasChanges = false;
    }
  }, 1000);
});

now i just need to have some kind of jsx file to generate mockup. but cant find any working one.

Stephen Marsh
Community Expert
Community Expert
July 25, 2024

There are many mockup scripts to be found, however, they often need to be modified or rewritten for each user as workflow, template file structure and other requirements may differ.

 

The issue is that most code that you find will be legacy ExtenScript, not UXP. The two languages are incompatible with each other, however it might be possible for .psjs to call a separate .jsx file as Photoshop can still execute both separately.

How is your watcher script executed, in what engine? It doesn't have a .psjs extension, but it doesn't look like a .jsx for Photoshop. You mentioned .js so is the script run elsewhere?