Creating A Proper ICNS Icon File From An Image

Sometimes it’s nice to override the default icons for various folders and drives on your Mac. Fortunately, the Mac makes it trivial to do this, as you can just drag an image into the icon in the “Get Info” window of a file in the Finder. I used to just do that with empty folders to keep a copy of the icon, but sometimes in moving said folder around, the icon gets lost, which is frustrating when you had that perfect icon.

Apple does provide the tools you need to generate an icns file that contains all the icon data in a form that will not get lost. There is also a command line utility you can use to create scaled images.

I put the two together into a script that will take an image and properly scale it:

#!/bin/bash

trap 'rm -rf /tmp/*.$$ *.$$ *.$$.* icon.$$.iconset; exit 0' 0 1 2 3 13 15

# This script will take an image (it should be square, and at least 512x512),
# and works best if it has a transparency lable.  PNG is the best format.
# It will create images of all the appropriate sizes, then create an icns file that
# can be used for whatever icons you want.

# Grab the name of the file.  It accepts 1 argument.  Everything else
# will be ignored.

input_file="$1"

# Figure out the extension of the file, and remove it from the variable.
ext="$( echo "${input_file}" | awk -F'.' '{ print $NF; }' )"

if [ "${ext}" != "png" ]
then
	echo "This tool requires a PNG file (extension .png)."
	exit 1
fi

output="$( basename "${input_file}" ".${ext}" )"

pixelHeight=$( sips -g pixelHeight "${input_file}" | awk '{ print $2; }' )
pixelWidth=$( sips -g pixelWidth "${input_file}" | awk '{ print $2; }' )

if [ ${pixelHeight} -lt 1024 ] -o [ pixelWidth -lt 1024 ]
then
	echo "Warning: Image should have at least one dimension >= 1024."
fi

hasAlpha=$( sips -g hasAlpha "${input_file}" | awk '{ print $2; }' )

if [ "${hasAlpha}" != "yes" ]
then
	echo "Warning: Icons work best if the image has a transparency layer."
fi

# Scale the input to 1024x1024, padding as necessary to make it
# square without changing the aspect ratio.
sips -Z 1024 -p 1024 1024 "${input_file}" -o "${output}.$$.png"
input_file="${output}.$$.png"

# Create a temp folder for all the required icon sizes, and then
# generate images at the appropriate sizes as defined by Apple:
# https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/app-icon/

mkdir -p "icon.$$.iconset"
sips -z 16 16     "${input_file}" --out "icon.$$.iconset/icon_16x16.png"
sips -z 32 32     "${input_file}" --out "icon.$$.iconset/icon_16x16@2x.png"
sips -z 32 32     "${input_file}" --out "icon.$$.iconset/icon_32x32.png"
sips -z 64 64     "${input_file}" --out "icon.$$.iconset/icon_32x32@2x.png"
sips -z 128 128   "${input_file}" --out "icon.$$.iconset/icon_128x128.png"
sips -z 256 256   "${input_file}" --out "icon.$$.iconset/icon_128x128@2x.png"
sips -z 256 256   "${input_file}" --out "icon.$$.iconset/icon_256x256.png"
sips -z 512 512   "${input_file}" --out "icon.$$.iconset/icon_256x256@2x.png"
sips -z 512 512   "${input_file}" --out "icon.$$.iconset/icon_512x512.png"
sips -z 1024 1024 "${input_file}" --out "icon.$$.iconset/icon_512x512@2x.png"

# Merge all of them into an icns file, with the same name as the input file.
iconutil -c icns "icon.$$.iconset" -o "${output}.icns"

Leave a Comment