1
0

Compare commits

...

8 Commits

Author SHA1 Message Date
5ab72c18d1 🤖 Bumped version to 0.1.1
All checks were successful
LÖVE/Lua Library / Lua-Testing (push) Successful in 8s
LÖVE/Lua Library / Static-Analysis (push) Successful in 4s
This commit was automatically generated by [a script](https://gitfub.space/Jmaa/repo-manager)
2025-04-17 16:00:31 +02:00
48091dcf98 🤖 Repository layout updated to latest version
This commit was automatically generated by [a script](https://gitfub.space/Jmaa/repo-manager)
2025-04-17 15:59:35 +02:00
962182f5c3 🤖 Repository layout updated to latest version
This commit was automatically generated by [a script](https://gitfub.space/Jmaa/repo-manager)
2025-04-17 15:59:07 +02:00
369dbb9d43 Author 2025-04-17 15:56:05 +02:00
d096e4b4eb 🤖 Repository layout updated to latest version
This commit was automatically generated by [a script](https://gitfub.space/Jmaa/repo-manager)
2025-04-17 15:53:17 +02:00
d08a003f31 🤖 Repository layout updated to latest version
This commit was automatically generated by [a script](https://gitfub.space/Jmaa/repo-manager)
2025-04-17 15:51:38 +02:00
1f1e8973c0 Re-add init 2025-04-17 14:59:37 +02:00
e0a7b52994 Rename init.lua 2025-04-17 14:59:03 +02:00
8 changed files with 270 additions and 196 deletions

View File

@ -1,8 +0,0 @@
name: Lua Library
on: [push]
jobs:
Lua-Testing:
uses: jmaa/workflows/.gitea/workflows/lua-testing.yaml@v6.19
Static-Analysis:
uses: jmaa/workflows/.gitea/workflows/lua-static-analysis.yaml@v6.19

View File

@ -0,0 +1,29 @@
# WARNING!
# THIS IS AN AUTOGENERATED FILE!
# MANUAL CHANGES CAN AND WILL BE OVERWRITTEN!
name: LÖVE/Lua Library
on:
push:
paths-ignore: ['README.md', '.gitignore', 'LICENSE', 'CONVENTIONS.md']
jobs:
Lua-Testing:
runs-on: ubuntu-latest
steps:
- name: Install Lua
run: |
apt-get update
apt-get install -y luajit
- name: Check out repository code
uses: actions/checkout@v3
- name: Run testing library
run: luajit test/init.lua
Static-Analysis:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Luacheck linter
uses: https://github.com/lunarmodules/luacheck@v1.1.1

19
.gitignore vendored Normal file
View File

@ -0,0 +1,19 @@
# WARNING!
# THIS IS AN AUTOGENERATED FILE!
# MANUAL CHANGES CAN AND WILL BE OVERWRITTEN!
# Löve: Exclude build items
/bin/
/lib/
.love-cache/
# Compiled Lua sources
luac.out
# Misc (Image, MacOS, Backups) files
*.psd
*~
.DS_Store
# Tools
*.tiled-session

View File

@ -1,6 +1,10 @@
std = "max" -- WARNING!
-- THIS IS AN AUTOGENERATED FILE!
-- MANUAL CHANGES CAN AND WILL BE OVERWRITTEN!
std = "love+max"
cache = true cache = true
include_files = {"**/*.lua"} include_files = {"**.lua", "*.luacheckrc"}
exclude_files = {} exclude_files = {}
self = false self = false
max_line_length=false max_line_length=false

3
LICENSE Normal file
View File

@ -0,0 +1,3 @@
Copyright (c) 2019-2025 Jon Michael Aanes
All rights reserved.

View File

@ -1,3 +1,23 @@
# Palette Swap <!-- WARNING! -->
<!-- THIS IS AN AUTOGENERATED FILE! -->
<!-- MANUAL CHANGES CAN AND WILL BE OVERWRITTEN! -->
Utility library for creating palette swaps of LÖVE-based images. # Utility library for creating palette swaps of LÖVE-based images
## Dependencies
This project requires [PUC Lua 5.1](https://www.tecgraf.puc-rio.br/lua/mirror/versions.html#5.1) or [LuaJIT](https://luajit.org/luajit.html). Newer versions of PUC Lua are not supported.
This project does not have any library requirements 😎
## Contributing
Feel free to submit pull requests. Please follow the [Code Conventions](CONVENTIONS.md) when doing so.
## License
```
Copyright (c) 2019-2025 Jon Michael Aanes
All rights reserved.
```

188
init.lua
View File

@ -1,185 +1,5 @@
--- Utility library for creating palette swaps of LÖVE-based images. -- WARNING!
-- THIS IS AN AUTOGENERATED FILE!
-- MANUAL CHANGES CAN AND WILL BE OVERWRITTEN!
local _VERSION = '0.1.0' return require (((...) ~= 'init' and (...) .. '.' or '') .. 'palette-swap')
local palette_swap = {
_VERSION = _VERSION,
}
--------------------------------------------------------------------------------
-- Main work functions
local function get_palette_of_image_data (data)
assert(data)
--
local palette = {}
local has_seen = {}
--
for x = 0, data:getWidth() - 1 do
for y = 0, data:getHeight() - 1 do
local r, g, b, a = data:getPixel(x, y)
if not has_seen[r] then has_seen[r] = {} end
if not has_seen[r][g] then has_seen[r][g] = {} end
if not has_seen[r][g][b] then
local color = {r,g,b,a}
has_seen[r][g][b] = color
palette[#palette+1] = color
end
end
end
--
return palette
end
local function change_palette_to_dim_tree (change_palette)
assert(type(change_palette) == 'table')
--
local tree = {}
--
for color_from, color_to in pairs(change_palette) do
assert(type(color_from) == 'table')
assert(type(color_to) == 'table')
--
local r, g, b = unpack(color_from)
if not tree[r] then tree[r] = {} end
if not tree[r][g] then tree[r][g] = {} end
--
assert(not tree[r][g][b])
tree[r][g][b] = color_to
end
--
return tree
end
local function apply_change_palette (data, change_palette)
assert(data)
assert(change_palette)
--
local change_tree = change_palette_to_dim_tree(change_palette)
local function map (_x, _y, r, g, b, a)
local c = change_tree[r][g][b]
return c[1], c[2], c[3], a
end
--
local new_data = data:clone()
new_data:mapPixel(map)
--
return new_data
end
local function change_palette_from_map (map_func, palette)
local change_palette = {}
for i = 1, #palette do
local from = palette[i]
local to = {[4] = 1, map_func(unpack(from))}
change_palette[from] = to
end
return change_palette
end
--------------------------------------------------------------------------------
-- API
palette_swap.get_palette_from_image_data = get_palette_of_image_data
local function concat_functions (first_fn, ...)
--
local funcs = {first_fn, ...}
-- Identity function.
if #funcs == 0 then
return function (...) return ... end
-- Only one function
elseif #funcs <= 1 then
return first_fn
end
-- Generic
return function (...)
local val = {...}
for i = 1, #funcs do
val = {funcs[i](unpack(val))}
end
return unpack(val)
end
end
function palette_swap.apply_color_map_to_image_data (img_data, ...)
assert(img_data)
--
local map_fn = concat_functions(...)
--
return apply_change_palette(img_data, change_palette_from_map(map_fn, get_palette_of_image_data(img_data)))
end
--------------------------------------------------------------------------------
-- Example color maps
palette_swap.color_map = {}
function palette_swap.color_map.invert (r,g,b)
return 1 - r, 1 - g, 1 - b
end
local CHANNEL_ORDERS = {
[0] = {'r', 'g', 'b'},
[1] = {'g', 'b', 'r'},
[2] = {'b', 'r', 'g'},
[3] = {'r', 'b', 'g'},
[4] = {'b', 'g', 'r'},
[5] = {'g', 'r', 'b'},
[6] = {'b', 'g', 'r'},
[7] = {'b', 'g', 'r'}, -- TODO
[8] = {'b', 'g', 'r'}, -- TODO
[9] = {'r', 'g', 'b'}, -- TODO
}
function palette_swap.color_map.switch_channel (mode)
local channel_order = CHANNEL_ORDERS[mode]
local func_s = ("return function (r, g, b) return %s, %s, %s end"):format(unpack(channel_order))
return loadstring (func_s)()
end
local function load_colors ()
-- Only need to import colors when needed
local colors = require 'colors'
assert(type(colors) == 'table')
assert(type(colors.rgb1_to_rgb255) == 'function')
assert(type(colors.rgb_to_hsl) == 'function')
assert(type(colors.hsl_to_rgb1) == 'function')
function palette_swap.color_map.increase_saturation (amount)
-- Create function
return function (r, g, b)
local hsl = colors.rgb_to_hsl(colors.rgb1_to_rgb255(r, g, b))
--
hsl[2] = math.min(1, math.max(0, hsl[2] + amount))
--
return unpack(colors.hsl_to_rgb1(hsl))
end
end
function palette_swap.color_map.rotate_hue (rad)
return function (r, g, b)
local hsl = colors.rgb_to_hsl(colors.rgb1_to_rgb255(r, g, b))
--
hsl[1] = (hsl[1] + rad) % 1
--
return unpack(colors.hsl_to_rgb1(hsl))
end
end
end
for _, key in ipairs {'rotate_hue', 'increase_saturation'} do
palette_swap.color_map[key] = function (...)
load_colors()
return palette_swap.color_map[key](...)
end
end
--------------------------------------------------------------------------------
-- Return
return palette_swap

187
palette-swap.lua Normal file
View File

@ -0,0 +1,187 @@
--- Utility library for creating palette swaps of LÖVE-based images.
--
-- @author Jon Michael Aanes (jonjmaa@gmail.com)
local _VERSION = '0.1.1'
local palette_swap = {
_VERSION = _VERSION,
}
--------------------------------------------------------------------------------
-- Main work functions
local function get_palette_of_image_data (data)
assert(data)
--
local palette = {}
local has_seen = {}
--
for x = 0, data:getWidth() - 1 do
for y = 0, data:getHeight() - 1 do
local r, g, b, a = data:getPixel(x, y)
if not has_seen[r] then has_seen[r] = {} end
if not has_seen[r][g] then has_seen[r][g] = {} end
if not has_seen[r][g][b] then
local color = {r,g,b,a}
has_seen[r][g][b] = color
palette[#palette+1] = color
end
end
end
--
return palette
end
local function change_palette_to_dim_tree (change_palette)
assert(type(change_palette) == 'table')
--
local tree = {}
--
for color_from, color_to in pairs(change_palette) do
assert(type(color_from) == 'table')
assert(type(color_to) == 'table')
--
local r, g, b = unpack(color_from)
if not tree[r] then tree[r] = {} end
if not tree[r][g] then tree[r][g] = {} end
--
assert(not tree[r][g][b])
tree[r][g][b] = color_to
end
--
return tree
end
local function apply_change_palette (data, change_palette)
assert(data)
assert(change_palette)
--
local change_tree = change_palette_to_dim_tree(change_palette)
local function map (_x, _y, r, g, b, a)
local c = change_tree[r][g][b]
return c[1], c[2], c[3], a
end
--
local new_data = data:clone()
new_data:mapPixel(map)
--
return new_data
end
local function change_palette_from_map (map_func, palette)
local change_palette = {}
for i = 1, #palette do
local from = palette[i]
local to = {[4] = 1, map_func(unpack(from))}
change_palette[from] = to
end
return change_palette
end
--------------------------------------------------------------------------------
-- API
palette_swap.get_palette_from_image_data = get_palette_of_image_data
local function concat_functions (first_fn, ...)
--
local funcs = {first_fn, ...}
-- Identity function.
if #funcs == 0 then
return function (...) return ... end
-- Only one function
elseif #funcs <= 1 then
return first_fn
end
-- Generic
return function (...)
local val = {...}
for i = 1, #funcs do
val = {funcs[i](unpack(val))}
end
return unpack(val)
end
end
function palette_swap.apply_color_map_to_image_data (img_data, ...)
assert(img_data)
--
local map_fn = concat_functions(...)
--
return apply_change_palette(img_data, change_palette_from_map(map_fn, get_palette_of_image_data(img_data)))
end
--------------------------------------------------------------------------------
-- Example color maps
palette_swap.color_map = {}
function palette_swap.color_map.invert (r,g,b)
return 1 - r, 1 - g, 1 - b
end
local CHANNEL_ORDERS = {
[0] = {'r', 'g', 'b'},
[1] = {'g', 'b', 'r'},
[2] = {'b', 'r', 'g'},
[3] = {'r', 'b', 'g'},
[4] = {'b', 'g', 'r'},
[5] = {'g', 'r', 'b'},
[6] = {'b', 'g', 'r'},
[7] = {'b', 'g', 'r'}, -- TODO
[8] = {'b', 'g', 'r'}, -- TODO
[9] = {'r', 'g', 'b'}, -- TODO
}
function palette_swap.color_map.switch_channel (mode)
local channel_order = CHANNEL_ORDERS[mode]
local func_s = ("return function (r, g, b) return %s, %s, %s end"):format(unpack(channel_order))
return loadstring (func_s)()
end
local function load_colors ()
-- Only need to import colors when needed
local colors = require 'colors'
assert(type(colors) == 'table')
assert(type(colors.rgb1_to_rgb255) == 'function')
assert(type(colors.rgb_to_hsl) == 'function')
assert(type(colors.hsl_to_rgb1) == 'function')
function palette_swap.color_map.increase_saturation (amount)
-- Create function
return function (r, g, b)
local hsl = colors.rgb_to_hsl(colors.rgb1_to_rgb255(r, g, b))
--
hsl[2] = math.min(1, math.max(0, hsl[2] + amount))
--
return unpack(colors.hsl_to_rgb1(hsl))
end
end
function palette_swap.color_map.rotate_hue (rad)
return function (r, g, b)
local hsl = colors.rgb_to_hsl(colors.rgb1_to_rgb255(r, g, b))
--
hsl[1] = (hsl[1] + rad) % 1
--
return unpack(colors.hsl_to_rgb1(hsl))
end
end
end
for _, key in ipairs {'rotate_hue', 'increase_saturation'} do
palette_swap.color_map[key] = function (...)
load_colors()
return palette_swap.color_map[key](...)
end
end
--------------------------------------------------------------------------------
-- Return
return palette_swap