A script to create Tahoe-looking icons from existing PNG or .icns files

Under Tahoe, the icons of all my AppleScript applets looked ugly, and I wanted to find a way to automate a process that would convert them to icons that look like the new-style Liquid Glass icons. As far as I understand these things, true Liquid Glass icons can only be created for apps built in Xcode, and I wanted standard .icns files that would at least look like Tahoe icons when used with my AppleScript applets. And I wanted to automate the process.

So here is an AppleScript app that converts an existing .icns file or a PNG file (256x256, 512x512, or 1024x1024) to an icon that looks like a Tahoe icon. By default it creates an icon with a light-colored background. If you add the string “dark” to the name of the script, it will instead create an icon with a dark background. If you add the string “both” to the name, it will create both styles.

The notarized, editable app is linked below. It contains (in its Helpers folder) two background images exported from the new Icon Composer. It requires the current BETA version of GraphicConverter12, because I can’t figure out how to use Apple’s built-in Image Tools to accomplish all its tasks. The code is clumsy and amateurish, but it seems to work. Any improvements will be welcome:

[https://mendelson.org/Resize%20Icon%20for%20Tahoe.zip]

1 Like

@emendelson
I’m not very good at English, so please forgive me if I misunderstand some parts of your post.

But since you’re not using Assets.car, I assume what you want is a sort of “Liquid Glass-❝like❞ ICNS” file, right?

Actually, it can be done using only the standard tools (you’ll need Xcode or Icon Composer.app, though).
The idea is to create an ICNS file with a Liquid Glass–❝like❞ appearance instead of the traditional icon look.

Steps
1:Create a folder named SOME.icon.
2:Inside it, create a subfolder named Assets.
3:Copy your SOME.png file into the Assets folder.
4:Create an icon.json file and place it inside SOME.icon. folder
5:Use Xcode’s built-in ictool (inside Icon Composer) to export the images.
6:From step 5, export images in the following sizes:824, 412, 206, 104, 52, 26, 14 pixels.
7:Add padding with sips, then resize to:1024, 512, 256, 128, 64, 32, 16 pixels.
8:Use iconutil to generate the final .icns file.

That’s it!

You can also use Icon Composer.app to generate the ICON file first, and then follow from step 5 onward to create the final ICNS file.

The ICON file package used by Icon Composer.app doesn’t involve any certificates, so you can freely add or remove files and edit the JSON as you like.

You can definitely do it this way.
Exporting the sizes with ictool, then using sips for padding and resizing might actually be the simplest workflow.
Give this method a try — it should work nicely! Just for reference:

Example
icon.json

{ "fill" : {"automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000" }, "groups" : [{ "layers" : [{ "image-name" : "SOME.png", "name" : "SOME"} ], "shadow" : {"kind" : "neutral","opacity" : 0.5 }, "translucency" : {"enabled" : true,"value" : 0.5 }} ], "supported-platforms" : {"circles" : [ "watchOS"],"squares" : "shared" }}

ictool
The PNG files exported from ictool don’t include any padding, so they won’t have the Liquid Glass–like appearance.
When you want to create a 1024-pixel icon image, don’t export it directly as 1024×1024 — the icon artwork is drawn about 100 px inside each edge,
1024-100-100 so you should export at 824×824 instead.

#72 ppi
"/Applications/Xcode.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool" "PATH_TO_ICON_FILE/SOME.icon" --export-preview macOS Default 824 824 1 -45 "PATH_TO_SAVE_DIR/icon_1024x1024.png"

#144 ppi
"/Applications/Xcode.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool" "PATH_TO_ICON_FILE/SOME.icon" --export-preview macOS Default 824 824 2 -45 "PATH_TO_SAVE_DIR/icon_512x512@2x.png"

#HELP
"/Applications/Xcode.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool" -h

ictool Options
“macOS Default”, “macOS Light”, “macOS Dark”, “macOS TintedLight”, “macOS TintedDark”, “macOS ClearLight”, “macOS ClearDark”

sips
By padding the 824-px image to 1024×1024, you’ll get that “Liquid Glass-❝like❞” outer transparency.

/usr/bin/sips --padToHeightWidth 1024 1024 "PATH_TO_SAVE_DIR/icon_1024x1024.png"

iconutil

Place the resized images (1024, 512, 256, 128, 64, 32, 16) into the SOME.iconset folder. (64 px may not be required.)

You can preview them with Quick Look. The PNG filenames inside the .iconset folder must follow this rule:
icon_x.png
icon_x@2x.png
Example: Pt Size
icon_1024x1024.png
icon_512x512@2x.png
Then, convert to ICNS:

/usr/bin/iconutil --convert icns "PATH_TO_ICONSET_DIR" -o "/Users/SOME/Desktop/SOME.icns"

Here’s what it looks like when you put the examples above together into a AppleScript.

LINK

@IceFole - Your English is very clear - thank you for this detailed report. I will try this when I next work on my icons. Would it be possible to make an AppleScript that would automate this?

@emendelson

Your English is very clear.

❝More than 90%❞ of it was actually translated from Japanese to English by OpenAI—haha. The bilingual comments in the script were also translated by OpenAI.

Starting from macOS 26 and later, app icons are basically managed as Assets.car files. The traditional ICNS format is now mainly used for backward compatibility, or when displaying icons in AppleScript dialogs and older macOS components.

For future macOS applications, I believe icon creation will generally start with Icon Composer.app, since it supports SVG and provides an excellent workflow.
It automatically handles scaling, allows grouping as layers, and you can configure resizing both globally and per group—it’s surprisingly well-designed. If you haven’t tried it yet, I really recommend giving Icon Composer a go.

The original version of my script was entirely in Japanese, so I’ve omitted the JSON-generation part for ICON files. What I’m posting here is the section that extracts the most tedious process— creating the .iconset folder and the required PNG files at each point size— from the original script.
My code is admittedly verbose, redundant, and my variable naming style has a bit of a bad reputation, but I hope it’s still helpful as a reference. I haven’t yet tested it thoroughly in an English macOS environment, so please let me know if it behaves differently there.

#!/usr/bin/env osascript
----+----1----+----2----+-----3----+----4----+----5----+----6----+----7
(*
ICON2ICNS.scpt
Icon Composer.appで作成したICONファイルから
旧環境用にICNSファイルを作成します

Creates an ICNS file for legacy environments
from an ICON file created with Icon Composer.app

保存先はピクチャーフォルダ
The save location is the Pictures folder
/Users/ショートユーザーID/Pictures/Icons/MakeIcon
/Users/USER_ID/Pictures/Icons/MakeIcon


1:Icon Composer.appで作成したICONファイルからictoolコマンドでPNGファイルを書き出し 
2:1のPNGファイルからiconsetに必要な各サイズのPNGをファイル命名規約で作成 
3:2で作ったiconsetフォルダを指定してiconutilコマンドでICNSファイルを作成 
4:書き出し先のフォルダを開く の順番で処理します

1: Export PNG files from ICON files created with Icon Composer.app using the ictool command
2: Generate all required PNG sizes for the .iconset folder based on naming conventions, using the PNGs from step 1
3: Create the ICNS file by specifying the .iconset folder in the iconutil command
4: Open the destination folder where the exported files are saved

License Notice
CC0 1.0 Universal (Public Domain Dedication).

20251016 15px icon size padd imagesize change 14px
20251020  change Apply HEIC rotation
20251025  I’ve added the license information.

com.cocolog-nifty.quicktimer.icefloe *)
----+----1----+----2----+-----3----+----4----+----5----+----6----+----7
use AppleScript version "2.8"
use framework "Foundation"
use framework "AppKit"
use framework "CoreImage"
#▼ここから下3つ不要かも?
use framework "CoreFoundation"
use framework "CoreGraphics"
use framework "ImageIO"
use scripting additions
property refMe : a reference to current application

set appShardWorkspace to refMe's NSWorkspace's sharedWorkspace()
set appFileManager to refMe's NSFileManager's defaultManager()

################## 
#設定項目(必須)
# Configuration (Required)
set strBinPath to ("/Applications/Xcode.app/Contents/Applications/Icon Composer.app/Contents/Executables/ictool") as text

################## 
#ICONファイル選択
# Select ICON file
set listUTI to {"com.apple.IconComposer.icon-document", "com.apple.iconcomposer.icon"} as list
#set strMes to ("Icon Composerで作成したICONファイルを選択してください") as text
set strMes to ("Choose an ICON file that was made with Icon Composer.") as text
tell application "SystemUIServer"
	activate
	set aliasIconFilePath to (choose file strMes with prompt strMes of type listUTI without invisibles, showing package contents and multiple selections allowed) as alias
end tell

################## 
#ICONファイルパス
#ICON FILE path
set strIconFilePath to (POSIX path of aliasIconFilePath) as text
set ocidIconFilePathStr to refMe's NSString's stringWithString:(strIconFilePath)
set ocidIconFilePath to ocidIconFilePathStr's stringByStandardizingPath()
set strIconFilePath to ocidIconFilePath as text
set ocidIconFilePathURL to refMe's NSURL's alloc()'s initFileURLWithPath:(ocidIconFilePath) isDirectory:(false)
set ocidIconFileName to ocidIconFilePathURL's lastPathComponent()
set ocidBaseFileName to ocidIconFileName's stringByDeletingPathExtension()

################## 
#保存先
#書き出しと出来上がりICNSの保存先PicturesDirectory
# Save location
# Export and save final ICNS to PicturesDirectory
set ocidURLsArray to (appFileManager's URLsForDirectory:(refMe's NSPicturesDirectory) inDomains:(refMe's NSUserDomainMask))
set ocidPicturesDirPathURL to ocidURLsArray's firstObject()
set strSetSubPath to ("Icons/MakeIcon/" & ocidBaseFileName & "") as text
set ocidSaveDirPathURL to ocidPicturesDirPathURL's URLByAppendingPathComponent:(strSetSubPath) isDirectory:(true)

#A:Exports ictoolからのPNG書き出し先
# A: Directory for PNG exports from ictool
set ocidExportsDirName to ocidBaseFileName's stringByAppendingString:("_Exports")
set ocidExportsDirPathURL to ocidSaveDirPathURL's URLByAppendingPathComponent:(ocidExportsDirName) isDirectory:(true)
set strExportsDirPath to ocidExportsDirPathURL's |path|() as text

#B:ICONSETフォルダの作成先
# B: Directory for ICONSET folder
set ocidIconSetName to ocidBaseFileName's stringByAppendingString:("_iconset")
set ocidIconSetDirPathURL to ocidSaveDirPathURL's URLByAppendingPathComponent:(ocidIconSetName) isDirectory:(true)
set strIconSetDirPath to ocidIconSetDirPathURL's |path|() as text

#AとBのフォルダを作っておく
# Create A and B folders
set ocidAttrDict to refMe's NSMutableDictionary's alloc()'s init()
#448=chmod 700
ocidAttrDict's setValue:(448) forKey:(refMe's NSFilePosixPermissions)
set listDone to appFileManager's createDirectoryAtURL:(ocidIconSetDirPathURL) withIntermediateDirectories:(true) attributes:(ocidAttrDict) |error|:(reference)
set listDone to appFileManager's createDirectoryAtURL:(ocidExportsDirPathURL) withIntermediateDirectories:(true) attributes:(ocidAttrDict) |error|:(reference)

################## 
#ICONファイルからPNG書き出し
#通常はmacOS Defaultだけで充分です
# Export PNG from ICON file
# Usually "macOS Default" is enough
set listOption to {"macOS Default"} as list

#フルセットで書き出す場合はこちら
# For full set export
set listOption to {"macOS Default", "macOS Light", "macOS TintedLight", "macOS TintedDark", "macOS ClearLight", "macOS ClearDark"} as list

#仕上がりPXサイズ
# Final pixel sizes
set listMaxPx to {"2048", "1024", "512", "256", "128", "64", "32", "16"} as list
#アイコンイメージのパディングされたサイズ=ictoolで書き出すサイズ
# Padded size for icon image = size exported with ictool
set listPaddPx to {"1648", "824", "412", "206", "104", "52", "26", "14"} as list

#NSDATA OPTION
set ocidOptionR to (refMe's NSDataReadingMappedIfSafe)
set ocidOptionW to (refMe's NSDataWritingAtomic)

#カラープロファイル付与 プロファイルはお好みで
# Apply color profile (optional)
set strColorFilePath to ("/System/Library/ColorSync/Profiles/Display P3.icc") as text
set ocidColorFilePathStr to (refMe's NSString's stringWithString:(strColorFilePath))
set ocidColorFilePath to ocidColorFilePathStr's stringByStandardizingPath()
set ocidColorFilePathURL to (refMe's NSURL's fileURLWithPath:(ocidColorFilePath) isDirectory:(false))
set listResponse to (refMe's NSData's alloc()'s initWithContentsOfURL:(ocidColorFilePathURL) options:(ocidOptionR) |error|:(reference))
set ocidColorProfileData to (first item of listResponse)


#PNG保存オプション
# PNG save options
set ocidPngPropertyDict to refMe's NSMutableDictionary's alloc()'s init()
(ocidPngPropertyDict's setObject:(refMe's NSNumber's numberWithBool:false) forKey:(refMe's NSImageInterlaced))
(ocidPngPropertyDict's setObject:(refMe's NSNumber's numberWithDouble:(1 / 2.2)) forKey:(refMe's NSImageGamma))
(ocidPngPropertyDict's setObject:(ocidColorProfileData) forKey:(refMe's NSImageColorSyncProfileData))
set ocidPngType to (refMe's NSBitmapImageFileTypePNG)

#CIImage FILL COLOR
set ocidSetColor to (refMe's CIColor's colorWithRed:(1) green:(1) blue:(1) alpha:(0))
set ocidFillColor to (refMe's CIImage's imageWithColor:(ocidSetColor))

################## 
#▼ictoolから画像書き出し ICNSファイル作成まで
# ▼ Export images from ictool and create ICNS
repeat with itemOption in listOption
	################## 
	#ICONからPNG書き出し 1024x1024@2x=2048pxサイズのみ書き出す
	# Export PNG from ICON: only 1024x1024@2x = 2048px
	set strExportsFilePatn to ("" & strExportsDirPath & "/" & itemOption & "1024x1024@2x.png")
	set strCmdText to ("/bin/zsh -c '\"" & strBinPath & "\" \"" & strIconFilePath & "\" --export-preview " & itemOption & " 1024 1024 2 -45 \"" & strExportsFilePatn & "\"'") as text
	do shell script strCmdText
	#書き出されるPNGファイルのパス
	# Path of exported PNG
	set ocidExportsFilePathStr to (refMe's NSString's stringWithString:(strExportsFilePatn))
	set ocidExportsFilePath to ocidExportsFilePathStr's stringByStandardizingPath()
	set ocidExportsFilePathURL to (refMe's NSURL's fileURLWithPath:(ocidExportsFilePath) isDirectory:(false))
	#アイコンセットのフォルダ名を定義してフォルダを作っておく
	# Define ICONSET folder name and create folder
	set strSubDirName to ("" & itemOption & ".iconset")
	set ocidconSetImageDirPathURL to (ocidIconSetDirPathURL's URLByAppendingPathComponent:(strSubDirName) isDirectory:(true))
	set listDone to (appFileManager's createDirectoryAtURL:(ocidconSetImageDirPathURL) withIntermediateDirectories:(true) attributes:(ocidAttrDict) |error|:(reference))
	################## 
	#NSDATA ictoolで書き出したPNG画像を読み込んで
	# Read PNG exported by ictool using NSData
	set listResponse to (refMe's NSData's alloc()'s initWithContentsOfURL:(ocidExportsFilePathURL) options:(ocidOptionR) |error|:(reference))
	set ocidReadData to (item 1 of listResponse)
	################## 
	#CIIMageに
	# Convert to CIImage
	set ocidReadCiImage to (refMe's CIImage's alloc()'s initWithData:(ocidReadData))
	#HEIC回転対応(必要ないけど)
	# HEIC rotation handling (not necessary here)
	set ocidMetaDataDict to ocidReadCiImage's |properties|()
	set ocidOrientation to (ocidMetaDataDict's objectForKey:(refMe's kCGImagePropertyOrientation))
	if ocidOrientation = (missing value) then
		#通常画像ですHEICではないので何もしない
		# Normal image, not HEIC, do nothing
	else
		#HEICの回転を適応させる
		# Apply HEIC rotation
		set recordAffine to (ocidReadCiImage's imageTransformForOrientation:(ocidOrientation))
		#20251020  change Apply HEIC rotation
		set ocidReadCiImage to (ocidReadCiImage's imageByApplyingTransform:(recordAffine))
	end if
	#Pxサイズを取得して
	# Get pixel size
	set ocidCGRect to ocidReadCiImage's extent()
	set numImageWidthPx to refMe's CGRectGetWidth(ocidCGRect) as number
	set numImageHeightPx to refMe's CGRectGetHeight(ocidCGRect) as number
	
	################## 
	#▼▼ICONSET用のPNG画像をサイズ毎に作成していく
	# ▼▼ Create PNG images for ICONSET for each size
	repeat with itemNo from 1 to 8 by 1
		#作成するICONサイズ
		# ICON size to create
		set numMaxPx to (item itemNo of listMaxPx) as integer
		#FILLのRECT
		# FILL RECT
		set ocidMakePoint to refMe's CGPoint's CGPointMake(0, 0)
		set ocidMakeSize to refMe's CGSize's CGSizeMake(numMaxPx, numMaxPx)
		set ocidMakeRect to refMe's CGRect's CGRectMake(0, 0, numMaxPx, numMaxPx)
		#新規イメージ作成
		# Create new image
		set ocidArtBord to (ocidFillColor's imageByCroppingToRect:(ocidMakeRect))
		#新規イメージサイズを指定サイズ合わせて縮小
		# Resize new image to specified size
		set numPaddPx to (item itemNo of listPaddPx)
		set numScale to (numPaddPx / numImageWidthPx) as number
		set numScallWpx to (numPaddPx) as integer
		set numScallHpx to (numPaddPx) as integer
		set numScallXpx to ((numMaxPx - numScallWpx) / 2) as integer
		set numScallYpx to ((numMaxPx - numScallHpx) / 2) as integer
		#Scale値で縮小して
		# Scale transformation
		set appScaleTransform to refMe's CGAffineTransformMakeScale(numScale, numScale)
		set ocidScaledImage to (ocidReadCiImage's imageByApplyingTransform:(appScaleTransform))
		#DRAWrectを定義
		# Define draw rect
		set ocidDrawPoint to refMe's CGPoint's CGPointMake(numScallXpx, numScallYpx)
		set ocidDrawSize to refMe's CGSize's CGSizeMake(numScallWpx, numScallHpx)
		set ocidDrawRect to refMe's CGRect's CGRectMake(numScallXpx, numScallYpx, numScallWpx, numScallHpx)
		#位置指定して
		# Position transformation
		set appTranslation to refMe's CGAffineTransformMakeTranslation(numScallXpx, numScallYpx)
		set ocidCIImage to (ocidScaledImage's imageByApplyingTransform:(appTranslation))
		#CompositingOverで縮小したICONファイルから書き出したPNGをペースト
		# CompositingOver to paste scaled PNG from ICON file
		set ocidSaveImage to (ocidCIImage's imageByCompositingOverImage:(ocidArtBord))
		
		################## 
		#NSBitmapImageRepに変換して
		# Convert to NSBitmapImageRep
		set ocidArtBoadRep to (refMe's NSBitmapImageRep's alloc()'s initWithCIImage:(ocidSaveImage))
		(ocidArtBoadRep's setProperty:(refMe's NSImageColorSyncProfileData) withValue:(ocidColorProfileData))
		
		################## 
		#解像度指定 72ppi
		# Set resolution to 72ppi
		(ocidArtBoadRep's setSize:(ocidMakeSize))
		set ocidPngData to (ocidArtBoadRep's representationUsingType:(ocidPngType) |properties|:(ocidPngPropertyDict))
		#ICONSET用の規定ファイル名で保存
		# Save using standard ICONSET file name
		set strSaveFileName to ("icon_" & numMaxPx & "x" & numMaxPx & ".png")
		set ocidSaveFilePathURL to (ocidconSetImageDirPathURL's URLByAppendingPathComponent:(strSaveFileName) isDirectory:(false))
		set listDone to (ocidPngData's writeToURL:(ocidSaveFilePathURL) options:(ocidOptionW) |error|:(reference))
		
		################## 
		#解像度指定 144ppi
		# Set resolution to 144ppi
		set ocidHiResSize to refMe's NSSize's NSMakeSize((numMaxPx / 2), (numMaxPx / 2))
		(ocidArtBoadRep's setSize:(ocidHiResSize))
		set ocidPngData to (ocidArtBoadRep's representationUsingType:(ocidPngType) |properties|:(ocidPngPropertyDict))
		#ICONSET用の規定ファイル名で保存
		# Save using standard ICONSET file name
		set numHiResPt to (numMaxPx / 2) as integer
		set strSaveFileName to ("icon_" & (numHiResPt as text) & "x" & (numHiResPt as text) & "@2x.png")
		set ocidSaveFilePathURL to (ocidconSetImageDirPathURL's URLByAppendingPathComponent:(strSaveFileName) isDirectory:(false))
		set listDone to (ocidPngData's writeToURL:(ocidSaveFilePathURL) options:(ocidOptionW) |error|:(reference))
	end repeat
	#▲▲ICONSETの処理の終わり
	# ▲▲ End of ICONSET processing
	################## 
end repeat
#▲画像別の繰り返しの終わり
# ▲ End of per-image repeat
################## 


################## 
#▼▼▼ICNSファイル生成
# ▼▼▼ Generate ICNS files
repeat with itemOption in listOption
	#ICNSに変換するICONSETのパスを定義して
	# Define ICONSET path to convert to ICNS
	set strSubDirName to ("" & itemOption & ".iconset")
	set ocidconSetImageDirPathURL to (ocidIconSetDirPathURL's URLByAppendingPathComponent:(strSubDirName) isDirectory:(true))
	set strconSetImageDirPath to ocidconSetImageDirPathURL's |path|() as text
	#ICNSファイルのパスを定義して
	# Define ICNS file path
	set strIcnsFileName to ("" & itemOption & ".icns") as text
	set ocidIcnsFilePathURL to (ocidIconSetDirPathURL's URLByAppendingPathComponent:(strIcnsFileName) isDirectory:(false))
	set strIcnsFilePath to ocidIcnsFilePathURL's |path|() as text
	#ICNSファイルを生成する
	# Generate ICNS file
	set strCmdText to ("/bin/zsh -c '/usr/bin/iconutil --convert icns  \"" & strconSetImageDirPath & "\"  -o  \"" & strIcnsFilePath & "\"'")
	do shell script strCmdText
end repeat
#▲▲▲ICNS作成終わり
# ▲▲▲ End of ICNS creation
################## 
#保存場所を開く
# Open save location
set boolDone to appShardWorkspace's openURL:(ocidSaveDirPathURL)
tell application "SystemUIServer" to quit

return 0

LINK

Thank you - that’s very impressive - and it works perfectly! Thank you for this amazing work.