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