Illustrator CS3 List Missing Links

Problem:

I want to get a list of missing files in an Illustrator file. The following code finds the links that are present but has a missing value in the “file path:file” part of the record returned. Note that the 1st one is missing its link and the second one is found.
Where or how do I get the name of the link that is missing?

Note: The finished code that answered this question is posted at the 3rd post. Any improvements would be greatly accepted.


tell application "Adobe Illustrator"
	
	repeat with r from (number of placed items in current document) to 1 by -1
		get properties of placed item r of document 1
	end repeat
	
end tell

Dictionary:
placed item‚n [inh. page item] : Every placed artwork item
elements
contained by documents, group items, layers.
properties
properties (record) : all of this object’s properties returned in a single record
bounding box (list, r/o) : dimensions of placed art object, regardless of transformations
content variable (anything) : the content variable bound to this placed art object
file path (file specification) : the file containing the placed artwork
matrix (matrix) : The transformation matrix of the placed art object

Results of above script

tell application “Adobe Illustrator”
count every placed item of current document
5
get properties of placed item 5 of document 1
{file path:missing value, matrix:{class:matrix, mvalue_a:0.51823502779, mvalue_b:0.0, mvalue_c:0.0, mvalue_d:-0.51823502779, mvalue_tx:-4027.209228515625, mvalue_ty:4919.87744140625}, bounding box:{7795.0, 8498.0, 7919.875, 8333.75}, content variable:missing value, URL:“”, note:“”, layer:layer 1 of document 1, locked:false, hidden:false, selected:false, position:{12.4326171875, 601.0361328125}, width:64.71484375, height:85.1201171875, geometric bounds:{12.4326171875, 601.0361328125, 77.1474609375, 515.916015625}, visible bounds:{12.4326171875, 601.0361328125, 77.1474609375, 515.916015625}, control bounds:{12.4326171875, 601.0361328125, 77.1474609375, 515.916015625}, name:“”, blend mode:normal, opacity:100.0, isolated:false, knockout:disabled, editable:true, sliced:false, visibility variable:missing value, wrapped:false, wrap offset:missing value, wrap inside:missing value, container:layer 1 of document 1, best type:reference, default type:reference, class:placed item, index:5}
get properties of placed item 4 of document 1
{file path:file “CUSTOMER UPLOADS:InternationalBreak122007174312:IndriGautama.tif”, matrix:{class:matrix, mvalue_a:0.819576919079, mvalue_b:0.0, mvalue_c:0.0, mvalue_d:-0.819576919079, mvalue_tx:-6376.18896484375, mvalue_ty:7355.943359375}, bounding box:{7795.0, 8592.3203125, 7872.0400390625, 8498.0}, content variable:missing value, URL:“”, note:“”, layer:layer 1 of document 1, locked:false, hidden:false, selected:false, position:{12.4130859375, 391.1787109375}, width:63.14013671875, height:77.302764892578, geometric bounds:{12.4130859375, 391.1787109375, 75.55322265625, 313.875946044922}, visible bounds:{12.4130859375, 391.1787109375, 75.55322265625, 313.875946044922}, control bounds:{12.4130859375, 391.1787109375, 75.55322265625, 313.875946044922}, name:“”, blend mode:normal, opacity:100.0, isolated:false, knockout:disabled, editable:true, sliced:false, visibility variable:missing value, wrapped:false, wrap offset:missing value, wrap inside:missing value, container:layer 1 of document 1, best type:reference, default type:reference, class:placed item, index:4}
get properties of placed item 3 of document 1


The other 3 results deleted for brevity

end tell

File contents if AI file is opened in Text Edit:

Partial contents:

xapMM:Manifest
rdf:Seq
<rdf:li rdf:parseType=“Resource”>
stMfs:linkFormEmbedByReference</stMfs:linkForm>
<stMfs:reference rdf:parseType=“Resource”>
<stRef:filePath>/Users/stephanienorton/Desktop/IBM/AWA 08/LeeNEWcloseup2007.tif</stRef:filePath>
stRef:instanceIDuuid:1A58E052AD5911DC87BEF94D8226B11E</stRef:instanceID>
stRef:documentIDuuid:0C353C26A8E711DCB9F5E57E6773AD82</stRef:documentID>
</stMfs:reference>
</rdf:li>
<rdf:li rdf:parseType=“Resource”>
stMfs:linkFormEmbedByReference</stMfs:linkForm>
<stMfs:reference rdf:parseType=“Resource”>
stRef:[b]filePath/Users/stephanienorton/Desktop/IBM/AWA 08/Cindy1.tif[/b]</stRef:filePath>
stRef:instanceIDuuid:0478AA3BA72711DCA3D49B92A22D0417</stRef:instanceID>
stRef:documentIDuuid:0478AA37A72711DCA3D49B92A22D0417</stRef:documentID>
</stMfs:reference>
</rdf:li>
<rdf:li rdf:parseType=“Resource”>
stMfs:linkFormEmbedByReference</stMfs:linkForm>
<stMfs:reference rdf:parseType=“Resource”>
stRef:[b]filePath/Users/stephanienorton/Desktop/IBM/AWA 08/PND_119_green bg.tif[/b]</stRef:filePath>
stRef:instanceIDuuid:75cabfa1-920e-11d9-8b11-bbf652566e9e</stRef:instanceID>
stRef:documentIDadobe:docid:photoshop:75cabfa0-920e-11d9-8b11-bbf652566e9e</stRef:documentID>
</stMfs:reference>
</rdf:li>
<rdf:li rdf:parseType=“Resource”>
stMfs:linkFormEmbedByReference</stMfs:linkForm>
<stMfs:reference rdf:parseType=“Resource”>
stRef:[b]filePath/Volumes/CUSTOMER UPLOADS/InternationalBreak122007174312/IndriGautama.tif[/b]</stRef:filePath>
stRef:instanceIDuuid:5b4a0d01-920e-11d9-8b11-bbf652566e9e</stRef:instanceID>
stRef:documentIDadobe:docid:photoshop:5b4a0d00-920e-11d9-8b11-bbf652566e9e</stRef:documentID>
</stMfs:reference>
</rdf:li>
<rdf:li rdf:parseType=“Resource”>
stMfs:linkFormEmbedByReference</stMfs:linkForm>
<stMfs:reference rdf:parseType=“Resource”>
stRef:[b]filePath/Users/stephanienorton/Desktop/IBM/AWA 08/Barb.NewHeadcropped.tif[/b]</stRef:filePath>
stRef:instanceIDuuid:65f96f0e-920e-11d9-8b11-bbf652566e9e</stRef:instanceID>
stRef:documentIDadobe:docid:photoshop:65f96f0d-920e-11d9-8b11-bbf652566e9e</stRef:documentID>
</stMfs:reference>

I suppose I could read the AI file and pull out the stRef?

Anyone have any ideas?

Update:

Illustrator can get the file’s XMP string. I can get the stRef from that.

OK, here is the final code and output:

Note, if anyone knows how to clean up the extra colons in the numbered output below, please share.

Output sample:

Document Name:
JobVol:Fileserver:Toms RB:CheckOut RB:RichV:untitled folder:AWA12008.eps

Number of links found: 6

Current Links in Document:
1:: :CUSTOMER UPLOADS:InternationalBreak122007174312:IndriGautama.tif:
:2:: :JobVol:Fileserver:ACTIVE JOBS BABY:42228 Catalog:ART:_019_RT8.tif:

Links supposed to be in doc:
1:: :stephanie:Desktop:IBM:AWA:08:LeeNEWcloseup2007:tif:
:2:: :stephanie:Desktop:IBM:AWA:08:Cindy1:tif:
:3:: :stephanie:Desktop:IBM:AWA:08:PND_119_green:bg:tif:
:4:: :CUSTOMER:UPLOADS:InternationalBreak122007174312:IndriGautama:tif:
:5:: :stephanien:Desktop:IBM:AWA:08:Barb:NewHeadcropped:tif:

Note: I suppose I should compare both lists and just report the last line as Missing Links:

CODE:

--get properties of placed items.app
(* Gets list of missing links in an Illustrator doc *)

(*Copywrite 2007, Thomas Lotzer. tlotzerDELETE_THIS_TEXT@usseryprinting.com
*)

property debugMode_Main : false -- turns on/off debug mode. true/false switch
property debugMode_Handler_PullOutLinkedFilenames : false -- turns on/off debug mode. true/false switch
property debugMode_Handler_TextEditReport : false -- turns on/off debug mode. true/false switch



-- VARIABLE DEFINITIONS:
(*
	Documentname = Name of current Illustrator document
	FilePath = Path to current Illustrator document
	XMPStringData = The image data for the current Illustrator document
	NumberPlaceditems = the number of placed images
	ListOfLinks = List of links inside the XMP string returned by Handler_PullOutLinkedFilenames
	CurrentLinks = List to hold current links found in current Illustrator document
	FoundLink = A link the was found in current Illustrator document
	VARIABLENAME = DESCRIPTION
	
===  HANDLER DEFINITIONS ======
	Handler_PullOutLinkedFilenames = Handler to extract file info from XMP string 
	Handler_TextEditReport = opens report in TextEdit
	VARIABLENAME = DESCRIPTION
*)

tell application "Adobe Illustrator"
	set Documentname to (get name of current document)
	set FilePath to (get file path of current document)
	set NumberPlaceditems to (number of placed items in current document)
	set XMPStringData to (get XMP string of current document)
	set CurrentLinks to {}
	
	repeat with r from NumberPlaceditems to 1 by -1
		try
			set FoundLink to (get file path of placed item r of document 1)
			set CurrentLinks to CurrentLinks & FoundLink -- appends found link to list
		end try
	end repeat
	if debugMode_Main then display dialog "CurrentLinks: " & CurrentLinks buttons {"Cancel", "Continue"} default button 2
	
	
	set ListOfLinks to my Handler_PullOutLinkedFilenames(XMPStringData, NumberPlaceditems)
	my Handler_TextEditReport(FilePath, CurrentLinks, ListOfLinks, NumberPlaceditems)
end tell



on Handler_PullOutLinkedFilenames(DataString, CountPlacedItems)
	-- VARIABLE DEFINITIONS:
	(*
	DataString = XMP string data read from AI file
	LinkList = List of all matches to stRef:filePath in AI file XMP  string data
	CountPlacedItems = Number of placed links in AI file
	ItemCount = All text items
	WordCount = All words
	ParagraphCount = All Paragraphs
	VARIABLENAME = DESCRIPTION
*)
	
	set LinkList to {}
	set ItemCount to (count items of DataString)
	if debugMode_Handler_PullOutLinkedFilenames then display dialog "ItemCount of XMP String: " & ItemCount buttons {"Cancel", "Continue"} default button 2
	
	set WordCount to (count words of DataString)
	if debugMode_Handler_PullOutLinkedFilenames then display dialog "WordCount of XMP String: " & WordCount buttons {"Cancel", "Continue"} default button 2
	
	set ParagraphCount to (count paragraphs of DataString)
	if debugMode_Handler_PullOutLinkedFilenames then display dialog "ParagraphCount of XMP String: " & ParagraphCount buttons {"Cancel", "Continue"} default button 2
	
	repeat with i from 1 to ParagraphCount
		set ParagraphToRead to (paragraph i of DataString)
		if debugMode_Handler_PullOutLinkedFilenames then display dialog "ParagraphToRead: " & return & ParagraphToRead & return & "ParagraphCount: " & i buttons {"Cancel", "Continue"} default button 2
		
		if ParagraphToRead contains "<stRef:filePath>" then
			set FileLink to (words 5 thru -4 of ParagraphToRead) as string -- Pulls out filename from tags and sets a string
			-- Without "as string" we get words broken up by the colon like this {"stephanienorton", "Desktop", "IBM", "AWA", "08", "LeeNEWcloseup2007", "tif") 
			-- With the "as string" we get: ({"stephanienorton:Desktop:IBM:AWA:08:LeeNEWcloseup2007:tif"}*)
			set LinkList to LinkList & FileLink
			if debugMode_Handler_PullOutLinkedFilenames then display dialog "LinkList: " & LinkList buttons {"Cancel", "Continue"} default button 2
			
		end if
		
	end repeat
	
	return LinkList
	
end Handler_PullOutLinkedFilenames

on Handler_TextEditReport(H_FilePath, H_CurrentLinks, H_ListOfLinks, H_NumberPlaceditems)
	-- VARIABLE DEFINITIONS:
	(*
	H_FilePath = File path to current doc
	H_CurrentLinks = name of all links in doc
	H_ListOfLinks = List of links pulled from XMP data
	H_NumberPlaceditems = Number of links in doc
	CountCurrentLinks = Count of current links
	CurrentLinkList = formated list of H_CurrentLinks
	FormattedLinkOfLists = formatted form of H_ListOfLinks
	VARIABLENAME = DESCRIPTION
*)
	set CountCurrentLinks to (count H_CurrentLinks)
	set CurrentLinkList to {}
	repeat with i from 1 to CountCurrentLinks
		set CurrentLinkList to CurrentLinkList & i & ": " & (item i of H_CurrentLinks) & return
	end repeat
	if debugMode_Handler_TextEditReport then display dialog "CountCurrentLinks: " & CountCurrentLinks buttons {"Cancel", "Continue"} default button 2
	set FormattedLinkOfLists to {}
	repeat with j from 1 to (count H_ListOfLinks)
		set FormattedLinkOfLists to FormattedLinkOfLists & j & ": " & (item j of H_ListOfLinks) & return
	end repeat
	set TextEditReport to "Document Name: " & return & H_FilePath & return & return & "Number of links found: " & H_NumberPlaceditems & return & return & "Current Links in Document:" & return & CurrentLinkList & return & return & "Links supposed to be in doc: " & return & FormattedLinkOfLists
	tell application "TextEdit"
		activate
		make new document with properties {text:TextEditReport}
	end tell
	
end Handler_TextEditReport


I just tested the script on an AI file, freshly opened where it reported that many images were missing. I told it to ignore all. When I ran the script, I got blanks for the "Links supposed to be in doc: " part. I had to save the file as eps and click the “include images”. That part must be where the XMP data is written to the file. After I did that, it worked correctly. Also notice that the extra colon problem is gone. Not sure how that happened. Looking closer, it looks like too many colons are gone. You can’t tell where folders begin and end.

Running script right after opening the AI file:
Document Name:
JobVol:Fileserver:Toms RB:CheckOut RB:RichV:untitled folder:AWA12008.ai

Number of links found: 5

Current Links in Document:
1: CUSTOMER UPLOADS:InternationalBreak122007174312:IndriGautama.tif

Links supposed to be in doc:

After resaving as AI or EPS, including images/links:

Document Name:
JobVol:Fileserver:Toms RB:CheckOut RB:RichV:untitled folder:AWA12008b.ai

Number of links found: 5

Current Links in Document:
1: CUSTOMER UPLOADS:InternationalBreak122007174312:IndriGautama.tif

Links supposed to be in doc:
1: stephanieDesktopIBMAWA08LeeNEWcloseup2007tif
2: stephanieDesktopIBMAWA08Cindy1tif
3: stephanieDesktopIBMAWA08PND_119_greenbgtif
4: CUSTOMERUPLOADSInternationalBreak122007174312IndriGautamatif
5: stephanienDesktopIBMAWA08BarbNewHeadcroppedtif