EDIT: I believe I found how to reference the active palette:
local currentPalette = app.activeSprite.palettes[1]
I’m still running into some other (possibly unrelated) issues so I can’t be sure for now.
Hi there! I’m trying to add a feature to my script that will allow me to find the color in the current palette that is nearest to the color that the user has selected in the dialog. What I’m confused about is how to reference the current palette.
I assumed that I could write: local currentPalette = app.activePalette
(or something along those lines). However, I can’t find a way to do this in the documentation anywhere. It almost seems like I can only make and reference local palettes that I myself created (or which I’ve loaded into a local variable from a separate palette file). Does anyone know I can reference the active palette?
Here’s a snippet of my code:
function findNearestColorInPalette(CM)
local nearestValIDX = 0
local minDistance
local currentPalette = app.activePalette -- somehow get active palette
-- iterate through the colors in the palette and get their distance from the main color
-- keep track of the minimum distance and the corresponding palette index
for i=0, #currentPalette - 1, 1 do
local secondColor = palette:getColor(i)
local currentDistance = getDistance(CM, secondColor)
if (not minDistance == nil) and currentDistance < minDistance then
minDistance = currentDistance
nearestValIDX = i
elseif minDistance == nil then
minDistance = currentDistance
nearestValIDX = i
end
end
-- use the PaletteEditor command to select the nearest color in the palette window
app.command.PaletteEditor.ChangeColor{target = nearestValIDX}
end
Correct, you need a specific sprite to reference the palette and the sprite.palettes[1] is the currently recommended solution according to the API documentation. This might change in the future when we get support for multiple color palettes.
Aseprite already provides an option to get the closest color from the palette using the Color.index property, it’s not specified how it is determined though.
Thanks! I didn’t know about the Color.index property, but I may want to be able to allow the user to specify the metric for computing the color distance (maybe a standard one, one based on closest saturation, one on closest lightness, etc).
I got it working with both the Color.index property and my original approach. I found out that I was being dumb when I wrote this line:
Also, you may be interested to know that the Color.index approach returns the same result as my current approach. Specifically, I’ve noticed that these two codes select the same palette index in all the cases I’ve tested so far.
Here’s the code with a generic distance-squared approach
function getDistance(firstColor,secondColor)
-- define a metric for a distance between two colors
-- return the computed distance
local firstRedVal = app.pixelColor.rgbaR(firstColor)
local firstGreenVal = app.pixelColor.rgbaG(firstColor)
local firstBlueVal = app.pixelColor.rgbaB(firstColor)
local firstAlphaVal = app.pixelColor.rgbaA(firstColor)
local secondRedVal = app.pixelColor.rgbaR(secondColor)
local secondGreenVal = app.pixelColor.rgbaG(secondColor)
local secondBlueVal = app.pixelColor.rgbaB(secondColor)
local secondAlphaVal = app.pixelColor.rgbaA(secondColor)
--I will start with the simplest color metric possible -- may add a more complicated variation later
local redDist = firstRedVal - secondRedVal
local greenDist = firstGreenVal - secondGreenVal
local blueDist = firstBlueVal - secondBlueVal
local alphaDist = firstAlphaVal - secondAlphaVal
local result = redDist*redDist + greenDist*greenDist + blueDist*blueDist + alphaDist*alphaDist
return result
end
function findNearestColorInPalette(CM)
local nearestValIDX = 0
local minDistance
-- iterate through the colors in the palette and get their distance from the main color
-- keep track of the minimum distance and the corresponding palette index
local currentPalette = app.activeSprite.palettes[1]
for i=0, #currentPalette-1 do
local secondColor = currentPalette:getColor(i)
local currentDistance = getDistance(CM, secondColor)
if (not minDistance == nil) and currentDistance < minDistance then
minDistance = currentDistance
nearestValIDX = i
elseif minDistance == nil then
minDistance = currentDistance
nearestValIDX = i
end
end
-- use the PaletteEditor command to select the nearest color in the palette window
app.command.ChangeColor{target = nearestValIDX}
--set the foreground color to the CM again so that the user doesn't have their fg change
app.fgColor = CM
end
and here’s the code for Color.index:
function findNearestColorInPalette(CM)
local nearestValIDX = CM.index
-- use the PaletteEditor command to select the nearest color in the palette window
app.command.ChangeColor{target = nearestValIDX}
--set the foreground color to the CM again so that the user doesn't have their fg change
app.fgColor = CM
end
RGBA distance was the most obvious but you can never be sure, I want to test how different would be results when calculating distance in other color models like HSV or HSL (they aren’t ideal for this but they are already supported).