Skip to main content
Known Participant
December 13, 2019
Question

Exploring Link.relink() function in Javascript and COM

  • December 13, 2019
  • 1 reply
  • 1739 views

Some days ago I needed to change my automation tool written in C# as Windows application. The reason was that we use Dropbox now and all pages opened on another computer have a whole bunch of missing links due to different Dropbox folder locations.

 

Updating links in Javascript is easy and if I do it from Indesign I use following script:

 

 

var alllinks = app.activeDocument.links;
for (var i = 0; i < alllinks.length; i++)
{
    var cur_link = alllinks[i];
    {
        var m = cur_link.filePath.match(/.+Dropbox\\(.+)/);
        if (m)
        {
            try
            {
                cur_link.relink(File('W:\\' + m[1]));
            }
            catch (e)
            { }
        }

    }
}

 

 

where W: is my Dropbox folder mapped as drive letter.

 

But as I tried to implement the same logic in my application using COM access

 

 

var allLinks = Doc.Links;
for (int i = 1; i <= allLinks.Count; i++)
{
Link l = allLinks[i];
if (l.Status == idLinkStatus.idLinkMissing)
{
string lp = (string) l.FilePath;
if (lp.IndexOf("Dropbox", StringComparison.Ordinal) > -1)
try
{
l.Relink(Regex.Replace(lp, ".+Dropbox", "W:"));
}
catch (COMException)
{
// ignored
}
}
}

 

 

I found that it doesn't work - relink function doesn't accept the new filename as string.

So I decided to look a little closer at the Javascript relink() function.

 

DOM defines it as following:

 

Link.relink (to:varies)

Adobe InDesign 2020 (15.0) Object Model

Points the link to a new source file.

to: Data Type: varies

The full path name of the new source file. Can accept: File or String.

 

In case of File it works perfectly and I am sure all of you use it in your scripts:

 

 

relink(File(newfilename));

 

 

But what about String?

I made a test page with missing image (d:\test\missing.jpg) and a test script:

 

 

var alllinks = app.activeDocument.links;
var newlink = "d:\\test\\test.jpg";
for (var i = 0; i < alllinks.length; i++)
{
    var cur_link = alllinks[i];
	$.writeln(cur_link.filePath + ' - ' + cur_link.status.toString());
        if (cur_link.status == LinkStatus.LINK_MISSING)
        {
            try
            {
                cur_link.relink(newlink);
		$.writeln(cur_link.filePath + ' - ' + cur_link.status.toString());
            }
            catch (e)
            { }
        }	
}

 

 

where I used a filename string as argument for relink().

Result:

d:\test\missing.jpg - LINK_MISSING

The function shows no error but does nothing and just goes to next loop iteration.

Changing the line

 

 

cur_link.relink(newlink);

 

 

to

 

 

cur_link.relink(File(newlink));

 

 

I got a working function:

d:\test\missing.jpg - LINK_MISSING
D:\test\test.jpg - NORMAL

 

So what does Adobe mean with the String and how could I get the right string in C#?

After some tests I have found the answer!

 

DOM should define the function argument as following:

The full path name of the new source file. Can accept: File or Uri String.

Indeed, if I change the filename string to Uri

 

 

cur_link.relink('file:' + newlink);

 

 

the script is working again:

d:\test\missing.jpg - LINK_MISSING
d:\test\test.jpg - NORMAL

Now I can use it in my C# code:

 

 

l.Relink($"file:{Regex.Replace(lp, ".+Dropbox", "W:")}");

 

 

 

Is the problem solved now? No.

The above solution works only if the new filename/path has no spaces.

As I deal with German filenames, it means

The above solution works only if the new filename/path has no umlauts.

So it wasn't a solution at all.

I needed to convert the new path to a valid Uri string.

That wasn't too complicate. In Javascript&colon;

 

 

cur_link.relink('file:' + encodeURI(newlink));

 

 

In C#:

 

 

l.Relink($"file:{Uri.EscapeUriString(Regex.Replace(lp, ".+Dropbox", "W:"))}");

 

 

Result:

d:\test\missing.jpg - LINK_MISSING
d:\test\test.jpg - NORMAL

 

I added another missing image to my test page to test the solution in a loop.

Result:

d:\test\missing.jpg - LINK_MISSING
d:\test\test.jpg - NORMAL
d:\test\missing.jpg - LINK_MISSING
d:\test\test.jpg - NORMAL

 

Victory! 🙂

 

To make my research complete, I tested the new reinitLink() function, which is stated as experimental.

 

 

cur_link.reinitLink('file:' + encodeURI(newlink));

 

 

Result:

d:\test\missing.jpg - LINK_MISSING
d:\test\test.jpg - LINK_OUT_OF_DATE
d:\test\test.jpg - LINK_OUT_OF_DATE

So, this function replaces link paths but doesn't update links.

 

I hope, this information might be useful. 🙂

1 reply

Community Expert
May 27, 2025

Hi @Michael_Rosenstein ,

I'm also testing the then ( InDesign 2018 ) new experimental method itemLink.reinitLink( linkResourceURI ) .

With InDesign 2025 in DOM documentation it's still mentioned as "experimental":

https://www.indesignjs.de/extendscriptAPI/indesign-latest/#Link.html#d1e301019__d1e301757

 

To my surprise there is a perhaps not documented feature ( or bug ) with reinitLink() .

 

If one graphic is placed more than one time, my tests are showing that if I use reinitLink() on one single instance of the graphic's itemLink the itemLink.linkResourceURI value for ALL OTHER INSTANCES in the document will change as well.

 

In my test case I had 2 pairs of images placed.

One pair of images share images with the same name but with different contents.

 

In one of the two pairs I wanted to "assign" a new linkResourceURI with reinitLink(), the one of the other image's linkResourceURI. To test if the image will change status. So it did. From NORMAL to OUT_OF_DATE as expected.

 

What was not expected by me was that the corresponding image in the other pair of images changed as well to OUT_OF_DATE with a new linkResourceURI. That behavor bears some dangers when using reinitLink() to graphics and images that are placed more than one time in a document.

 

Details from my German InDesign 2025:

 

Running this code on my selection of images:

var linkResourceURI1 = app.selection[0].allGraphics[0].itemLink.linkResourceURI;
var linkResourceURI2 = app.selection[1].allGraphics[0].itemLink.linkResourceURI;

app.selection[0].allGraphics[0].itemLink.reinitLink( linkResourceURI2 );

 

Result where also the other instance of the image has changed, not only the selected one:

 

 

Regards,
Uwe Laubender
( Adobe Community Expert )

Community Expert
May 27, 2025

On with my tests:

If there is yet a different image is placed with the same name, this one will not change with my script snippet.

Just the other instance of the same placed file.

 

Before script run:

 

 

After the script run:

 

Regards,
Uwe Laubender
( Adobe Community Expert )