-
-
Save Qix-/f4090181e55ea365633da8c3d0ab5249 to your computer and use it in GitHub Desktop.
# LICENSE: CC0 - go nuts. | |
# Hi :) This is what I used to generate the ICNS for my game, Tide. | |
# Both input formats (SVG vs PNG) work just fine, but in my experience | |
# the SVG came out with noticeably better results (although PNG wasn't | |
# a catastrophe either). The logo for the game was simple enough that | |
# SVG was indeed an option. | |
# To use: | |
# | |
# make_icns( INPUT "path/to/img.{svg,png}" | |
# OUTPUT ICNS_PATH ) | |
# | |
# Then add it as a custom target or use it as a | |
# dependency somewhere - I give you that option. | |
# | |
# For example: | |
# | |
# add_custom_target( my-icns ALL DEPENDS "${ICNS_PATH}" ) | |
# | |
# For the associated utilities: | |
# | |
# - PNG: brew install imagemagick | |
# - SVG: brew cask install inkscape | |
# | |
# Enjoy! | |
function (make_icns_from_png) | |
cmake_parse_arguments ( | |
ARG | |
"" # Boolean args | |
"INPUT;OUTPUT" # List of single-value args | |
"" # Multi-valued args | |
${ARGN}) | |
find_program ( | |
convert_exe | |
NAMES "convert" "convert.exe" | |
DOC "Path to ImageMagick convert") | |
if (NOT convert_exe) | |
message (FATAL_ERROR "Could not find ImageMagick's 'convert' - is ImageMagick installed?") | |
endif () | |
get_filename_component (ARG_INPUT_ABS "${ARG_INPUT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") | |
get_filename_component (ARG_INPUT_ABS_BIN "${ARG_INPUT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") | |
get_filename_component (ARG_INPUT_FN "${ARG_INPUT_ABS_BIN}" NAME_WE) | |
get_filename_component (ARG_INPUT_DIR "${ARG_INPUT_ABS_BIN}" DIRECTORY) | |
set (sourceimg "${ARG_INPUT_ABS}") | |
set (basepath "${ARG_INPUT_DIR}/${ARG_INPUT_FN}") | |
set (output_icns "${basepath}.icns") | |
set (iconset "${basepath}.iconset") | |
set (deplist "") | |
foreach (size IN ITEMS 16 32 128 256 512) | |
math (EXPR size2x "2 * ${size}") | |
set (ipath "${iconset}/icon_${size}x${size}.png") | |
set (ipath2x "${iconset}/icon_${size}x${size}@2x.png") | |
list (APPEND deplist "${ipath}" "${ipath2x}") | |
add_custom_command ( | |
OUTPUT "${ipath}" | |
COMMAND "${convert_exe}" ARGS "${sourceimg}" -resize "${size}x${size}" "${ipath}" | |
MAIN_DEPENDENCY "${sourceimg}" | |
COMMENT "ICNS resize: ${ipath}" | |
VERBATIM) | |
add_custom_command ( | |
OUTPUT "${ipath2x}" | |
COMMAND "${convert_exe}" ARGS "${sourceimg}" -resize "${size2x}x${size2x}" "${ipath2x}" | |
MAIN_DEPENDENCY "${sourceimg}" | |
COMMENT "ICNS resize: ${ipath2x}" | |
VERBATIM) | |
endforeach () | |
add_custom_command ( | |
OUTPUT "${output_icns}" | |
COMMAND iconutil ARGS --convert icns --output "${output_icns}" "${iconset}" | |
MAIN_DEPENDENCY "${sourceimg}" | |
DEPENDS ${deplist} | |
COMMENT "ICNS: ${output_icns}" | |
VERBATIM) | |
if (ARG_OUTPUT) | |
set ("${ARG_OUTPUT}" "${output_icns}" PARENT_SCOPE) | |
endif () | |
endfunction () | |
function (make_icns_from_svg) | |
cmake_parse_arguments ( | |
ARG | |
"" # Boolean args | |
"INPUT;OUTPUT" # List of single-value args | |
"" # Multi-valued args | |
${ARGN}) | |
set (CMAKE_FIND_APPBUNDLE NEVER) # otherwise, it'll pick up the app bundle and open a shit ton of windows | |
find_program ( | |
inkscape_exe | |
NAMES "inkscape" "inkscape.exe" | |
DOC "Path to Inkscape" | |
PATHS "/usr/local/bin" "/usr/bin") | |
message (STATUS "Inkscape path: ${inkscape_exe}") | |
if (NOT inkscape_exe) | |
message (FATAL_ERROR "Could not find Inkscape - is it installed?") | |
endif () | |
get_filename_component (ARG_INPUT_ABS "${ARG_INPUT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") | |
get_filename_component (ARG_INPUT_ABS_BIN "${ARG_INPUT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") | |
get_filename_component (ARG_INPUT_FN "${ARG_INPUT_ABS_BIN}" NAME_WE) | |
get_filename_component (ARG_INPUT_DIR "${ARG_INPUT_ABS_BIN}" DIRECTORY) | |
set (sourceimg "${ARG_INPUT_ABS}") | |
set (basepath "${ARG_INPUT_DIR}/${ARG_INPUT_FN}") | |
set (output_icns "${basepath}.icns") | |
set (iconset "${basepath}.iconset") | |
set (deplist "") | |
foreach (size IN ITEMS 16 32 128 256 512) | |
math (EXPR size2x "2 * ${size}") | |
set (ipath "${iconset}/icon_${size}x${size}.png") | |
set (ipath2x "${iconset}/icon_${size}x${size}@2x.png") | |
list (APPEND deplist "${ipath}" "${ipath2x}") | |
add_custom_command ( | |
OUTPUT "${ipath}" | |
COMMAND "${inkscape_exe}" ARGS -z -e "${ipath}" -w ${size} -h ${size} "${sourceimg}" | |
MAIN_DEPENDENCY "${sourceimg}" | |
COMMENT "ICNS resize: ${ipath}" | |
VERBATIM) | |
add_custom_command ( | |
OUTPUT "${ipath2x}" | |
COMMAND "${inkscape_exe}" ARGS -z -e "${ipath2x}" -w ${size2x} -h ${size2x} "${sourceimg}" | |
MAIN_DEPENDENCY "${sourceimg}" | |
COMMENT "ICNS resize: ${ipath2x}" | |
VERBATIM) | |
endforeach () | |
add_custom_command ( | |
OUTPUT "${output_icns}" | |
COMMAND iconutil ARGS --convert icns --output "${output_icns}" "${iconset}" | |
MAIN_DEPENDENCY "${sourceimg}" | |
DEPENDS ${deplist} | |
COMMENT "ICNS: ${output_icns}" | |
VERBATIM) | |
if (ARG_OUTPUT) | |
set ("${ARG_OUTPUT}" "${output_icns}" PARENT_SCOPE) | |
endif () | |
endfunction () | |
function (make_icns) | |
cmake_parse_arguments ( | |
ARG | |
"" # Boolean args | |
"INPUT;OUTPUT" # List of single-value args | |
"" # Multi-valued args | |
${ARGN}) | |
if (NOT ARG_INPUT) | |
message (FATAL_ERROR "INPUT is required") | |
endif () | |
if (NOT IS_ABSOLUTE "${ARG_INPUT}") | |
get_filename_component (ARG_INPUT "${ARG_INPUT}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") | |
endif () | |
if (NOT EXISTS "${ARG_INPUT}") | |
message (FATAL_ERROR "INPUT does not exist: ${ARG_INPUT}") | |
endif () | |
file (RELATIVE_PATH ARG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}" "${ARG_INPUT}") | |
get_filename_component (ARG_INPUT_EXT "${ARG_INPUT}" EXT) | |
if ("${ARG_INPUT_EXT}" STREQUAL ".png") | |
make_icns_from_png (INPUT "${ARG_INPUT}" OUTPUT child_output) | |
elseif ("${ARG_INPUT_EXT}" STREQUAL ".svg") | |
make_icns_from_svg (INPUT "${ARG_INPUT}" OUTPUT child_output) | |
else () | |
message (FATAL_ERROR "INPUT must refer to a .png or .svg, but a ${ARG_INPUT_EXT} was provided") | |
endif () | |
if (ARG_OUTPUT) | |
set ("${ARG_OUTPUT}" "${child_output}" PARENT_SCOPE) | |
endif () | |
endfunction () |
What do you mean by standalone mode in this context? :)
by standalone I meant that I have PNG files, convert
and cmake
installed, how to use this file to convert PNG to ICNS?
What preparations to make to directory structure? How to invoke cmake
? What arguments to pass in?
But then I've found the icnsutils
package which solved my simple CLI needs with png2icns
executable.
It only supports one image that gets resized, you don't need to do anything except pass in the main image. The output argument is the variable name in the caller scope that receives the final path of the icon file, which you can use in another custom command's list of dependencies.
Hello Qix,
I am the author of Sky Dolly, an open source flight recorder and replay application for Microsoft Flight Simulator 2020 (MSFS). Sky Dolly essentially
• Records flights done in MSFS, by sampling position, aircraft attitude, engine and other aircraft status variables («simulation variables»)
• Replays the recorded flights in MSFS, by sending back the previously sampled «simulation variables»
• Provides several import and export formats (GPX, IGC, KML, CSV, …)
Your gist to automatically generate application icon sets (*.icns) is used for the macOS build of Sky Dolly (currently Sky Dolly is only really useful on Windows, because MSFS only runs on Windows - but I mainly develop Sky Dolly on macOS (and "cross-check" the builds on Linux with another compiler), with the long-term plan to implement - maybe - a networked "SimConnect" connection between the apps running on different platforms.
Anyway... ;)
Your contribution is mentioned here:
https://github.com/till213/SkyDolly/blob/main/THIRD_PARTY.md
And within in the application itself (embedded in the “About” dialog):
https://github.com/till213/SkyDolly/blob/main/src/UserInterface/res/text/ThirdParty.md
Thank you so much for providing this very useful CMake snippet, it was very helpful and saved me a couple of hours 😊
Best, Oliver
Hey thanks for letting me know! Cool stuff, appreciate that!
Hi, thanks for sharing this. How do I use it in a standalone mode? provided that I have
convert
andcmake
installed