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!
1 Correct answer
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 == 'Raste
...
Explore related tutorials & articles
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.
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
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.
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
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
}
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
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.
Hope this is clear.
Copy link to clipboard
Copied
Yes, very well explained, and taught me something. Thanks! Again, excellent work. 🙂
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
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.
Copy link to clipboard
Copied
Oh, that's good to know.
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.
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;
}
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.
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.)

