local palette_swap = {} -------------------------------------------------------------------------------- -- 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 = 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 function palette_swap.apply_color_map_to_image_data (img_data, map_fn) assert(img_data) assert(type(map_fn) == 'function') -- 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 function palette_swap.color_map.switch_channel (mode) local channels = {'r', 'g', 'b'} local channel_order = {} for i = 1, #channels do local index = (mode % #channels) + 1 mode = mode / #channels channel_order[#channel_order+1] = table.remove(channels,index) end local func_s = ("return function (r, g, b) return %s, %s, %s end"):format(unpack(channel_order)) return loadstring (func_s)() end function palette_swap.color_map.rotate_hue (rad) -- 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') -- Create function return function (r, g, b) local hsl = colors.rgb_to_hsl(colors.rgb1_to_rgb255(r, g, b)) -- hsl[1] = (hsl[1] + rad) % 1 -- local rgb1 = colors.hsl_to_rgb1(hsl) return unpack(rgb1) end end -------------------------------------------------------------------------------- -- Return return palette_swap