Scripting Question: How to reference the active Palette

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

Any advice is appreciated! Thanks!

1 Like

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.

1 Like

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:

app.command.PaletteEditor.ChangeColor{target = nearestValIDX}

The command I was looking for was:

app.command.ChangeColor{target = nearestValIDX}

Thanks for your help! This community is so awesome!

1 Like

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
1 Like

That’s very valuable to me, thank you!

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).