• Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
    Dedicated community for Japanese speakers
  • 한국 커뮤니티
    Dedicated community for Korean speakers
Exit
0

Place linked using script

Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

I am looking for a way to place linked photos directly from Lightroom.

After selecting a layer, I want to run my script which will do the following:

  • Get the layer name (this will be the linked filename + suffix, at this point dgn)
  • Open a “browse” dialog using  Folder.selectDialog to get the root path the file can be found in.
  • Recursively search down and if fileName.dgn is found place it as linked and delete the current layer.
    Or, convert the smart object in the active layer to linked

How can I recursively search down to find the file?

How can I place it as linked?

TOPICS
Actions and scripting

Views

3.5K

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 1 Correct answer

People's Champ , Nov 05, 2018 Nov 05, 2018

Replace

descriptor.putObject( stringIDToTypeID( "openAs" ), charIDToTypeID( "null" ), descriptor2 );

with

descriptor.putObject(stringIDToTypeID("openAs"), stringIDToTypeID("Adobe Camera Raw"), descriptor2 );

Votes

Translate

Translate
Adobe
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

karpiyon  wrote

I am looking for a way to place linked photos directly from Lightroom.

After selecting a layer, I want to run my script which will do the following:

  • Get the layer name (this will be the linked filename + suffix, at this point dgn)
  • Open a “browse” dialog using  Folder.selectDialog to get the root path the file can be found in.
  • Recursively search down and if fileName.dgn is found place it as linked and delete the current layer.
    Or, convert the smart object in the active layer to linked

How can I recursively search down to find the file?

How can I place it as linked?

How would  what you wrote be directly from Lightroom?

If you select a layer you are in Photoshop Lightroom does not support Layers.

If you target a layer in Photoshop then use place.  Place will create a Smart Object Layer above the current targeted layer and this new smart object layer will be Photoshop new current target.   If you want the Placed image file to be linked you would use Place linked not place embedded.  So the current layer would be a smart object layer with a linked image file in the layers object.  If you delete the current layer you delete the smart object layer you just placed in.  Lightroom had no part in this process.  You may have saved the file you place in using Lightroom in the past.   That was not part of your script's process.

Your script Process would put the Photoshop User into a select image file dialog.  (Not a folder select dialog) The user would navigate to the file to want placed in and select that file.  The Script would then use place Linked to place in the smart object layer with the linked image file.   The layer will not be an independent smart object layer it will be linked to you master image file.

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

Let me rephrase...

In LR I select the image ans open as smart object in PS

In PS I run my script on the smart object layer.

The reason i do this is because i do not want to navigate to the location of the image and search for it - it is time consuming task.

In my script I specify the root folder and it looks for a file whose name is equal to the PS smart layer name.

Currently i have most of the script including the recursive search for the file.

What need is a was to insert/place a file as linked from withing PS by scripting.

Dan

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

The above is not done directly from LR but will save a lot for time.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

OK I see you open you lightroom image in Photoshop as a smart object layer instead of a background image.   When your in Photoshop with this smart object bottom layer you want a script to find the file that was open as an embedded object.  Then Place the image in as a linked object  in a smart object layer then delete the original  opened embedded object layer.

I would be concerned that recursive searching folders will take some time and may find a file  with duplicate file name, fine the wrong file as a match. Do you plain of verifying you found  the correct image file?

To do the File Place you will most likely need to use action manager code coded as a function where you pass the full path of the file to be placed in.   You would use action manager code for menu File>Place Linked.

scriptlistener code for place linked

// =======================================================

var idPlc = charIDToTypeID( "Plc " );

    var desc14 = new ActionDescriptor();

    var idIdnt = charIDToTypeID( "Idnt" );

    desc14.putInteger( idIdnt, 3 );

    var idnull = charIDToTypeID( "null" );

    desc14.putPath( idnull, new File( "C:\\LO2G5037.CR2" ) );

    var idLnkd = charIDToTypeID( "Lnkd" );

    desc14.putBoolean( idLnkd, true );

    var idOpAs = charIDToTypeID( "OpAs" );

        var desc15 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

    desc14.putObject( idOpAs, idnull, desc15 );

    var idFTcs = charIDToTypeID( "FTcs" );

    var idQCSt = charIDToTypeID( "QCSt" );

    var idQcsa = charIDToTypeID( "Qcsa" );

    desc14.putEnumerated( idFTcs, idQCSt, idQcsa );

    var idOfst = charIDToTypeID( "Ofst" );

        var desc16 = new ActionDescriptor();

        var idHrzn = charIDToTypeID( "Hrzn" );

        var idPrc = charIDToTypeID( "#Prc" );

        desc16.putUnitDouble( idHrzn, idPrc, 0.000000 );

        var idVrtc = charIDToTypeID( "Vrtc" );

        var idPrc = charIDToTypeID( "#Prc" );

        desc16.putUnitDouble( idVrtc, idPrc, 0.000000 );

    var idOfst = charIDToTypeID( "Ofst" );

    desc14.putObject( idOfst, idOfst, desc16 );

executeAction( idPlc, desc14, DialogModes.NO );

Code cleaned by Clean SL script

// =======================================================

placeEvent(3, new File( "C:\\LO2G5037.CR2" ), true, 0, 0);

function placeEvent(ID, null2, linked, horizontal, vertical) {

var descriptor = new ActionDescriptor();

var descriptor2 = new ActionDescriptor();

var descriptor3 = new ActionDescriptor();

descriptor.putInteger( stringIDToTypeID( "ID" ), ID );

descriptor.putPath( charIDToTypeID( "null" ), null2 );

descriptor.putBoolean( stringIDToTypeID( "linked" ), linked );

descriptor.putObject( stringIDToTypeID( "openAs" ), charIDToTypeID( "null" ), descriptor2 );

descriptor.putEnumerated( stringIDToTypeID( "freeTransformCenterState" ), stringIDToTypeID( "quadCenterState" ), stringIDToTypeID( "QCSAverage" ));

descriptor3.putUnitDouble( stringIDToTypeID( "horizontal" ), stringIDToTypeID( "percentUnit" ), horizontal );

descriptor3.putUnitDouble( stringIDToTypeID( "vertical" ), stringIDToTypeID( "percentUnit" ), vertical );

descriptor.putObject( stringIDToTypeID( "offset" ), stringIDToTypeID( "offset" ), descriptor3 );

executeAction( stringIDToTypeID( "placeEvent" ), descriptor, DialogModes.NO );

}

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

Yes, i'm aware of the fact i may find more than one candidate.

As for the search time, i allow the user to specify the root folder for search to reduce search time.

I attached my script below, assuming i find only one file, I am unable to "return" it from my recursion.

In this case i always get it as undefined.

SO i have 2 questions:

1. What do i need to change in order to make sure i get required search result,in this case: "foundFile"

I tried modifying the end recursive return traverseFolder(files, layerN);  but that ruined all the function.

The best would be to return a global variable but i failed to do this as well.

2. how do i use the action manager code for menu File>Place Linked in my script once i have the full path to the required file.

This is my script so far:

var doc = app.activeDocument;

var fName = doc.name.split(".");

var fName = fName[0];

var layerN = doc.activeLayer.name;

var linkFolder = Folder.selectDialog("Selection prompt");

if(linkFolder !== null){

    var linkFolderPath = linkFolder.path;

    var linkName = linkFolder.name;

    var linkFullPath = linkFolderPath+"/"+linkName;

    //alert("Looking for " + layerN + " in\n" + linkFullPath);

    function traverseFolder(path, layerN)  { 

        var folder = new Folder(path); 

        suffix = new Array();

        suffix[0] = "tif";

        suffix[1] = "dng";

        suffix[2] = "psd";

        var files = folder.getFiles(); 

        for (var i = 0; i < files.length; i++) 

        { 

            if (files instanceof File) 

            {  

                var fullPathName = Folder.decode(files);

                var fileName = files.name;

                fileName = decodeURI(fileName);

                for(var s = 0; s < suffix.length ; s++){

                    search_name = layerN + "." + suffix;

                    search_NAME = layerN + "." + suffix.toUpperCase();

                    if ((fileName == search_name) || (fileName == search_NAME)) 

                    { 

                        foundFile = fullPathName + "/" + fileName;

                        alert("Found: " + foundFile); 

                        return foundFile ;

                    }

                }

            } 

            else 

            { 

               traverseFolder(files, layerN); 

               // return traverseFolder(files, layerN); 

            } 

        } 

    } 

    var foundFile = traverseFolder(linkFullPath, layerN);

    alert("Found: " + foundFile);

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

I posted the File Place Link Action manager code in my previous post.   I do not know javascript I just hack at it.  Looking at what you posted do not see a not found return indicator.  So if not found I do not now what would be returned by your function.   I do not know javascript.

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

I run your added code and i get. in the extendedScript tool:

General Photoshop error occurred. This function may not be available in this version of Photoshop.

well, of course it is available...

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

Did you change the code to make it a function and pass a valid  image file  or create a "C:\LO2G5037.CR2"?

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

your code has a function:

function placeEvent(ID, null2, linked, horizontal, vertical) {

    var descriptor = new ActionDescriptor();   

    var descriptor2 = new ActionDescriptor();

    var descriptor3 = new ActionDescriptor();  

    descriptor.putInteger( stringIDToTypeID( "ID" ), ID );

    descriptor.putPath( charIDToTypeID( "null" ), null2 );

    descriptor.putBoolean( stringIDToTypeID( "linked" ), linked );

    descriptor.putObject( stringIDToTypeID( "openAs" ), charIDToTypeID( "null" ), descriptor2 );

    descriptor.putEnumerated( stringIDToTypeID( "freeTransformCenterState" ), stringIDToTypeID( "quadCenterState" ), stringIDToTypeID( "QCSAverage" ));

    descriptor3.putUnitDouble( stringIDToTypeID( "horizontal" ), stringIDToTypeID( "percentUnit" ), horizontal );

    descriptor3.putUnitDouble( stringIDToTypeID( "vertical" ), stringIDToTypeID( "percentUnit" ), vertical );

    descriptor.putObject( stringIDToTypeID( "offset" ), stringIDToTypeID( "offset" ), descriptor3 );

    executeAction( stringIDToTypeID( "placeEvent" ), descriptor, DialogModes.NO );

}

i used it as:

                        placeEvent(3, new File(foundFile), true, 0, 0);

i noticed that the found file path is of the sort D:\Pictures\Adobe\Work\...

to make sure this was not a path issue i tried with:

                        foundFile = "D:\\Pictures\Adobe\Work\...";

and also

                        foundFile = "D:\Pictures\Adobe\Work\...";

none is working and the erorr is not related to a file not found

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

"\" is Jacascripts escape chacter to get am "\" you need to code \\

foundFile = "D:\\Pictures\\Adobe\\Work\\...";

for D:\Pictures\Adobe\Work\...

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

in any case regarding the path to the file - should i not use the file i found earlier in my script?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

In any case you may not need to use Place link or Delete the original smart object layer you may  just need the convert the original layer from and embedded Smart object layer to a linked smart object layer.

Here I opened my CR2 file in Photoshop as a embedded Smart object layer then  I placed in the same CR2 as a Linked smart object layer.  You can see this from the two different icons in their layer in the layers palette.  One is a link the other an embedded object.  Right click in the layer pallets on the linked one you can see a menu item  "Reveal in Explorer" and if I use it  Windows explorer will open to the file.  If I right Click one the embedded smart object layer that menu item is not there but the is a "Relink to File" menu Item.  If I use it I can convert the embedded smart object layer to a linked smart object layer,  So once you find your file all you need to do is convert the layer to a linked smart object layer.  Here is what the scriptlistener recorded.

// =======================================================

var idplacedLayerRelinkToFile = stringIDToTypeID( "placedLayerRelinkToFile" );

    var desc121 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

    desc121.putPath( idnull, new File( "C:\\LO2G5037.CR2" ) );

executeAction( idplacedLayerRelinkToFile, desc121, DialogModes.NO );

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

The code I posted I did not check it was straight from the Scriptlistene Placing Linked a RAW CR2 file.  I have have problems in the past using code done with a RAW File I found Using code Placing a jpeg works fine and It also has no problem placing a RAW file. I tested the function and it works on my windows machine.

placeImageLinked("C:\\LO2G5037.CR2") ;

function placeImageLinked(file) {

   var idPlc = charIDToTypeID( "Plc " );

       var desc48 = new ActionDescriptor();

       var idIdnt = charIDToTypeID( "Idnt" );

       desc48.putInteger( idIdnt, 7 );

       var idnull = charIDToTypeID( "null" );

       desc48.putPath( idnull, new File( file ) );

       var idLnkd = charIDToTypeID( "Lnkd" );

       desc48.putBoolean( idLnkd, true );

       var idFTcs = charIDToTypeID( "FTcs" );

       var idQCSt = charIDToTypeID( "QCSt" );

       var idQcsa = charIDToTypeID( "Qcsa" );

       desc48.putEnumerated( idFTcs, idQCSt, idQcsa );

       var idOfst = charIDToTypeID( "Ofst" );

           var desc49 = new ActionDescriptor();

           var idHrzn = charIDToTypeID( "Hrzn" );

           var idPrc = charIDToTypeID( "#Prc" );

           desc49.putUnitDouble( idHrzn, idPrc, 0.000000 );

           var idVrtc = charIDToTypeID( "Vrtc" );

           var idPrc = charIDToTypeID( "#Prc" );

           desc49.putUnitDouble( idVrtc, idPrc, 0.000000 );

       var idOfst = charIDToTypeID( "Ofst" );

       desc48.putObject( idOfst, idOfst, desc49 );

   executeAction( idPlc, desc48, DialogModes.NO );

   return app.activeDocument.activeLayer;

}

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

I have very little scripting knowledge/experience, so I am just throwing out these ideas that may help if you can work out how to code them:

* When opening the Lightroom image as a smart object in Photoshop, the embedded image uses the source images filename without the extension as the layer name, perhaps this could be used in a filename mask?

* XMP “Ingredients File Path” metadata may have a full path including extension for the original image, perhaps this could be used as a default search path or a filename mask?

* XMP “Document ID” or “Original Document ID” or “Derived from Document ID” or “Derived from Original Document ID” metadata should match between the file opened from Lightroom and the image in Photoshop, which could possibly be leveraged to find the correct file.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

i managed to get most of the script, there was a problem with the path and naming but now I am nearly there.

The problem is that i cannot place the linked file.

I always get an error of this sort:

My code is below:

and i call the place function here:

                        //placeEvent(3, new File(winPath), true, 0, 0);

                        placeLink(winPath);

function placeLink(fileName){

        var d = new ActionDescriptor();

        var d1 = new ActionDescriptor();

        var d2 = new ActionDescriptor();

        d.putInteger(stringIDToTypeID("ID"), 3);

        d.putPath(stringIDToTypeID("null"), new File(fileName));

        d.putBoolean(stringIDToTypeID("linked"), true);

        d.putObject(stringIDToTypeID("openAs"), stringIDToTypeID("null"), d1);

        d.putEnumerated(stringIDToTypeID("freeTransformCenterState"), stringIDToTypeID("quadCenterState"), stringIDToTypeID("QCSAverage"));

        d2.putUnitDouble(stringIDToTypeID("horizontal"), stringIDToTypeID("pixelsUnit"), 0);

        d2.putUnitDouble(stringIDToTypeID("vertical"), stringIDToTypeID("pixelsUnit"), 0);

        d.putObject(stringIDToTypeID("offset"), stringIDToTypeID("offset"), d2);

        executeAction(stringIDToTypeID("placeEvent"), d, DialogModes.NO);

}

function placeEvent(ID, null2, linked, horizontal, vertical) {

    var descriptor = new ActionDescriptor();   

    var descriptor2 = new ActionDescriptor();

    var descriptor3 = new ActionDescriptor();  

    descriptor.putInteger( stringIDToTypeID( "ID" ), ID );

    descriptor.putPath( charIDToTypeID( "null" ), null2 );

    descriptor.putBoolean( stringIDToTypeID( "linked" ), linked );

    descriptor.putObject( stringIDToTypeID( "openAs" ), charIDToTypeID( "null" ), descriptor2 );

    descriptor.putEnumerated( stringIDToTypeID( "freeTransformCenterState" ), stringIDToTypeID( "quadCenterState" ), stringIDToTypeID( "QCSAverage" ));

    descriptor3.putUnitDouble( stringIDToTypeID( "horizontal" ), stringIDToTypeID( "percentUnit" ), horizontal );

    descriptor3.putUnitDouble( stringIDToTypeID( "vertical" ), stringIDToTypeID( "percentUnit" ), vertical );

    descriptor.putObject( stringIDToTypeID( "offset" ), stringIDToTypeID( "offset" ), descriptor3 );

    executeAction( stringIDToTypeID( "placeEvent" ), descriptor, DialogModes.NO );

}

function modWinPath(path){

    var newchar = '\\\\';

    var winPath;

    winPath = path.split('/').join(newchar);

    winPath = winPath.replace("\\\\d\\\\", "d:\\\\");

    winPath = winPath.replace("\\\\c\\\\", "c:\\\\"); 

    return winPath;

}       

       

var doc = app.activeDocument;

var fName = doc.name.split(".");

var fName = fName[0];

var layerN = doc.activeLayer.name;

var linkFolder = Folder.selectDialog("Selection prompt");

if(linkFolder !== null){

    var linkFolderPath = linkFolder.path;

    var linkName = linkFolder.name;

    var linkFullPath = linkFolderPath+"/"+linkName;

    function traverseFolder(path, layerN)  { 

        var folder = new Folder(path); 

        suffix = new Array();

        suffix[0] = "tif";

        suffix[1] = "dng";

        suffix[2] = "psd";

        var files = folder.getFiles(); 

        for (var i = 0; i < files.length; i++) 

        { 

            if (files instanceof File) 

            {  

                var fullPathName = Folder.decode(files);

                var fileName = files.name;

                fileName = decodeURI(fileName);

                for(var s = 0; s < suffix.length ; s++){

                    search_name = layerN + "." + suffix;

                    search_NAME = layerN + "." + suffix.toUpperCase();

                    if ((fileName == search_name) || (fileName == search_NAME)) 

                    { 

                        foundFile = fullPathName;

                        var winPath = modWinPath(foundFile);

                        alert("Try to place:\n" + winPath);

                        //placeEvent(3, new File(winPath), true, 0, 0);

                        placeLink(winPath);

                    }

                }

            } 

            else 

            { 

               traverseFolder(files, layerN); 

            } 

        } 

    } 

    traverseFolder(linkFullPath, layerN);

}

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 04, 2018 Nov 04, 2018

Copy link to clipboard

Copied

Another thing - even when i use the same code the event listener generated and try to run it, I get this error.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Nov 05, 2018 Nov 05, 2018

Copy link to clipboard

Copied

Replace

descriptor.putObject( stringIDToTypeID( "openAs" ), charIDToTypeID( "null" ), descriptor2 );

with

descriptor.putObject(stringIDToTypeID("openAs"), stringIDToTypeID("Adobe Camera Raw"), descriptor2 );

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 05, 2018 Nov 05, 2018

Copy link to clipboard

Copied

great!

it's working now

i'll tidy things up and place the code here.

do you know how i can select a layer below?

i need to delete the older smart object layer but it has the same name.

it is the layer below the new "active" link now.

so how do i select and delete it?

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
People's Champ ,
Nov 05, 2018 Nov 05, 2018

Copy link to clipboard

Copied

Delete previous layer.

var d = new ActionDescriptor();

var r = new ActionReference();

r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("previous"));

d.putReference(stringIDToTypeID("null"), r);

executeAction(stringIDToTypeID("delete"), d, DialogModes.NO);

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Nov 05, 2018 Nov 05, 2018

Copy link to clipboard

Copied

You could instead of placing in a new linked smart object later convert the original embedded smart object layer to a liknked one by using relink to file.

the scriptlistened code look like this

// =======================================================

var idplacedLayerRelinkToFile = stringIDToTypeID( "placedLayerRelinkToFile" );

    var desc10 = new ActionDescriptor();

    var idnull = charIDToTypeID( "null" );

    desc10.putPath( idnull, new File( "C:\\LO2G5037.CR2" ) );

executeAction( idplacedLayerRelinkToFile, desc10, DialogModes.NO );

IMO you want to do this from Lightroom.  You should user Adobe feedback site and request a change to ACR the would add an additional option to open the image as a linked smart object layer that way a user can choose to open  the image as a image background layer, or an embedded smarts object layer, or a linked smart object layer.  If Adobe makes that change Adobe can add a option to Lightroom and have ACR open Files from Lightroon as Embedded or Linked smart object layer.  Today Lightroom can only have ACR open file in Photoshop as embedded smart object layers. 

JJMack

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Nov 05, 2018 Nov 05, 2018

Copy link to clipboard

Copied

Thanks but what you suggest forces me again to search for the file myself.

The script I created with all the help i got here help converting the smart object to linked.

  • From LR, open the image as smart object in PS
    Actually this does not have to be smart object. The only thing needed is that the image layer name in PS
    will be identical to the file name, with or without the file suffix.
  • Select the layer to convert, in PS and run the script.
  • Specify a root folder for the search. it will recursively search down and try to find files matching layerName.ext
    ext is currently psd,tif or dng, both upper and lower.
  • When found it will place the found file as a linked.
  • It will offer to delete the previous layer.

It needs some more touch-ups, e,g. i can't return values from my recursion for if more than 1 file is found i will offer to place all.

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Advocate ,
Dec 26, 2020 Dec 26, 2020

Copy link to clipboard

Copied

LATEST

@karpiyon 

i was looking for something similar as yours. I needed a script with which i could do bulk relinked. After find your script, the first iteration you posted, i started working on that and getting it to work properly. I noticed your variant had problems with the paths. I think if you just get the file path from the original array and use that it works flawless on all systems. I did not test my iteration on OSX yet though.

 

Anyways, with a combination of my own script parts and some of the layercomp exporter i got it work.

Its functionality now is that the user selects the layers containing the missing links. Then we prompt for a folder, and it runs over all. I also expanded it with some more file types for my needs.

 

This is really super nice, now i can work properly on my designs on both OSX and Windows without the need to manual relink all the files. Thats really hideous to do when you got around 100 or more linked files.

 

Ive also added some extra pars so it show in a sub part of the script menu

restore-missing-links.png

 

 

// Collection of scripts i gathered for quick relinken missing images
// Rombout Versluijs Dec 2020


/*
@@@BUILDINFO@@@ Restore Missing Links.jsx 0.0.0.7
*/
/*
// BEGIN__HARVEST_EXCEPTION_ZSTRING
/*
<javascriptresource>
<name>$$$/JavaScripts/RestoreMissingLinks/Menu=Restore Missing Links...</name>
<category>aaaThisPutsMeAtTheTopOfTheMenu</category>
//<category>Restore</category>
<enableinfo>true</enableinfo>
</javascriptresource>

// END__HARVEST_EXCEPTION_ZSTRING

*/


#target photoshop

// var docName = app.activeDocument.name;
// app.activeDocument = app.documents[docName];
docRef = app.activeDocument;

//var new_path = "D:\\_MINDFLOW\\CLIENTS\\Allusion\\Design\\Recourses\\Icons-24x"; // YOUR REAL NEW PATH
//alert(new_path)
function cTID(s) { return app.charIDToTypeID(s); };
function sTID(s) { return app.stringIDToTypeID(s); };


///////////////////////////////////////////////////
// Get Layer Kind
// https://www.ps-scripts.com/viewtopic.php?p=43242#p43242
// Get return layerkind by layerid
///////////////////////////////////////////////////
function getLayerKindByIndex(index) {
    var ref, desc, adjustmentDesc, layerSectionType;
    ref = new ActionReference();
    ref.putIndex(charIDToTypeID("Lyr "), index);
    desc = executeActionGet(ref);
    var layerType = typeIDToStringID(desc.getEnumerationValue(stringIDToTypeID('layerSection')));
    if (layerType != 'layerSectionContent') return; // return if layerSet
    if (desc.hasKey(stringIDToTypeID('textKey'))) return LayerKind.TEXT;
    if (desc.hasKey(stringIDToTypeID('smartObject'))) return LayerKind.SMARTOBJECT; // includes LayerKind.VIDEO
    if (desc.hasKey(stringIDToTypeID('layer3D'))) return LayerKind.LAYER3D;
    if (desc.hasKey(stringIDToTypeID('videoLayer'))) return LayerKind.VIDEO;
    if (desc.hasKey(stringIDToTypeID('adjustment'))) {
        switch (typeIDToStringID(desc.getList(stringIDToTypeID('adjustment')).getClass(0))) {
            case 'photoFilter':
                return LayerKind.PHOTOFILTER;
            case 'solidColorLayer':
                return LayerKind.SOLIDFILL;
            case 'gradientMapClass':
                return LayerKind.GRADIENTMAP;
            case 'gradientMapLayer':
                return LayerKind.GRADIENTFILL;
            case 'hueSaturation':
                return LayerKind.HUESATURATION;
            case 'colorLookup':
                return udefined; //this does not exist and errors with getting layer kind
            case 'colorBalance':
                return LayerKind.COLORBALANCE;
            case 'patternLayer':
                return LayerKind.PATTERNFILL;
            case 'invert':
                return LayerKind.INVERSION;
            case 'posterization':
                return LayerKind.POSTERIZE;
            case 'thresholdClassEvent':
                return LayerKind.THRESHOLD;
            case 'blackAndWhite':
                return LayerKind.BLACKANDWHITE;
            case 'selectiveColor':
                return LayerKind.SELECTIVECOLOR;
            case 'vibrance':
                return LayerKind.VIBRANCE;
            case 'brightnessEvent':
                return LayerKind.BRIGHTNESSCONTRAST;
            case 'channelMixer':
                return LayerKind.CHANNELMIXER;
            case 'curves':
                return LayerKind.CURVES;
            case 'exposure':
                return LayerKind.EXPOSURE;
                // if not one of the above adjustments return - adjustment layer type
            default:
                return typeIDToStringID(desc.getList(stringIDToTypeID('adjustment')).getClass(0));
        }
    }
    return LayerKind.NORMAL; // if we get here normal should be the only choice left.
};



/// ////////////////////////////////////////////////////////////////////////////
// Function: Combination of applyToAllLayersAMIdx & getLayerInfo
// Usage: extract a list of index values of all the selected layers & ID layernamer
// Input:: (active document.) s
// Return: array of indexes ID"s of selected layers.
// Mixed this so it only loops once over all layers
/// ////////////////////////////////////////////////////////////////////////////
function applyToAllLayersInfo(docRef) {
    // alert(docRef)
    var selectedLayers = new Array()
    var ref = new ActionReference()
    // get a number list of selected artLayers in the document
    ref.putProperty(app.charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"))
    ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"))
    // what do I want to do this this list? Define an description of an action.
    var desc = executeActionGet(ref)
    // if the selected object has the "Target Layers" key (only works CS4+)
    if (desc.hasKey(stringIDToTypeID("targetLayers"))) {
        desc = desc.getList(stringIDToTypeID("targetLayers"))
        var c = desc.count
        var selectedLayers = [] // for each
        for (var i = 0; i < c; i++) {
            var lyr = {}
            var lyrIndex;
            try {
                docRef.backgroundLayer // try to select a background layer, if I can then adjust the index counting. (Background layers change index counitng of all layers by 1)
                // selectedLayers.push(desc.getReference(i).getIndex())
                lyrIndex = desc.getReference(i).getIndex();
            } catch (e) {
                // selectedLayers.push(desc.getReference(i).getIndex() + 1)
                lyrIndex = desc.getReference(i).getIndex() + 1;
            }
            // Added from getLayerInfo
            var lyrRef = new ActionReference();
            lyrRef.putIndex(charIDToTypeID("Lyr "), lyrIndex)
            var lyrDesc = executeActionGet(lyrRef);
            // alert(lyrDesc.getInteger(stringIDToTypeID("layerKind")))
            var Id = lyrDesc.getInteger(stringIDToTypeID("layerID"));
            lyr.AMid = Id;
            lyr.lyrKind = getLayerKindByIndex(lyrIndex);
            lyr.lyrIndex = lyrIndex;
            selectedLayers.push(lyr);
        }
    }
    return selectedLayers
}



///////////////////////////////////////////////////
// Select Layer by LayerIndex
// Source: https://stackoverflow.com/questions/26295492/photoshop-script-new-layer-below-current-layer
// select [LayerNum], optionally [add] to selection (if add=2: with inclusion)
///////////////////////////////////////////////////
function selLyr(LyrN, add) {
    var adesc = new ActionDescriptor();
    var aref = new ActionReference();
    aref.putIndex(charIDToTypeID("Lyr "), LyrN);
    adesc.putReference(charIDToTypeID("null"), aref);
    if (add) {
        add = (add == 2) ? stringIDToTypeID("addToSelectionContinuous") : stringIDToTypeID("addToSelection");
        adesc.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), add);
    }
    adesc.putBoolean(charIDToTypeID("MkVs"), false);
    return executeAction(charIDToTypeID("slct"), adesc, DialogModes.NO);
}



///////////////////////////////////////////////////
// Select Layers by LayerID
// Source: https://graphicdesign.stackexchange.com/questions/130739/photoshop-scripting-applying-changes-only-to-selected-artboards
///////////////////////////////////////////////////
function selectById(AMid) {
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putIdentifier(charIDToTypeID('Lyr '), AMid);
    desc1.putReference(charIDToTypeID('null'), ref1);
    executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
}


/// ////////////////////////////////////////////////////////////////////////////
// Function: getSelectedLayersAMIdx
// Usage: extract a list of index values of all the selected layers.
// Input:: (active document.) s
// Return: array of indexes ID"s of selected layers.
/// ////////////////////////////////////////////////////////////////////////////
function getSelectedLayersAMIdx(docRef) {
    var selectedLayers = new Array()
    var ref = new ActionReference()
    // get a number list of selected artLayers in the document
    ref.putProperty(app.charIDToTypeID("Prpr"), stringIDToTypeID("targetLayers"))
    ref.putEnumerated(charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"))
    // what do I want to do this this list? Define an description of an action.
    var desc = executeActionGet(ref)
    // if the selected object has the "Target Layers" key (only works CS4+)
    if (desc.hasKey(stringIDToTypeID("targetLayers"))) {
        desc = desc.getList(stringIDToTypeID("targetLayers"))
        var c = desc.count
        var selectedLayers = [] // for each
        for (var i = 0; i < c; i++) {
            try {
                docRef.backgroundLayer // try to select a background layer, if I can then adjust the index counting. (Background layers change index counitng of all layers by 1)
                selectedLayers.push(desc.getReference(i).getIndex())
            } catch (e) {
                selectedLayers.push(desc.getReference(i).getIndex() + 1)
            }
        }
    }
    return selectedLayers
}



/// ////////////////////////////////////////////////////////////////////////////
// Function: relinkFiles
// Usage: relinks path to missing linked image.
// Input:: string of path to found image
// Return: correct linked image
// source: https://community.adobe.com/t5/photoshop/update-linked-smart-objects-broken-file-path/m-p/11707888?page=1#M213131
/// ////////////////////////////////////////////////////////////////////////////
function relinkFiles() {
    var r = new ActionReference();
    r.putProperty(stringIDToTypeID("property"), stringIDToTypeID("smartObject"));
    r.putEnumerated(stringIDToTypeID("layer"), stringIDToTypeID("ordinal"), stringIDToTypeID("targetEnum"));
    var d = executeActionGet(r);
    if (d.hasKey(stringIDToTypeID("smartObject"))) {
        d = d.getObjectValue(stringIDToTypeID("smartObject"));
        if (d.hasKey(stringIDToTypeID("link"))) {
            var type = d.getType(stringIDToTypeID("link"));
            var pth;
            switch (type) {
                case DescValueType.ALIASTYPE:
                    pth = d.getPath(stringIDToTypeID("link"));
                    break;
                case DescValueType.STRINGTYPE:
                    pth = d.getString(stringIDToTypeID("link"));
                    break;
                default:
                    throw ("\n\nHmmm!\n\n");
            }
            var file = new File(pth);
            if (!file.exists) {
                file = new File(new_path + "\\" + file.name);
                var d = new ActionDescriptor();
                d.putPath(stringIDToTypeID("null"), file);
                //executeAction(stringIDToTypeID("placedLayerRelinkToFile"), d, DialogModes.NO);// replace link
                executeAction(stringIDToTypeID("placedLayerReplaceContents"), d, DialogModes.NO); // replace content
                alert("Done!")
            } else
                alert("File already exists");
        } else {
            alert("No link");
        }
    } else {
        alert("No smartObject");
    }
}


/// ////////////////////////////////////////////////////////////////////////////
// Function: searchFolder
// Usage: prompt for folder and loop over files
// Input:: folder path
// Return: correct linked image
// source: https://community.adobe.com/t5/photoshop/place-linked-using-script/td-p/10205968?page=1
/// ////////////////////////////////////////////////////////////////////////////
var linkFolder = Folder.selectDialog("Selection prompt");
// alert(linkFolder)
function searchFolder(){
    var layerN = docRef.activeLayer.name;
    if(linkFolder !== null){
        var linkFolderPath = linkFolder.path;
        var linkName = linkFolder.name;
        var linkFullPath = linkFolderPath+"/"+linkName;
        function traverseFolder(path, layerN)  { 
            var folder = new Folder(path); 
            suffix = new Array();
            suffix[0] = "tif";
            suffix[1] = "dng";
            suffix[2] = "psd";
            suffix[3] = "svg";
            suffix[4] = "jpg";
            var files = folder.getFiles(); 
            for (var i = 0; i < files.length; i++) { 
                if (files[i] instanceof File) {  
                    var fullPathName = Folder.decode(files[i]);
                    //alert(fullPathName)
                    var fileName = files[i].name;
                    //alert(fileName)
                    fileName = decodeURI(fileName);
                    //alert(fileName)
                    for(var s = 0; s < suffix.length ; s++){
                        search_name = layerN + "." + suffix[s];
                        search_NAME = layerN + "." + suffix[s].toUpperCase();
                        if ((fileName == search_name) || (fileName == search_NAME)) 
                        { 
                            foundFile = fullPathName + "/" + fileName;
                            //alert("Found: " + foundFile); 
                            //alert("Found: " + files[i]); 
                            relinkFile(files[i])
                            return files[i] ;
                        }
                    }
                } else { 
                traverseFolder(files[i], layerN); 
                // return traverseFolder(files, layerN); 
                } 
            } 
        }
        
        function relinkFile(foundFile){
            var d = new ActionDescriptor();
            d.putPath( cTID('null'), new File( foundFile ) );
            executeAction(stringIDToTypeID("placedLayerRelinkToFile"), d, DialogModes.NO);// replace link
            // executeAction( sTID('placedLayerReplaceContents'), d, DialogModes.NO );// replace content
        }
        var foundFile = traverseFolder(linkFullPath, layerN);
        //alert(foundFile)
    }
}

var layerInfo = applyToAllLayersInfo(docRef);
for (var i = 0; i < layerInfo.length; i++) {
    selectById(layerInfo[i].AMid);
    searchFolder()
}

 

Votes

Translate

Translate

Report

Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines