How to change a folder icon ?

Wow, talk about quick service :slight_smile: Thanks so much.

I tried running the script and pointed it at the root folder of my music collection. it ran for a few seconds and then returned but nothing in the folder structure was changed.

am i running it correctly or is there something else i would need to do to get it to work correctly?

cheers,

phill

Hello

If you run the script on a folder containing subfolders containing jpeg files, the icon of the first jpeg file in a subfolder is given to this subfolder.

Isn’t it what was asked for ?

Yvan KOENIG (from FRANCE vendredi 10 novembre 2006 20:26:23)

Yvan,

A thousand apologies. I was running the script against a backup directory of my music which in fact didn’t have the album art in there either! Doh!

The scripts works perfectly.

Now to learn AppleScript…

Any recommendations for good websites as I am away travelling at the moment so getting books isn’t exactly feasible?

Cheers,

Phill

Just stick around here for a while. In my opinion this is the number 1 spot to learn appescript. Look at some peoples scripts at the macscripters section, and look at code people have posted here. I have learned almost all my techniques from here. Don’t forget to practice, practice practice! Do small little test exercises to learn different techniques, of doing things. Good luck:)

Hello

If you read French, you may look at:

http://didierdurandet.free.fr/applescript/

It offers a tutorial which give the basis.

Yvan KOENIG (from FRANCE samedi 11 novembre 2006 20:10:53)

But how can you apply the ditto command when moving an icon from a (source) folder to (destination) folder…?
(invisible icon resources)

Hello

Here is a new version using “osxutils”.

As this set of commands doesn’t work if one used pathname contains accented chars, I coded a workaround:
the folder containing the source file is moved into the Temporary Folder and renamed.
The iconize process is done then the folder is moved back to it’s original folder and it is renamed with its original name.
As is, the coded workaround assumes that the jpeg filename doesn’t contain accented and make the same assumption upon the boot volume.
It’s what I am working with :wink:

-- [SCRIPT iconizer]
(* uses osxutils 
with a workaround for accented chars

osxutils is available (free) from
http://osxutils.sourceforge.net/
*)

set _ to choose folder
open (_ as list)

on open (sel)
	local F, cl
	set F to (sel's item 1) as Unicode text
	tell application "Finder"
		if class of item F is document file then
			my saveImageWithItselfAsIcon(F as alias) (* I'm not sure that the file already has an icon *)
		else
			if ((class of item F) is folder) then my iconizeFolder(F)
		end if
	end tell
end open

on iconizeFolder(F)
	local ao, i, lesJPEGs, fichier
	tell application "Finder" to tell folder F
		set lesJPEGs to every item whose kind contains "jpeg"
		if lesJPEGs is not {} then
			set fichier to (lesJPEGs's item 1) as alias
			my saveImageWithItselfAsIcon(fichier) (* I'm not sure that the file already has an icon *)
			my copyIcon(fichier)
		end if
		repeat with i in (get folders)
			my iconizeFolder((i as alias))
		end repeat
	end tell -- to folder F then  to Finder
end iconizeFolder

on saveImageWithItselfAsIcon(F)
	tell application "Image Events"
		launch
		tell (open F)
			save with icon -- save icon_image_file with itself as icon 
			close
		end tell
	end tell
	tell application "Finder" to update F
end saveImageWithItselfAsIcon

on copyIcon(F) (* F is an alias *)
	local tName, F, coF, cocoF, nocoF, tempStorage, tempCof
	tell application "Finder"
		(* temporarily move and rename so the used pathname will not contain accented chars *)
		set coF to (container of F) as alias
		set {cocoF, nocoF, tName} to {(container of coF) as alias, name of coF, "osxutils_slituxso"}
		set tempStorage to (path to temporary items from user domain) as alias
		set coF to (move coF to tempStorage) as alias
		set name of coF to tName
	end tell -- to Finder 
	
	do shell script "/usr/local/bin/seticon " & quoted form of POSIX path of F & " " & quoted form of POSIX path of coF
	
	tell application "Finder"
		(* back to original storage and name *)
		set coF to (move coF to cocoF) as alias
		set name of coF to nocoF (* remet le vrai nom *)
		update coF
	end tell
	
end copyIcon

-- [/SCRIPT]

Yvan KOENIG (from FRANCE dimanche 12 novembre 2006 12:22:38)

hey

i applied the script using osxutils, but i get the error: sh: line 1: /usr/local/bin/seticon: No such file or directory

any idea

i first applied the first script, without the workaround, but not every folder containing an image jpg file got an icon

thx

Hello

SetIcon is a part of osxutils is available (free) from
http://osxutils.sourceforge.net/

You have to download it.
Then, install the Seticon file where it must be stored.

Yvan KOENIG

Thank you, installed it and no error anymore

beautiful applescript; was looking for this functionality in applescript, started writing my own but didn’t get very far due the lack of sufficient knowlegde

but i applied it to my music folder, in which every folder contains a jpg-file, but not every folder get an icon

i understand that the script takes the first jpg which the folder contains, but apparently there must be a difference somewhere

Edit: I found the difference, the jpg files contain special symbols like é and ü etc…

thx very much

Hello, this is a very old topic but I have just tried this script and it gives me an error

error “missing value doesn’t understand the “save” message.” number -1708 from missing value

on line

save with icon – save icon_image_file with itself as icon

Hoping someone can help as I am very new to AppleScript

Thanks,
Rob

Hi @rob71. Welcome to MacScripter.

It seems that the Image Events application in macOS no longer understands AppleScript’s ‘alias’ specifier, which is what’s passed to the saveImageWithItselfAsIcon(F) handler in Yvan’s script. The simplest fix seems to be to change this line in the handler:

tell (open F)

to:

tell (open (F as «class furl»))

This coerces the alias to a different kind of file specifier that Image Events does understand and can use to open the image file.

The script in the post to which you’ve replied depends on a third-part utility called “osxutils” which has to be downloaded and installed before it can be used. The URL for it in the script’s comments now appears to be dead, which isn’t totally surprising after 17 years! Google returns several hits for the name, but I haven’t checked any of them out to see if they’re the same utility and work with current versions of macOS. The other scripts in this thread don’t need it.

Hi Nigel, and thanks for your help! The script I was trying to use was the one Yvan posted before the one requiring osxutils. I have amended the line that was causing the error, but it is still not producing the intended result (i.e pointing at a folder, if an image is present then use that image as the folder icon, any subfolders containing their own image use this image for the folder icon, any subfolders without an image file use the image in the parent folder as their icon). It doesn’t actually change the icon to the image expected, it just creates an icon of a generic ‘‘jpeg’’ icon; and any subfolders are ignored. Sometimes it will complete without an error, but if pointing the script to a folder containing several subfolders it will produce a time-out error.
As I say I am just at the start of my journey with AppleScript so it is all beyond me at present, but grateful for any advice you can give (as from the comments it seemed to work on older versions of MacOS).

Hi rob71.

I’ve run the script right through with a test folder this morning and it turns out that there’s been a change in the Finder’s behaviour too which essentially renders Yvan’s ingenious workaround useless. :confused: Also, the script was never intended to change the icon for folders not containing an image file. Its modus operandi is:

  • Search the current folder for any image files — specifically JPEG ones.
  • If there are any:
    • Use Image Events to open the first one found and to resave it immediately with the image it contains as its icon. This still works once the ‘alias’ business is sorted out.
    • Open a Finder information window for the image file and copy the icon from it to the clipboard. This still works, BUT the icon shown in the information window is now the generic one for an image file, not the actual icon assigned to the file. Or I should say: in many cases, the icon’s a generic one. On both my Ventura and Sequoia machines, my testing so far has shown that only image file icons are genericised (if that’s a word) and only some image files are so affected. I’ve not so far been able to determine what sets affected and unaffected image files apart. It doesn’t seem to be related to size, age, colourisation, or dimensions.
    • Open a Finder information window for the current folder and paste the copied icon image into it. This sets the icon for the folder. (An invisible file whose name is (“Icon” & return) is saved in the folder.)
  • Recursively repeat the above with any subfolders, subfolders of subfolders, etc.

So I don’t know the answer at the moment. I’ll look into it further, and hopefully others will be inspired to do so too, but for now I’m stumped. :frowning:

1 Like

Hi peavine.

Yes. It seems to. When I apply your script to my test hierarchy, which contains one or two subfolders that don’t contain JPEG files, it complains that the folder is empty and only offers the option to stop. None of the folders’ icons are changed. It does work though with a folder containing a JPEG and no subfolders. And using ASObjC to handle the icons is definitely the way to go!

1 Like

Thanks Nigel for your explanation. I misunderstood the OP’s requirements, confusing the folder selected by the user with the parent folder. This raises the question as to what should happen if a subfolder does not have a JPG and that subfolder’s parent folder does not have a JPG. Do you just keep going up the path until you find a JPG?

1 Like

Hi peavine.

As I understand it from rob72’s description above (I expect he’ll clarify it himself later), he wants every folder in the chosen hierarchy that contains a JPEG file to have an icon that’s the same picture as the one in that file. If a folder doesn’t contain a JPEG file, he wants that folder to have the same icon as the one given to the chosen root folder. Yvan’s scripts do something similar except that folders not containing JPEGS aren’t given new icons. It may be a good idea to wait for rob72 to confirm what he wants before getting too deeply into the code development! I won’t be able to do anything about it myself for the next day or so, so I’ll leave it to your expertise with NSIcon methods!

2 Likes

Hi Nigel, that is exactly what I’m hoping to achieve, thank you. In the case that a subfolder does not have an image file (it could be a jpg or a png) my goal is that the subfolder inherits the same icon image as its parent folder.

Thanks Nigel. I’ve included below a script that works in the above fashion. Please note that the user is notified of an error and the script stops if the chosen root folder does not contain a JPG file. I tested this script on my Sequoia computer without issue.

--revised 2025.01.22

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	set allowedSubfolders to 10 --set to desired value
	set theFolder to POSIX path of (choose folder)
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set folderImage to getImage(theFolder)
	if (folderImage's |count|()) is 0 then display dialog "This script cannot proceed because an image file was not found in the chosen root folder." buttons {"OK"} cancel button 1 default button 1
	set folderImage to folderImage's objectAtIndex:0
	set theSubfolders to getSubfolders(theFolder)
	set subfolderCount to theSubfolders's |count|()
	if subfolderCount is greater than allowedSubfolders then display dialog "This script cannot proceed because the chosen root folder contains " & subfolderCount & " subfolders, which exceeds the allowed number of subfolders." buttons {"OK"} cancel button 1 default button 1
	display dialog "The chosen root folder contains " & subfolderCount & " subfolders. Do you want to change the icon of the chosen root folder and all of its subfolders? An existing Finder window may have to be closed and reopened to see the changed icons." cancel button 1 default button 1
	set folderImage to (current application's NSImage's alloc()'s initWithContentsOfURL:folderImage)
	(current application's NSWorkspace's sharedWorkspace()'s setIcon:folderImage forFile:(theFolder's |path|()) options:2) --option 2 suppresses QuickDraw format icons
	repeat with aSubfolder in theSubfolders
		set subfolderImage to getImage(aSubfolder)
		if (subfolderImage's |count|()) is 0 then --image file not found in subfolder
			set subfolderImage to folderImage
		else
			set subfolderImage to (current application's NSImage's alloc()'s initWithContentsOfURL:(subfolderImage's objectAtIndex:0))
		end if
		(current application's NSWorkspace's sharedWorkspace()'s setIcon:subfolderImage forFile:(aSubfolder's |path|()) options:2)
	end repeat
end main

on getSubfolders(theFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set folderKey to current application's NSURLIsDirectoryKey
	set packageKey to current application's NSURLIsPackageKey
	set booleanTrue to current application's NSNumber's numberWithBool:true
	set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:6 errorHandler:(missing value))'s allObjects() --option 6 skips hidden files and package descendants
	set theSubfolders to current application's NSMutableArray's new()
	repeat with anItem in folderContents
		set {theResult, aFolder} to (anItem's getResourceValue:(reference) forKey:folderKey |error|:(missing value))
		if aFolder is booleanTrue then
			set {theResult, aPackage} to (anItem's getResourceValue:(reference) forKey:packageKey |error|:(missing value))
			if aPackage is not booleanTrue then (theSubfolders's addObject:anItem)
		end if
	end repeat
	return theSubfolders
end getSubfolders

on getImage(theFolder)
	set fileManager to current application's NSFileManager's defaultManager()
	set folderContents to fileManager's contentsOfDirectoryAtURL:(theFolder) includingPropertiesForKeys:{} options:4 |error|:(missing value) --option 4 skips hidden files
	set thePredicate to current application's NSPredicate's predicateWithFormat_("pathExtension.lowercaseString IN %@", {"jpg", "jpeg", "png"}) --set desired image formats which are case-insensitive
	return (folderContents's filteredArrayUsingPredicate:thePredicate)
end getImage

main()
2 Likes

It works well on both my Sequoia and Ventura machines. :sunglasses:

1 Like