Skip to content

Commit

Permalink
Testing some utility classes
Browse files Browse the repository at this point in the history
  • Loading branch information
tresf committed Feb 6, 2025
1 parent 6a0a4cd commit 4d22dda
Show file tree
Hide file tree
Showing 4 changed files with 243 additions and 0 deletions.
15 changes: 15 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ SET(LMMS_SOURCE_DIR ${CMAKE_SOURCE_DIR})
# Import of windows.h breaks min()/max()
ADD_DEFINITIONS(-DNOMINMAX)

include(SvgRecolor)
set(svg_green "#27ab5f;#249a56;#34d07b;opacity=\".1\" fill=\"#fff\"")
set(svg_blue "#3992cb;#2b6fc5;#62a8d4;opacity=\".1\" fill=\"#fff\"")
set(svg_purple "#5547bd;#493ba1;#7871c5;opacity=\".05\" fill=\"#fff\"")

svg_recolor(svg_green svg_purple "${CMAKE_SOURCE_DIR}/cmake/linux/icons/scalable/apps/lmms.svg" svg_recolored)

include(SvgConvert)
svg_convert("16;16@2;32;32@2;48;48@2" "${svg_recolored}" "${CMAKE_CURRENT_BINARY_DIR}/branding/%size%x%size%@%mult%/%name%.png")

include(IcnsConvert)
icns_convert("${svg_recolored}" "${CMAKE_CURRENT_BINARY_DIR}/lmms.icns")

message(FATAL_ERROR "Done")

# CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES is not set correctly for MinGW until
# CMake 3.14.1, so avoid specifying system include directories on affected
# versions. Normal include directories are safe, since GCC ignores them if they
Expand Down
46 changes: 46 additions & 0 deletions cmake/modules/IcnsConvert.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Convert an SVG to Apple icns file
#
# Copyright (c) 2025, Tres Finocchiaro, <tres.finocchiaro@gmail.com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
function(icns_convert source_file destination_file)
include(SvgConvert)

if(CPACK_CURRENT_BINARY_DIR)
# Support calling from CPACK
set(working_directory "${CPACK_CURRENT_BINARY_DIR}")
else()
set(working_directory "${CMAKE_CURRENT_BINARY_DIR}")
endif()

if(DEFINED ENV{WANT_DEBUG_BRANDING})
set(WANT_DEBUG_BRANDING ON)
endif()
if(WANT_DEBUG_BRANDING)
set(COMMAND_ECHO STDOUT)
else()
set(COMMAND_ECHO NONE)
endif()

# First, create icons at the standard resolutions
get_filename_component(name "${source_file}" NAME_WLE)
file(REMOVE "${working_directory}/${name}.iconset")

set(sizes 16 16@2 32 32@2 64 64@2 128 128@2 256 256@2 512 512@2)
#svg_convert("16@2;32;48;64;128" "${svg_recolored}" "${CMAKE_CURRENT_BINARY_DIR}")
svg_convert("${sizes}" "${source_file}" "${working_directory}/%name%.iconset/icon_%size%x%size%@%mult%x.png")

# Create the icns file
execute_process(COMMAND iconutil
--convert icns
"${working_directory}/${name}.iconset"
--output "${destination_file}"
WORKING_DIRECTORY "${working_directory}"
OUTPUT_QUIET
COMMAND_ECHO ${COMMAND_ECHO}
COMMAND_ERROR_IS_FATAL ANY)

file(REMOVE "${working_directory}/${name}.iconset")
message(STATUS " icns_convert: ${source_file} --> ${destination_file}")
endfunction()
147 changes: 147 additions & 0 deletions cmake/modules/SvgConvert.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# Convert an SVG to png at the sizes specified by size_list
#
# Copyright (c) 2025, Tres Finocchiaro, <tres.finocchiaro@gmail.com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
function(svg_convert size_list source_file output_pattern)
if(CPACK_CURRENT_BINARY_DIR)
# Support calling from CPACK
set(working_directory "${CPACK_CURRENT_BINARY_DIR}")
else()
set(working_directory "${CMAKE_CURRENT_BINARY_DIR}")
endif()

if(DEFINED ENV{WANT_DEBUG_BRANDING})
set(WANT_DEBUG_BRANDING ON)
endif()
if(WANT_DEBUG_BRANDING)
set(COMMAND_ECHO STDOUT)
else()
set(COMMAND_ECHO NONE)
endif()

foreach(size ${size_list})
if(NOT EXISTS "${source_file}")
message(FATAL_ERROR "SVG file does not exist: ${source_file}")
endif()
#find_best_tool()
rsvg_convert("${source_file}" ${size} "${working_directory}" "${output_pattern}" ${COMMAND_ECHO} png_rendered)
#inkscape_convert("${source_file}" ${size} "${working_directory}" "${output_pattern}" ${COMMAND_ECHO} png_rendered)
message(STATUS " svg_convert: ${source_file} --> ${png_rendered}")
endforeach()
endfunction()

# Inkscape is pretty slow, but it works
function(inkscape_convert source_file size working_directory pattern command_echo result)
patternize_file("${source_file}" ${size} "${pattern}" scaled_size png_out)

# Inkscape prefers units as 90-dpi
execute_process(COMMAND inkscape "${source_file}"
--batch-process
--export-dpi=72
--export-type=png
--export-width=${scaled_size}
"--export-filename=${png_out}"
WORKING_DIRECTORY "${working_directory}"
OUTPUT_QUIET
ERROR_QUIET
COMMAND_ECHO ${command_echo}
COMMAND_ERROR_IS_FATAL ANY
ERROR_VARIABLE inkscape_output)

# Inkscpae doesn't properly return error codes, parse output instead
if("${inkscape_output}" MATCHES "(Failed|failed|error)")
message(FATAL_ERROR "${inkscape_output}")
endif()

set(${result} "${png_out}" PARENT_SCOPE)
endfunction()

# RSVG is much faster than inkscape
function(rsvg_convert source_file size working_directory pattern command_echo result)
patternize_file("${source_file}" ${size} "${pattern}" scaled_size png_out)

execute_process(COMMAND rsvg-convert
"${source_file}"
-w "${scaled_size}"
-o "${png_out}"
WORKING_DIRECTORY "${working_directory}"
COMMAND_ECHO ${command_echo}
COMMAND_ERROR_IS_FATAL ANY)

set(${result} "${png_out}" PARENT_SCOPE)
endfunction()

# FIXME:
# 1. rsvg_convert is fastest
# 2. inkscape is slow but works well
# 3. gimp?
function(find_best_tool)
if(ImageMagick_FOUND AND RSVG_FOUND)
# good
else()
find_package(ImageMagick COMPONENTS convert)
# Prefer EXECUTE_PROCESS over PKG_CHECK_MODULES per https://apple.stackexchange.com/q/169601/147537
execute_process(COMMAND rsvg-convert --version ERROR_QUIET OUTPUT_VARIABLE RSVG_FOUND)
endif()
endfunction()

# Patternize a filename so we can write it to well-known locations
#
# Example:
# patternize_file(background.svg 64@2 "%name%@%mult%x.png" size file)
#
# source_file:
# background.svg, lmms.svg, etc
#
# size:
# 32, 64, 64@2, etc
#
# pattern:
# background@2x.png = %name%@%mult%x.png
# icons/16x16@2/apps/lmms.png = icons/%size%x%size%@%mult%.png
#
# result_size, result_file: output variables
#
# There is no handling for escaping %'s
function(patternize_file source_file size pattern result_size result_file)
# Calculate 'multiplier' 'unscaled_size' 'scaled_size' from provided size (e.g. '128' or '128@2')
if(size MATCHES "@")
string(REPLACE "@" ";" parts "${size}")
list(GET parts 0 unscaled_size)
list(GET parts 1 multiplier)
math(EXPR scaled_size "${unscaled_size}*${multiplier}")
else()
set(unscaled_size "${size}")
set(multiplier 1)
set(scaled_size "${size}")
endif()

# Handle %mult%
if(multiplier EQUAL 1)
# Assume no one wants "@1" or "@2x" in a filename
string(REPLACE "@%mult%x." "." result_file_name "${pattern}")
string(REPLACE "@%mult%" "" result_file_name "${result_file_name}")
else()
# Special handling for apple's "@2x" notation
string(REPLACE "@%mult%x." "@${multiplier}x." result_file_name "${pattern}")
string(REPLACE "%mult%" "${multiplier}" result_file_name "${pattern}")
endif()

# Handle %size%
string(REPLACE "%size%" "${unscaled_size}" result_file_name "${result_file_name}")

# Handle %name%
get_filename_component(name "${source_file}" NAME_WLE)
string(REPLACE "%name%" "${name}" result_file_name "${result_file_name}")

# Ensure parent directory exists
get_filename_component(parent_dir "${result_file_name}" DIRECTORY)
if(NOT EXISTS "${parent_dir}")
file(MAKE_DIRECTORY "${parent_dir}")
endif()

set(${result_size} "${scaled_size}" PARENT_SCOPE)
set(${result_file} "${result_file_name}" PARENT_SCOPE)
endfunction()
35 changes: 35 additions & 0 deletions cmake/modules/SvgRecolor.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Recolor an SVG using search/replace techniques
#
# Copyright (c) 2025, Tres Finocchiaro, <tres.finocchiaro@gmail.com>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
function(svg_recolor search_list replace_list source_file result)
file(READ "${source_file}" svg_data)
# set(var "${${var}}") will read and expand a quoted list by name
set(search_list "${${search_list}}")
set(replace_list "${${replace_list}}")
list(LENGTH search_list length)
math(EXPR length "${length}-1")
foreach(i RANGE ${length})
list(GET search_list ${i} search)
list(GET replace_list ${i} replace)
if(WANT_DEBUG_BRANDING OR DEFINED ENV{WANT_DEBUG_BRANDING})
message(" svg_recolor ${i}: ${search} --> ${replace}")
endif()
string(REPLACE "${search}" "${replace}" svg_data "${svg_data}")
endforeach()

get_filename_component(source_file_name "${source_file}" NAME)
if(CPACK_CURRENT_BINARY_DIR)
# Support calling from CPACK
set(working_directory "${CPACK_CURRENT_BINARY_DIR}")
else()
set(working_directory "${CMAKE_CURRENT_BINARY_DIR}")
endif()
set(destination_file "${working_directory}/${source_file_name}")

file(WRITE "${destination_file}" "${svg_data}")
message(STATUS " svg_recolor: ${source_file} --> ${destination_file}")
set(${result} "${destination_file}" PARENT_SCOPE)
endfunction()

0 comments on commit 4d22dda

Please sign in to comment.