A scripted solution for getting file icons (Mac only)
Terry Judd
tsj at unimelb.edu.au
Mon Mar 16 05:42:21 EDT 2009
I really didn't think this was possible until I stumbled across the
AppleScript 'Image Events' dictionary a couple of days ago but here (below)
is a scripted solution for creating a PNG image of a file's icon based on
its filepath. It uses a couple of applescript snippets plus the revXML
external to parse application pList files but you could undoubtedly forgo
the XML external with a bit of extra scripting effort.
The getIconToFile_Mac function has 4 parameters...
# pSourceFilePath = path of the file you're getting the icon of
# pDestFilePath = path of the image file you're creating
# pIconSize = pixel dimensions of output image (e.g. 16 or 32 etc)
# pReturnImageData = true or false/empty - if true the image contents are
returned by the function
The routine works on files and applications (including application bundles)
and the output is a PNG image which retains transparent regions and is ready
to be sucked up into your project.
There doesn't seem to be any way to capture 'standard' volume and folder
icons (custom folder and volume images are possible) so I've left them out
for now.
I've included a couple of drag and drop handlers that you can place in an
image object to test the routines out.
Anyway, I hope this is useful to someone (it's a bit long and messy). Feel
free to improve or modify as you see fit.
-- ####################################################################
-- ## create an image and put the following 2 handlers in its script ##
-- ## watch out for line wraps ##
ON dragEnter
set the acceptdrop to true
END dragEnter
ON dragDrop
put dragData["files"] into tFile
IF tFile = "" THEN
put dragData["text"] into tFile
if tFile is not empty then
if not ((there is a folder tFile) and char -4 to -1 of tFile =
".app") then
exit dragDrop
end if
else
exit dragDrop
end if
end if
get getIconToFile_Mac(tFile,,128,true)
if it contains "error:" then
put "" into me
else
put it into me
end if
END dragDrop
-- ###############################################################
-- ## put the following 2 functions in the card or stack script ##
-- ## watch out for line wraps ##
FUNCTION getIconToFile_Mac pSourceFilePath, pDestFilePath, pIconSize,
pReturnImageData
local tIconFileName
-- default icon size is 32x32
if pIconSize is empty then put 32 into pIconSize
if (pDestFilePath is empty) and pReturnImageData then
-- use a temporary file
put specialFolderPath("temporary") &"/tempicon.png" into pDestFilePath
-- delete the file if it already exists
if there is a file pDestFilePath then delete file pDestFilePath
end if
set the itemdel to "/"
put item 1 to -2 of pSourceFilePath into tFolderPath
put urlencode(item -1 of pSourceFilePath) into tFileName
set the itemdel to "."
put item -1 of pSourceFilePath into tExtension
put the defaultfolder into tDF
set the defaultfolder to tFolderPath
put the detailed files into tFiles
set the defaultfolder to tDF
filter tFiles WITH (tFileName&"*")
set the itemdel to comma
put char 5 to 8 of last item of tFiles into tFIleType
if not (there is a file pSourceFilePath) then
-- invalid filepath or it's an application bundle
if there is a folder pSourceFilePath and tExtension = "app" then
-- the icns file should be in the resources folder inside the
bundle
delete char -4 to -1 of tFileName
put pSourceFilePath&"/Contents/Resources/"&tFileName&".icns" into
tSourceIconPath
if there is a file tSourceIconPath then
-- create the image
get
createFileFromIcon(tSourceIconPath,pDestFilePath,pIconSize,pReturnImageData)
return it
else
return "Error: couldn't locate icon file"
end if
else
return "Error: invalid input file path"
end if
end if
put revMacFromUnixPath(pSourceFilePath) into tPath
put "tell application 'System Events' to get the path of the default
application of file '[[tPath]]'" into tScript
put merge(tScript) into tScript
replace "'" WITH quote in tScript
do tScript as AppleScript
put the result into tAppPath
replace quote WITH empty in tAppPath
IF tAppPath = tPath THEN
-- it's an application (but not an application bundle)
put getResources(pSourceFilePath,"icns") into tResources
if tResources = "" then
return "Error: no icon available"
else
-- assume the correct icon is the first icns resource
put item 2 of line 1 of tResources into tResID
put getResource(pSourceFilePath,"icns",tResID) into tIcon
-- need to write this out to a temporary file
put specialFolderPath("temporary") &"/tempicon.icns" into tTempPath
-- delete the file if it already exists
if there is a file tTempPath then delete file tTempPath
put tIcon into url ("binfile:"&tTempPath)
get
createFileFromIcon(tTempPath,pDestFilePath,pIconSize,pReturnImageData)
return it
end if
END IF
put revUnixFromMacPath(tAppPath) into tAppPath
put url ("file:"&tAppPath&"/Contents/info.plist") into tXML
IF tXML is empty THEN return "Error: couldn't locate plist file"
IF not(tXML contains "CFBundleTypeIconFile") THEN
-- no icon files in plist (shouldn't happen)
return "Error: couldn't locate icon file"
END IF
-- create an xml tree from the plist file
put revCreateXMLTree(tXML,false,true,false) into tXMLID
-- try using the fileType to locate the icon file first
-- look in the first array node (follows the 'CFBundleDocumentTypes' key
element)
put "plist/dict/array" into tStartNode
if tXML contains "CFBundleTypeOSTypes" then
put revXMLNumberOfChildren(tXMLID,tStartNode,"dict",0) into nNodes
REPEAT WITH i = 1 to nNodes
put revXMLText(tXMLID,tStartNode&"/dict["&i&"]") into tNodeXML
replace "><" with ">"&cr&"<" in tNodeXML
if tNodeXML contains "<string>"&tFileType&"</string>" then
-- get the name of the icns file
filter tNodeXML with "*.icns*"
replace "<string>" with "" in tNodeXML
replace "</string>" with "" in tNodeXML
if tNodeXML is empty then
return "Error: couldn't locate icon file"
else
put tNodeXML into tIconFileName
put tAppPath&"Contents/Resources/"&tIconFileName into
tSourceIconPath
IF there is a file tSourceIconPath THEN
-- create the image
get
createFileFromIcon(tSourceIconPath,pDestFilePath,pIconSize,pReturnImageData)
return it
ELSE
return "Error: couldn't locate icon file"
END IF
end if
else
next repeat
end if
END repeat
end if
-- that hasn't worked so we'll try using the file extension
if tXML contains "CFBundleTypeExtensions" then
put revXMLNumberOfChildren(tXMLID,tStartNode,"dict",0) into nNodes
REPEAT WITH i = 1 to nNodes
put revXMLText(tXMLID,tStartNode&"/dict["&i&"]") into tNodeXML
replace "><" with ">"&cr&"<" in tNodeXML
if tNodeXML contains "<string>"&tExtension&"</string>" then
-- get the name of the icns file
filter tNodeXML with "*.icns*"
replace "<string>" with "" in tNodeXML
replace "</string>" with "" in tNodeXML
if tNodeXML is empty then
return "Error: couldn't locate icon file"
else
put tNodeXML into tIconFileName
put tAppPath&"Contents/Resources/"&tIconFileName into
tSourceIconPath
IF there is a file tSourceIconPath THEN
-- create the image
get
createFileFromIcon(tSourceIconPath,pDestFilePath,pIconSize,pReturnImageData)
return it
ELSE
return "Error: couldn't locate icon file"
END IF
end if
else
next repeat
end if
END repeat
END IF
-- that didn't work either so we'll see if there is any reference to an
icon file based on the extension
IF tXML contains (tExtension&".icns") THEN
put tAppPath&"Contents/Resources/"&tExtension&".icns" into
tSourceIconPath
IF there is a file tSourceIconPath THEN
-- create the image
get
createFileFromIcon(tSourceIconPath,pDestFilePath,pIconSize,pReturnImageData)
ELSE
return "Error: couldn't locate icon file"
END IF
ELSE
return "Error: couldn't locate icon file"
END IF
END getIconToFile_Mac
FUNCTION createFileFromIcon pSourceIconPath, pDestFilePath, pIconSize,
pReturnImageData
IF not (there is a file pDestFilePath) THEN
put empty into url ("file:"&pDestFilePath)
IF not (there is a file pDestFilePath) THEN
return "Error: couldn't create output file"
END IF
END IF
put revMacFromUnixPath(pSourceIconPath) into pSourceIconPath
put revMacFromUnixPath(pDestFilePath) into pDestFilePath
put "tell application 'Image Events'" &cr&\
"launch" &cr&\
"set theIcon to open file '[[pSourceIconPath]]'" &cr&\
"scale theIcon to size [[pIconSize]]" &cr&\
"save theIcon as PNG in file '[[pDestFilePath]]' without icon" &cr&\
"close theIcon" &cr&\
"end tell" into tScript
put merge(tScript) into tScript
replace "'" WITH quote in tScript
do tScript as AppleScript
put revUnixFromMacPath(pDestFilePath) into pDestFilePath
IF pReturnImageData THEN
IF there is a file pDestFilePath THEN
put url ("binfile:"&pDestFilePath) into tImageData
return tImageData
ELSE
return "Error: couldn't create output file"
END IF
ELSE
return the result
END IF
END createFileFromIcon
More information about the use-livecode
mailing list