Highlighted

Find broken link name using placedItem name property

Community Beginner ,
Nov 06, 2020

Copy link to clipboard

Copied

Hello,

I'm trying to relink broken link with an input file path based on broken link name.

 

function updateLinks(inputFileName, inputFilePath)

{

   var activeDocument = app.activeDocument;

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

   {

       try {
          var file = activeDocument.placedItems[i].file;
           if (file && file.exists) {
             // Do nothing

          }
      }
      catch (e) {

         alert("Link is missing");
         var name = activeDocument.placedItems[i].name;
         if(name == inputFileName) {
             //Relink with input file path
            activeDocument.placedItems[i].relink(File(inputFilePath));

        }
     }
   }

}

 

placedItem.name is supposed to return image name right? this returns empty string

Any help is much appreciated!

 

TOPICS
Bug, How to, Scripting

Views

125

Likes

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

Find broken link name using placedItem name property

Community Beginner ,
Nov 06, 2020

Copy link to clipboard

Copied

Hello,

I'm trying to relink broken link with an input file path based on broken link name.

 

function updateLinks(inputFileName, inputFilePath)

{

   var activeDocument = app.activeDocument;

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

   {

       try {
          var file = activeDocument.placedItems[i].file;
           if (file && file.exists) {
             // Do nothing

          }
      }
      catch (e) {

         alert("Link is missing");
         var name = activeDocument.placedItems[i].name;
         if(name == inputFileName) {
             //Relink with input file path
            activeDocument.placedItems[i].relink(File(inputFilePath));

        }
     }
   }

}

 

placedItem.name is supposed to return image name right? this returns empty string

Any help is much appreciated!

 

TOPICS
Bug, How to, Scripting

Views

126

Likes

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
Nov 06, 2020 0
Engaged ,
Nov 06, 2020

Copy link to clipboard

Copied

No.  placedItem.name is the name of the placedItem, as it appears in the layers panel.  If it returns an empty string, it's because it's unnamed.  If you want the name of the image file, try this

 

var name1 = activeDocument.placedItems[i].file.name.replace(/\.[^\.]+$/, "");

 

Also, don't call your variable "name".  Call it name1, for example. 

Likes

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
Reply
Loading...
Nov 06, 2020 1
Community Beginner ,
Nov 06, 2020

Copy link to clipboard

Copied

for broken link placedItem.file doesn't exist, so unable to get image name using activeDocument.placedItems[i].file.name

Likes

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
Reply
Loading...
Nov 06, 2020 0
Contributor ,
Nov 07, 2020

Copy link to clipboard

Copied

Hi Janaki5FF1, I tried this out and yes you are right. I couldn't get the filepath when the link is broken. That's a huge shortcoming!

 

You can see the path in the XMP manifest, by choosing File > File Info menu item and clicking "Raw data". Scroll down to the <xmpMM:Manifest> element. Not pretty, but the path is there.

 

To work out how to edit it there, try looking at this question. Not sure if they got it to fully work though.

Likes

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
Reply
Loading...
Nov 07, 2020 0
Contributor ,
Nov 07, 2020

Copy link to clipboard

Copied

Ok, I've had a play with it myself and put together a script that *should* relink broken placed images.

 

It currently just looks for them in a folder specified by the user, but you could modify it for your particular case. For example, instead of providing a new path, you might prefer to use a regex replacement on the broken path to fix it. This is just to demonstrate the concepts. Most of the info I got from the question I linked to above.

 

Here's the script. Not tested much at all, so please let me know how you go.

 

 

// ask for path - script will look for broken link files here
var newPath = Folder.selectDialog();
if (newPath != null) {
    newPath = newPath.fullName + "/";

    // 1. get all the placedItems
    var items = app.activeDocument.placedItems;

    // 2. get the paths of all the placedItems
    if (ExternalObject.AdobeXMPScript == undefined) ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
    var xmp = new XMPMeta(app.activeDocument.XMPString);
    var paths = [];
    for (var i = 1; i <= xmp.countArrayItems(XMPConst.NS_XMP_MM, 'Manifest'); i++) {
        var xpath = 'xmpMM:Manifest[' + i + ']/stMfs:reference/stRef:filePath';
        paths.push(xmp.getProperty(XMPConst.NS_XMP_MM, xpath).value);
    }

    // 3. relink all the broken links
    var relinked = [], notFound = [];
    for (var i = 0; i < items.length; i++) {
        try {
            var triggerErrorIfBrokenLink = items[i].file;
        } catch (error) {
            var filename = paths[i].split('/').pop();
            var linkPath = newPath + filename;
            if (File(linkPath).exists) {
                items[i].file = new File(linkPath);
                relinked.push(filename);
            } else {
                notFound.push(filename);
            }
        }
    }

    // 4. report
    app.redraw();
    var report = relinked.length > 0 ? 'Relinked:\n' + relinked.join('\n') + '\n\n' : '';
    report += notFound.length > 0 ? 'Not found:\n' + notFound.join('\n') : '';
    alert(report);
}

 

 

(Aside: there must be a better way to handle a missing file property than I use here, ie. deliberately triggering an error, but I couldn't work it out in a hurry.)

 

Edit: I forgot to mention, this script relies on the fact that the placedItems are in the same order as the XMP manifest resources. I think it's a reasonable assumption, but if I'm wrong, the script will get the files mixed up! IMPORTANT: xmp data is only loaded when a file is opened, and isn't updated until it is again opened. So if you were to open your document, rearrange the placedItems in layer order, the script will get mixed up because the xmp data won't reflect the new order. In this case, save and close the document, then re-open, then run the script.

 

- Mark

Likes

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
Reply
Loading...
Nov 07, 2020 3
Community Beginner ,
Nov 09, 2020

Copy link to clipboard

Copied

Hi Mark,

Thank you for the details.

As you know images can be either linked or embedded in Illustrator.

I haven't found linked or embedded information in XMP. It would be nice to get filepath of only placedItems (linked images) from XMP.

I'm trying to update broken file path for images which are linked.

I have tried the following and this works:

function updateLinks(inFileName, inFilePath) {

  // 1. get the paths of all the linked or embedded images
  if (ExternalObject.AdobeXMPScript == undefined) 
    ExternalObject.AdobeXMPScript = new ExternalObject('lib:AdobeXMPScript');
  
  //Read xmp string - You can see document XMP in Illustrator -> File-> File Info -> Raw Data
  var xmp = new XMPMeta(app.activeDocument.XMPString);

  //Read file paths from XMP - this returns file paths of both embedded and linked images
  var xmpFilePaths = [];
  for (var i = 1; i <= xmp.countArrayItems(XMPConst.NS_XMP_MM, 'Manifest'); i++) {
    var xpath = 'xmpMM:Manifest[' + i + ']/stMfs:reference/stRef:filePath';
    xmpFilePaths.push(xmp.getProperty(XMPConst.NS_XMP_MM, xpath).value);
  }

  // 2. relink all the broken links
  //Assumption - order of file paths from XMP matches order of elements retrieved from active doc
  var artItems = app.activeDocument.pageItems;
  alert("number of page items = " + artItems.length);

  //Counter to keep track of linked (PlacedItem) and embedded (RasterItem) images
  var cnt = -1;

  //Loop through all the items on the artwork
  for(var i = 0; i < artItems.length; i++) {
    
    var artItem = artItems[i];
    var itemType = artItem.typename;
    alert("itemType = " + itemType);

    if("RasterItem" == itemType) {
      cnt++;
      continue;
    }
    else if("PlacedItem" == itemType) {
      cnt++;
      try {
        var triggerErrorIfBrokenLink = artItem.file;
      } catch (error) {

        //Get broken link file name from xmp
        //var filename = xmpFilePaths[cnt].split('/').pop();
        var filename = File(xmpFilePaths[cnt]).fsName;
        alert("xmp filename = " + filename);

        if(filename == inFileName) {
          artItem.relink(File(inFilePath));
        }
      }
    }
  }//end of for loop
}

 

Likes

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
Reply
Loading...
Nov 09, 2020 0
Contributor ,
Nov 10, 2020

Copy link to clipboard

Copied

Excellent work!

 

One question though... why don't you just get PlacedItems from the start? eg.

  var artItems = app.activeDocument.placedItems;

 Then you won't have to worry.

 

Mark

Likes

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
Reply
Loading...
Nov 10, 2020 0
Community Beginner ,
Nov 10, 2020

Copy link to clipboard

Copied

"stRef:filePath" from XMP gives list of all filepaths (includes both linked and embedded images)

var xpath = 'xmpMM:Manifest[' + i + ']/stMfs:reference/stRef:filePath';

 

whereas placedItems gives list of only linked items

var artItems = app.activeDocument.placedItems;

 

I need a way to map index of filepath retrieved from XMP with the item on active document.

Hence I'm checking for RasterItem (embedded) or PlacedItem (linked file)

 

To be more precise, for embedded items you can still see the image on artwork even if the filepath is missing (as embedded item is part of document).

But for linked items if the filepath is not found, when the document is opened, Illustrator pops up a message saying that some of the links are missing and you won't see the linked item (whose filepath is not found) on document. You won't get this warning for embedded items.

Illustrator Missing Link Warning.PNG

Hope this is clear.

Likes

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
Reply
Loading...
Nov 10, 2020 0
Contributor ,
Nov 10, 2020

Copy link to clipboard

Copied

Yes, very well explained, and taught me something. Thanks! Again, excellent work. 🙂

Likes

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
Reply
Loading...
Nov 10, 2020 0
Contributor ,
Nov 07, 2020

Copy link to clipboard

Copied

Hi femkeblanco, I would call the variable 'name' in the case you mention. I think its actually perfect. Why is it bad? - Mark

Likes

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
Reply
Loading...
Nov 07, 2020 0
Engaged ,
Nov 08, 2020

Copy link to clipboard

Copied

Labels like "name", "path", "selection", etc are application defined properties.  Redefining them can cause unexpected behaviour.  Using "path" caused me such a headache once, until I found out why. 

Likes

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
Reply
Loading...
Nov 08, 2020 1
Contributor ,
Nov 10, 2020

Copy link to clipboard

Copied

Oh, that's good to know.

Likes

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
Reply
Loading...
Nov 10, 2020 0
Community Beginner ,
Nov 17, 2020

Copy link to clipboard

Copied

How to get item Format property displayed in Links Panel?
Can we get this from app.activeDocument.pageItem?

For embedded items shown in Links panel, "typename" is "RasterItem"

For images placed using Illustrator->File->Place command, information like Format (ex: JPG(Embedded File)) is displayed in Links panel
When I select any item like Text from document and rasterize (using Illustrator->Object->Rasterize), the item is rasterized and displayed in Links panel. For these types of rasterized items, Format is NA(Embedded File)
I need to differentiate between Raster item whose Format is NA and other types like JPG, PNG etc.

LinkFormatProperty.png

Likes

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
Reply
Loading...
Nov 17, 2020 0
Contributor ,
Nov 18, 2020

Copy link to clipboard

Copied

I'm don't have a perfect answer. Could you try this:

 

Check if item has a file property (ie. item.file doesn't throw an error) and get the file suffix from the file name.

var item = app.activeDocument.pageItems[0];
var suffix = getItemFileSuffix(item);
if (suffix != undefined) {
    // now you know the file format is not N/A
    if (suffix == 'jpg') {
        //do something?
    }
}

function getItemFileSuffix(item) {
    var suffix;
    if (item.typename == 'PlacedItem' || item.typename == 'RasterItem') {
        try {
            suffix = examplePageItem.file.fullName.split('.').pop();
        } catch (error) { }
    }
    return suffix;
}

Likes

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
Reply
Loading...
Nov 18, 2020 0
Community Beginner ,
Nov 19, 2020

Copy link to clipboard

Copied

I have tried this.

Rasterized text doesn't have file property.
But in case of embedded image, if the file path seen in the links panel is not available on user's machine, then in this case too app.activeDocument.pageItems[0].file doesn't exist.

So I'm not able to differentiate between embedded image which has Format like JPG, PNG etc and rasterized text whose Format is NA as displayed in Links panel.

Likes

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
Reply
Loading...
Nov 19, 2020 0
m1b LATEST
Contributor ,
Nov 19, 2020

Copy link to clipboard

Copied

Just checking: you are also considering the path from the XMP manifest entry? (Sorry I don't have time to test right now, but I assume you have.)

Likes

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
Reply
Loading...
Nov 19, 2020 0
Resources