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

Extend script not auto refreshing the missing link.

Engaged ,
Mar 15, 2024 Mar 15, 2024

Copy link to clipboard

Copied

I made a script that takes the selected image in indesign, sends it to photoshop, uses the select subject command, masks it and saves it as a tiff with transparancy. This is just for rough cut outs and it speed up my workflow quite a bit but I'm running into one snag. Indesign isn't updating the link. I tried onResult with a delay but thats not working. I end up having to refresh the link manually which isn't the end of the world but it would be nice to not have to do that. Any one know how to get that working?

 

if (app.documents.length > 0 && app.selection.length > 0 && app.selection[0].constructor.name == "Rectangle") {
    var selectedFrame = app.selection[0];

    if (selectedFrame.images.length > 0) {
        var imageFile = new File(selectedFrame.images[0].itemLink.filePath);

        if (imageFile.exists) {
            app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL;

            var photoshop = BridgeTalk.getSpecifier("photoshop");
            if (photoshop) {

                var openScript = "var openFile = new File(\"" + imageFile.fsName + "\");\r";
                openScript += "app.open(openFile);\r";

                var photoshopScript = "if (app.documents.length > 0) {\r";
                photoshopScript += "    var docRef = app.activeDocument;\r";

                // Select Subject
                photoshopScript += "    try {\r";
                photoshopScript += "        var desc = new ActionDescriptor();\r";
                photoshopScript += "        executeAction(stringIDToTypeID('autoCutout'), desc, DialogModes.NO);\r";
                photoshopScript += "    } catch (e) {\r";
                photoshopScript += "        alert(\"Error during autoCutout: \" + e.message);\r";
                photoshopScript += "    }\r";

                // Mask
                photoshopScript += "maskSelection(\"revealSelection\");\r\n";
                photoshopScript += "function maskSelection(maskParameter) {\r";
                photoshopScript += "    var s2t = function (s) { return app.stringIDToTypeID(s); };\r";
                photoshopScript += "    var descriptor = new ActionDescriptor();\r";
                photoshopScript += "    var reference = new ActionReference();\r";
                photoshopScript += "    descriptor.putClass( s2t( \"new\" ), s2t( \"channel\" ));\r";
                photoshopScript += "    reference.putEnumerated( s2t( \"channel\" ), s2t( \"channel\" ), s2t( \"mask\" ));\r";
                photoshopScript += "    descriptor.putReference( s2t( \"at\" ), reference );\r";
                photoshopScript += "    descriptor.putEnumerated( s2t( \"using\" ), s2t( \"userMaskEnabled\" ), s2t( maskParameter ));\r";
                photoshopScript += "    executeAction( s2t( \"make\" ), descriptor, DialogModes.NO );\r";
                photoshopScript += "}\r\n";

                // Save
                photoshopScript += "    var saveOptions = new TiffSaveOptions();\r";
                photoshopScript += "    saveOptions.transparency = true;\r";
                photoshopScript += "    saveOptions.layers = true;\r";
                photoshopScript += "    saveOptions.alphaChannels = true;\r";
                photoshopScript += "    saveOptions.embedColorProfile = true;\r";
                photoshopScript += "    saveOptions.imageCompression = TIFFEncoding.NONE;\r";
                photoshopScript += "    try {\r";
                photoshopScript += "        docRef.saveAs(docRef.fullName, saveOptions, true, Extension.LOWERCASE);\r";
                photoshopScript += "    } catch (e) {\r";
                photoshopScript += "        alert(\"Failed to save the file. Error: \" + e.message);\r";
                photoshopScript += "    }\r";
                photoshopScript += "}\r";

                photoshopScript += "app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);\r";

                // Bridgetalk
                var bt = new BridgeTalk();
                bt.target = photoshop;
                bt.body = openScript + photoshopScript;

                // Refresh selection
                bt.onResult = function(res) {
                    setTimeout(function() {
                        var link = selectedFrame.images[0].itemLink;
                        link.relink(new File(imageFile.fsName));
                        link.update();
                    }, 2000); // Delay of 2 seconds
                };

                bt.send();

            } else {
                alert("Photoshop is not available.");
            }

        } else {
            alert("The image file associated with the selected frame does not exist.");
        }

    } else {
        alert("The selected frame does not contain an image.");
    }

} else {
    alert("Please select a frame that contains an image in an InDesign document.");
}
TOPICS
Scripting

Views

457

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 2 Correct answers

Community Expert , Mar 16, 2024 Mar 16, 2024

Hi @davidn5918184 (and @Eugene Tyson) I actually couldn't get the bt.onResult function to execute at all. Is that a known thing? I've hardly done any BridgeTalk so I have no idea. I'm on MacOS, so maybe on Windows onResult works?

 

@davidn5918184 I've made some adjustments to your code, mostly for your interest, and my learning, and I've got it working. It's not super pretty, but has improved a bit I hope.

 

Some notes:

1. You don't have to write the bridgeTalk body out as strings. It's more con

...

Votes

Translate

Translate
Community Expert , Mar 16, 2024 Mar 16, 2024

I tried onResult with a delay but thats not working.

 

Hi @davidn5918184 , Bridgetalk can be difficult. Rather than editing your code, here is a example of template I use where I write a regular Photoshop function and retrieve it as a string for the BridgeTalk body object—I find it’s a lot easier to debug the Photoshop function doing it this way.

 

I don’t think a delay will help—you have to return the new tif file path via resObject.body to InDesign after the Photoshop code is complete. In this

...

Votes

Translate

Translate
Community Expert ,
Mar 15, 2024 Mar 15, 2024

Copy link to clipboard

Copied

You could try something like this

// Refresh link in InDesign
bt.onResult = function(res) {
    // Wait for a short delay to ensure Photoshop has finished processing
    $.sleep(1000); // Adjust delay time as needed
    // Relink and update the link in InDesign
    var link = selectedFrame.images[0].itemLink;
    link.relink(new File(imageFile.fsName));
    link.update();
};

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

Hi @davidn5918184 (and @Eugene Tyson) I actually couldn't get the bt.onResult function to execute at all. Is that a known thing? I've hardly done any BridgeTalk so I have no idea. I'm on MacOS, so maybe on Windows onResult works?

 

@davidn5918184 I've made some adjustments to your code, mostly for your interest, and my learning, and I've got it working. It's not super pretty, but has improved a bit I hope.

 

Some notes:

1. You don't have to write the bridgeTalk body out as strings. It's more convenient to write it as a normal function, and then coerce that to a string, but you have to then execute the function code in that string, so I wrapped it in an IIFE (again as a string).

 

2. I've used the principal of "returning early" so that we don't have that hierarchy of massive blocks wrapping everything. This helps to keep the code more straightforward and readable especially because the predicate and the error message are together.

 

3. I've used a method of Link called "reinit" which changes the linked item's file but—critically—it doesn't matter if that file exists. This is perfect for this case, because we can set it without really caring much if Photoshop has finished.

 

4. I've used a bit of a clumsy while loop at the end to do the link.update()—if you want a neater approach, then maybe use an idleTask? Or better yet... UXP?

 

Anyway, here's my adjusted version. See what you think.

- Mark

 

UPDATE: please see my other variation on this script, which incorporates @rob day's knowledge and is much better.

 

/**
 * @discussion https://community.adobe.com/t5/indesign-discussions/extend-script-not-auto-refreshing-the-missing-link/m-p/14492836
 */
function main() {

    if (
        0 === app.documents.length
        || 0 === app.selection.length
        || 'Rentangle' === app.selection[0].constructor.name
    )
        return alert("Please select a frame that contains an image in an InDesign document.");

    var selectedFrame = app.selection[0];

    if (0 === selectedFrame.images.length)
        return alert("The selected frame does not contain an image.");

    var imageFile = new File(selectedFrame.images[0].itemLink.filePath);

    if (!imageFile.exists)
        return alert("The image file associated with the selected frame does not exist.");

    app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL;

    var photoshop = BridgeTalk.getSpecifier("photoshop");

    if (!photoshop)
        alert("Photoshop is not available.");

    // Bridgetalk
    var bt = new BridgeTalk();
    bt.target = photoshop;

    // arrange the function as an IIFE string, and put the file path in it
    bt.body = '(X)();'
        .replace('X', autoCutoutForPhotoshop + '\r')
        .replace('/*IMAGE_FILE_PATH*/', imageFile.fsName);

    // does this work for anyone? it doesn't for me
    bt.onResult = function () { alert('Do you see this?') };

    bt.send();

    var link = selectedFrame.images[0].itemLink;

    // this must match what we did to the filename in photoshop!
    var linkURI = link.linkResourceURI.replace(/\.[^\.]+$/, '.tif');

    // reinit the link, pointing to the .tif file
    // you can do this even if the file doesn't exist yet!
    link.reinitLink(linkURI);

    var done = false,
        counter = 0;

    // try to update link a bunch of times!
    // timing out after 10 tries
    while (!done && counter++ < 10) {
        try {
            $.sleep(1000);
            if (LinkStatus.LINK_OUT_OF_DATE === link.status) {
                link.update();
                done = true;
            };
        } catch (error) { }
    }

    alert(done ? 'Succeeded!' : 'Failed');

};

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Auto Cutout');


function autoCutoutForPhotoshop() {

    var openFile = new File('/*IMAGE_FILE_PATH*/');
    app.open(openFile);

    if (0 === app.documents.length)
        return;

    var docRef = app.activeDocument;

    try {
        var desc = new ActionDescriptor();
        executeAction(stringIDToTypeID('autoCutout'), desc, DialogModes.NO);
    } catch (e) {
        alert("Error during autoCutout: " + e.message);
    }

    maskSelection("revealSelection");

    function maskSelection(maskParameter) {
        var s2t = function (s) { return app.stringIDToTypeID(s); };
        var descriptor = new ActionDescriptor();
        var reference = new ActionReference();
        descriptor.putClass(s2t("new"), s2t("channel"));
        reference.putEnumerated(s2t("channel"), s2t("channel"), s2t("mask"));
        descriptor.putReference(s2t("at"), reference);
        descriptor.putEnumerated(s2t("using"), s2t("userMaskEnabled"), s2t(maskParameter));
        executeAction(s2t("make"), descriptor, DialogModes.NO);
    };

    var saveOptions = new TiffSaveOptions();
    saveOptions.transparency = true;
    saveOptions.layers = true;
    saveOptions.alphaChannels = true;
    saveOptions.embedColorProfile = true;
    saveOptions.imageCompression = TIFFEncoding.NONE;

    try {
        docRef.saveAs(docRef.fullName, saveOptions, true, Extension.LOWERCASE);
    } catch (e) {
        alert("Failed to save the file. Error: " + e.message);
    }

    app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);

};

 

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

I'm not sure - I've seen it elsewhere - like here 
https://community.adobe.com/t5/photoshop-ecosystem-discussions/how-to-get-result-from-bridgetalk-mes...

 

I didn't actually get a chance to test it - I just thought the idea at least was to add a wait time before trying to update the link. 

 

It was just an idea.

 

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

You are totally right that that's where the code *should* go, as you say. But it simply didn't execute for me. Something I don't understand—maybe even a bug.

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

But it simply didn't execute for me

 

Hi Mark, this minimal example shows how the result is handled:

 

runPhotoshop(new BridgeTalk());

function runPhotoshop(bt){

    bt.target = "photoshop";  
    bt.body = psScript.toString() + "\rpsScript();";
    bt.onResult = function(resObj) { 
        alert("InDesign is now running. The returned result is: " + resObj.body);
    } 
    //this would return the result asynchronously
    //the result never makes it back to InDesign and there is no alert
    //bt.send();  
    //this sends the result synchronously with a timeout as the parameter
    bt.send(100);

    function psScript() {  
        var s = "Hello World"
        //nothing returned
        //return s
    }  
}

 

Result:

 

Screen Shot 28.png

 

runPhotoshop(new BridgeTalk());

function runPhotoshop(bt){

    bt.target = "photoshop";  
    bt.body = psScript.toString() + "\rpsScript();";
    bt.onResult = function(resObj) { 
        alert("InDesign is now running. The returned result is: " + resObj.body);
    } 
    //this sends the result synchronously with a timeout as the parameter
    bt.send(100);

    function psScript() {  
        var s = "Hello World"
        return s
    }  
}

 

The result when the Photoshop function returns a string

 

 

Screen Shot 27.png

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

Thank you, M1B, for providing me with a functional script. It accomplishes exactly what I needed, even if it might not be the most "pretty" solution. Also, I appreciate Rob's contribution of the template. I'll work on implementing it and definitely plan to utilize it moving forward.

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

Glad to hear that it was helpful! See my newer version of the script below, where I have incorporated Rob's help.

- Mark

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 ,
Mar 17, 2024 Mar 17, 2024

Copy link to clipboard

Copied

Hi Mark, It wouldn’t be a problem is this case— it’s unlikely there would be multiple images in the selection— but I think you want to avoid creating multiple Bridgetalk instances inside of a loop.

 

There are lots of ways to do that, but here’s a simplified example where I create a single Bridgetalk instance, and pass it into the Photoshop function rather than creating a new instance for every item in the loop. This gets the all of the document’s links and returns new file paths:

 



main()

function main(){
    //create a single Bridgetalk instance to be referenced in the loop
    //rather than creating new instances inside the loop
    var bt = new BridgeTalk();
    bt.target = "photoshop"; 

    // a variable to hold the result
    var res;
    bt.onResult = function(resObj) { 
        res = resObj.body;
    } 

    //get the document links, send their paths to PS
    //and get new paths returned from Photoshop
    var lnks = app.documents[0].links;
    for (var i = 0; i < lnks.length; i++){
        
        getNewImage(lnks[i].filePath, bt)
        //res is the new file path returned from Photoshop
        $.writeln(res);
    };   
}


/**
* Sends a Bridgetalk message to Photoshop 
* @ param a Bridgetalk instance 
* @ param a file path as a string 
* @ returns a new file path string 
* 
*/
function getNewImage(fp, bt){
    bt.body = psScript.toString() + "\rpsScript('"+fp+"');";
    bt.send(10);
    function psScript(fp) {     
        //save as routine here
        return fp.replace(RegExp('()?\.[^\.]+$'), '.tif');
    }  
}


 

 

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 ,
Mar 17, 2024 Mar 17, 2024

Copy link to clipboard

Copied

Yes thank you! I actually wondered about that, but decided not to worry because they are pretty lightweight objects. I might adjust script tomorrow. Thanks again, I've learned heaps. 

- Mark 

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 ,
Mar 19, 2024 Mar 19, 2024

Copy link to clipboard

Copied

@rob day I finally got around to testing and I didn't find any difference in performance whether I created 1000 bridgetalk message objects or re-used just one. I believe they are very lightweight—really not much to them.

- Mark

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 ,
Mar 19, 2024 Mar 19, 2024

Copy link to clipboard

Copied

LATEST

Thanks. I just make it a practice to always declare variables outside of the loop.

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

I tried onResult with a delay but thats not working.

 

Hi @davidn5918184 , Bridgetalk can be difficult. Rather than editing your code, here is a example of template I use where I write a regular Photoshop function and retrieve it as a string for the BridgeTalk body object—I find it’s a lot easier to debug the Photoshop function doing it this way.

 

I don’t think a delay will help—you have to return the new tif file path via resObject.body to InDesign after the Photoshop code is complete. In this example the image to open is a .psd, and I’m saving it as a tif and replacing it with the Photoshop function’s returned file path. I’m not including your action descriptor code for the mask:

 



maskImage()

//a variable for the new .tif file path
var np;

/**
* An InDesign function to run 
* creates a Bridgetalk instance and opens a selected image
* @ return void 
*/

function maskImage(){
    if (app.selection.length > 0) {
        var s = app.selection[0]
        if (s.constructor.name == "Image") {
            var img = s.itemLink;
            var b = new BridgeTalk();  
            openImage(img.filePath, b);
            img.relink(File(np))
            alert("Updated Link To:\r" + np)
        } 
    } else {
        alert("Select an Image")
        return
    }
}


/**
* Open the selected link in Photoshop 
* @ param the image file path 
* @ param A single BridgeTalk instance created in InDesign
* @ return void 
* 
*/
function openImage(fp, bt){
    bt.target = "photoshop";  

    //Get the body from the psScript function below Note a string parameter is '"+fp+"'
    bt.body = psScript.toString() + "\rpsScript('"+fp+"');";

    //This is missing from your code resObj.body is
    //the returned value of the Photoshop function 
    //sent back to InDesign
    //the new file path in this case
    bt.onResult = function(resObj) { 
        np = resObj.body;
    }  
    bt.onError = function( inBT ) { alert(inBT.body); };  
    bt.send(8); 
    
    /**
    * A Photoshop function to run 
    * @ param a  
    * @ return value 
    */
    function psScript(fp) {  

        var of = open (File(fp));   
        //get the opened file’s name
        var n = fp.split( "." )
        if ( n.length > 1 ) {
            n.length--;
        }
        n = n.join(".");

        //add your Photoshop actions and code here...


        //TIFF save options
        var so = new TiffSaveOptions();
        so.transparency = true;
        so.layers = true;
        so.alphaChannels = true;
        so.embedColorProfile = true;
        so.imageCompression = TIFFEncoding.NONE;
        
        of.saveAs(new File(n + ".tif"), so, true);
        of.close(SaveOptions.DONOTSAVECHANGES);  

        //return the file path of the new tif back to InDesign
        return n + ".tif"
    }  
}


Before and after:

 
Screen Shot 22.png
 
Screen Shot 23.png
 
 

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

Thanks @rob day, are you saying that the onResult callback is only called when the bt.body returns a value?

- Mark

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

Right, your Photoshop function’s returned value gets saved as the resObj.body and sent back to InDesign—it can be a string or any other object.

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

Also do you mind me asking: why `8` in bt.send(8)? Come to think of it, do you know where good documentation for BridgeTalk can be found? I really no next to nothing about it.

- Mark

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

As far as I know, which is very little, it's priority 0-15 0 being lowest and 15 highest, 8 is normal... I think

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

It‘s the timeout for a returned value—when it’s specified the call is synchronous, which you probably want when ID is waiting for a value.

 

Here‘s the documentation:

 

https://extendscript.docsforadobe.dev/interapplication-communication/communicating-through-messages....

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

So it's not priority?

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

I don’t think so, I read it as the time allowed for a synchronous return of the Photoshop function‘s value. The parameter description is in the link above.

 

Here’s a generic example that throws up 3 alerts—1st when Photoshop is running, 2nd on the return to InDesign, and 3rd from InDesign with the returned Photoshop values:

 

//global variabes available to both ID and PS
var a = [];
var str = "Hello";

IDtoPS();

/**
* An InDesign function to run 
* creates a single Bridgetalk instance
* @ return void 
*/

function IDtoPS(){
    //I create a single Bridgtalk instance in InDesign
    //in case I want to run a loop
    var bt = new BridgeTalk();
    
    //variables to pass to the PS function
    var bol = true;
    var s = "World"
    runPhotoshop(bol, s, bt);
    
    //the global array returned from Photoshop
    alert("Returned From Photoshop: " + a[2] + " " + a[1])
}



/**
* A function to run in Photoshop 
* @ param a boolean example 
* @ param a string example 
* @ param a single bridgetalk object to use
* @ return void 
* 
*/
function runPhotoshop(isBoolean, theString, bt){
    //open Photoshop and run psScript()
    bt.target = "photoshop";  
    //the function string with a string variable and 2 parameters
    //Note a string parameter is '"+theString+"'
    //Other parameters are "+isBoolean+"
    bt.body = "var aString = '"+str+"'; \r" + psScript.toString() + "\rpsScript("+isBoolean+",'"+theString+"');";

    bt.onResult = function(resObj) { 
        //split the returned result body string into an array
        a = resObj.body.split(',');
        //return to InDesign
        alert("InDesign is now Running");
    }  
    bt.onError = function( inBT ) { alert(inBT.body); };  
    bt.send(1000);  
    //$.writeln(bt.body)
      
    function psScript(isBoolean, theString) {  
        //var doc = app.documents.add();
        app.bringToFront();
        //change the string variable value
        aString += " There"
        //Photoshop is running
        alert("Photoshop Running;  1st function Param= " + isBoolean +";  2nd Param= " + theString+ ";  1st Var= " + aString)
        return [isBoolean, theString, aString]
    }  
}

​

Screen Shot 24.png
 
 
Screen Shot 25.png
 
 
Screen Shot 26.png

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

That's interesting, thanks

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 ,
Mar 16, 2024 Mar 16, 2024

Copy link to clipboard

Copied

Okay, thanks very much @rob day you have taught me quite a bit about BridgeTalk. I've incorporated your information into a new version of the script, so now it doesn't need the hacky while loop, uses the synchronous call to BridgeTalk.send(), and I've also made it work with multiple graphics selected. This should be the one to use rather than the other, but I'll leave the other one there for the sake of comparison.

- Mark

/**
 * Auto Cutout Selected Images Using Photoshop
 * @authors davidn5918184, m1b, rob day
 * @discussion https://community.adobe.com/t5/indesign-discussions/extend-script-not-auto-refreshing-the-missing-link/m-p/14492836
 */
function main() {

    if (
        0 === app.documents.length
        || 0 === app.selection.length
    )
        return alert("Please select one or more frames that contains a images and try again.");

    var doc = app.activeDocument;
    var counter = {};

    cutOutImages(doc, doc.selection, counter);

    var successes = counter.successCount;

    alert('Cut out ' + (0 === successes ? 'no' : successes) + ' image' + (1 === successes ? '' : 's') + '.');

};

app.doScript(main, ScriptLanguage.JAVASCRIPT, undefined, UndoModes.ENTIRE_SCRIPT, 'Auto Cutout');


/**
 * Talks to Photoshop to do a quick "cut out" of selected images.
 * Cut out images will be saved in same location, with .tif extension.
 * @param {Document} doc - an Indesign Document.
 * @param {PageItem|Array<PageItem>|collection} item - a page item containing a graphic, or array or collection of.
 * @param {Object} [counter] - a counter object { successCount: 0 } used only for counting the number of successful cut-outs performed.
 * @param {Object} [success] - internal success flag.
 */
function cutOutImages(doc, item, counter, success) {

    // not sure what
    const timer = 2000;

    if (undefined != counter)
        counter.successCount = 0;

    if (item.hasOwnProperty('0')) {

        // handle collections of items
        for (var i = 0; i < item.length; i++) {

            // used for counting
            success = {};

            // do cutout on this one item
            cutOutImages(doc, item[i], undefined, success);

            if (
                undefined != counter
                && success.value
            )
                counter.successCount++;

        }

        return;

    }

    if (
        !item.hasOwnProperty('images')
        || 0 === item.images.length
    )
        // does not contain an image
        return;

    var imageFile = new File(item.images[0].itemLink.filePath);

    if (!imageFile.exists)
        return alert("The image file associated with the selected frame does not exist.");

    app.scriptPreferences.userInteractionLevel = UserInteractionLevels.INTERACT_WITH_ALL;

    var photoshop = BridgeTalk.getSpecifier("photoshop");

    if (!photoshop)
        alert("Photoshop is not available.");

    // Bridgetalk
    var bt = new BridgeTalk();
    bt.target = photoshop;

    // arrange the function as an IIFE string, and put the file path in it
    bt.body = '(X)();'
        .replace('X', autoCutoutForPhotoshop)
        .replace('#IMAGE_FILE_PATH#', imageFile.fsName);

    // callback
    bt.onResult = function (obj) {

        var f = File(obj.body);

        if (!f.exists)
            return;

        var link = item.images[0].itemLink;

        try {

            link.relink(f);

            if (LinkStatus.NORMAL === link.status)
                success.value = true;

        } catch (error) { }

    };

    bt.send(timer);

};


/**
 * Performs an auto cutout in Photoshop and saves
 * with added suffix as .tif file in same location.
 * Notes:
 *   - This function is designed to be coerced to
 *     a String for sending to BridgeTalk.
 *   - The placeholder #IMAGE_FILE_PATH# must be
 *     replaced with the image's path.
 * @returns {String} - the path to the saved .tif file.
 */
function autoCutoutForPhotoshop() {

    var suffix = '_cutout';

    var openFile = new File('#IMAGE_FILE_PATH#');
    app.open(openFile);

    if (0 === app.documents.length)
        return;

    var docRef = app.activeDocument;

    try {
        var desc = new ActionDescriptor();
        executeAction(stringIDToTypeID('autoCutout'), desc, DialogModes.NO);
    } catch (e) {
        alert("Error during autoCutout: " + e.message);
    }

    maskSelection("revealSelection");

    function maskSelection(maskParameter) {
        var s2t = function (s) { return app.stringIDToTypeID(s); };
        var descriptor = new ActionDescriptor();
        var reference = new ActionReference();
        descriptor.putClass(s2t("new"), s2t("channel"));
        reference.putEnumerated(s2t("channel"), s2t("channel"), s2t("mask"));
        descriptor.putReference(s2t("at"), reference);
        descriptor.putEnumerated(s2t("using"), s2t("userMaskEnabled"), s2t(maskParameter));
        executeAction(s2t("make"), descriptor, DialogModes.NO);
    };

    // note: easiest to use RegExp constructor form in BT because of backslashes not being escaped properly
    var cutoutFilePath = docRef.fullName.fsName.replace(RegExp('(' + suffix + ')?\.[^\.]+$'), suffix + '.tif');

    var saveOptions = new TiffSaveOptions();
    saveOptions.transparency = true;
    saveOptions.layers = true;
    saveOptions.alphaChannels = true;
    saveOptions.embedColorProfile = true;
    saveOptions.imageCompression = TIFFEncoding.NONE;

    try {
        docRef.saveAs(File(cutoutFilePath), saveOptions, true, Extension.LOWERCASE);
    }
    catch (e) {
        alert("Failed to save the file. Error: " + e.message);
    }
    finally {
        app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
    }

    return cutoutFilePath;

};

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 ,
Mar 17, 2024 Mar 17, 2024

Copy link to clipboard

Copied

I was thinking of adding a loop to handle multiple images at once, so thanks for the suggestion. This might use more resources, but it shouldn't be a problem for just a few images. To overwrite the original file, I changed the line to: var cutoutFilePath = docRef.fullName.fsName; This achieves what I want, but now when the image updates in InDesign, it shows transparency so it is reloading correctly and then indicates the link was modified, needing a refresh. It's interesting that this issue only occurs when overwriting the file, not with the original code you wrote. Any idea why this is?

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 ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

I just force it by adding link.update(); to the bt.onResult function. Thanks again for all the help! 

    bt.onResult = function (obj) {

        var f = File(obj.body);

        if (!f.exists)
            return;

        var link = item.images[0].itemLink;

        try {

            link.relink(f);

            if (LinkStatus.NORMAL === link.status)
                success.value = true;

                link.update();

        } catch (error) { }

    };

    bt.send(timer);

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 ,
Mar 18, 2024 Mar 18, 2024

Copy link to clipboard

Copied

Good solution! So the relink method doesn't actually update the graphic if it is the same filename? A tiny bug I guess.

 

I would suggest changing the order like this:

try {

    link.relink(f);

    if (LinkStatus.LINK_OUT_OF_DATE === links[i].status)
        link.update();

    if (LinkStatus.NORMAL === link.status)
        success.value = true;

} catch (error) { }

so that the update happens before the script marks the success flag (otherwise I don't think it will be counted).

- Mark

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