0
votes

I'm working on a script that should go through a photoshop document and relink all visible linked objects to a new specified file. I've gotten the loop working so that it cycles through every layer and collects only the visible layers, but for the life of me I can't find if there's a method available to relink a smart object. The closest I've found is this script:

https://gist.github.com/laryn/0a1f6bf0dab5b713395a835f9bfa805c

but when it gets to desc3.putPath(idnull, new File(newFile));, it spits out an error indicating that the functionality may not be present in the current Photoshop version. The script itself is 4 years old so it may be out of date.

Any help would be appreciated!

MY script as it stands is below:

// SELECT FILE //

var files = File.openDialog("Please select new linked file");

var selectedFile = files[0];

// GET ALL LAYERS //

var doc = app.activeDocument;
var allLayers = [];
var allLayers = collectAllLayers(doc, allLayers);

function collectAllLayers (doc, allLayers)
{
    for (var m = 0; m < doc.layers.length; m++)
    {
        var theLayer = doc.layers[m];
        
        if (theLayer.typename === "ArtLayer")
        {
            allLayers.push(theLayer);
        }
        else
        {
            collectAllLayers(theLayer, allLayers);
        }
    }
    return allLayers;
}

// GET VISIBLE LAYERS //

var visibleLayers = [];

for (i = 0; i < allLayers.length; i++)
{
    var layer = allLayers[i];
    
    if (layer.visible && layer.kind == LayerKind.SMARTOBJECT)
    {
        visibleLayers.push(layer);
    }
}

// REPLACE LAYERS

for (i = 0; i < visibleLayers.length; i++)
{
    var layer = visibleLayers[i];
    
    //--> REPLACE THE FILE HERE 
}

Note: I am aware that this script currently may be error-prone if you don't know exactly how it works; I'm not intending to publish it at this time so I'm not super concerned with that at the moment. Mostly I just need the core functionality to work.

1
Are you trying to relink all visibleLayers? what if they aren't smart objects..? - Sergey Kritskiy
They will all be smart objects because when I'm using the script I will ensure that only smart objects are visible. That said, the line if (layer.visible && layer.kind == LayerKind.SMARTOBJECT) should ensure that only smart objects are being added to the visibleLayers array even if I miss something. - Arcane
to me it works fine. maybe paste your full script? - Sergey Kritskiy
What is posted is the full script. What's missing is the functionality to replace the linked files that should be at //--> REPLACE THE FILE HERE. This is the functionality that I'm asking how to do. - Arcane
No, the full script would result in the error you posted (that the functionality may not be present in the current Photoshop version). I don't have this error with the snippet you provided — it successfully replaces SO contents — meaning you're doing something wrong in your full script or it's something wrong with your PS. - Sergey Kritskiy

1 Answers

1
votes

I used an AM function for getting visible smart objects — it works much faster. But if you want you can use yours. The important bit is relinkSO(path);: it'll also work in your script (just don't forget to select a layer: activeDocument.activeLayer = visibleLayers[i];)

Note that it works similar to Photoshop Relink to File command — if used on one instance of Smart Object all the instances are going to be relinked. If you want to relink only specific layers you'll have to break instancing first (probably using the New Smart Object via Copy command)

function main() {
  var myFile = Folder.myDocuments.openDlg('Load file', undefined, false);
  if (myFile == null) return false;
  
  // gets IDs of all smart objects
  var lyrs = getLyrs();

  for (var i = 0; i < lyrs.length; i++) {
    // for each SO id...

    // select it
    selectById(lyrs[i]);

    // relink SO to file
    relinkSO(myFile);

    // embed linked if you want
    embedLinked()
  }

  function getLyrs() {
        var ids = [];
        var layers, desc, vis, type, id;

        try
        {
          activeDocument.backgroundLayer;
          layers = 0;
        }
        catch (e)
        {
          layers = 1;
        }

        while (true)
        {
          ref = new ActionReference();
          ref.putIndex(charIDToTypeID('Lyr '), layers);
          try
          {
            desc = executeActionGet(ref);
          }
          catch (err)
          {
            break;
          }
          vis = desc.getBoolean(charIDToTypeID("Vsbl"));
          type = desc.getInteger(stringIDToTypeID("layerKind"));
          id = desc.getInteger(stringIDToTypeID("layerID"));
          if (type == 5 && vis) ids.push(id);
          layers++;
        }
        return ids;

  } // end of getLyrs()

  function selectById(id) {
        var desc = new ActionDescriptor();
        var ref = new ActionReference();
        ref.putIdentifier(charIDToTypeID('Lyr '), id);
        desc.putReference(charIDToTypeID('null'), ref);
        executeAction(charIDToTypeID('slct'), desc, DialogModes.NO);
  } // end of selectById()
  
  function relinkSO(path) {
      var desc = new ActionDescriptor();
      desc.putPath( charIDToTypeID('null'), new File( path ) );
      executeAction( stringIDToTypeID('placedLayerRelinkToFile'), desc, DialogModes.NO );
  } // end of relinkSO()

  function embedLinked() {
      executeAction( stringIDToTypeID('placedLayerConvertToEmbedded'), undefined, DialogModes.NO );
  } // end of embedLinked()
  
}
app.activeDocument.suspendHistory("relink SOs", "main()");