Palette Reduction/Conversion Tool

Hi @blaze_kick,

Welcome aboard and congratulations on releasing your Aseprite extension! :slight_smile:

Regarding any tips, I’m not in the least an expert on performance, so take all advice to follow with a grain of salt.

I’d say start by having a look at this post:

As far as I know, color matching can be sped up with a space partitioning strategy. I’m aware of octrees, I believe people use k-d trees as well, and there may be yet others.

I also suggest finding the unique colors in an image, then matching the palette to uniques, rather than looping over all the pixels. Unique colors can be found by using a boolean as a dummy value for each key, e.g., dictionary[rgbaInteger] = true. Palette matches can be assigned to colors from the image in a similar manner, e.g., dictionary[uniqueImageColor] = paletteMatchInteger, then pixelIterator(dictionary[pixelIterator()]). In the examples, by integer I’m referring to the 32-bit integers that store the color channels, each in [0, 255], in the order 0xAABBGGRR.

Perhaps not as important: if you use Euclidean distance, try seeing if the distance-squared gives you the same results. It might spare you some math.sqrt calls. Also, if I remember correctly, you don’t need to find the math.abs of the delta when the exponent is even, i.e. is 2. For example, check that with local deltasq = delta * delta. You may want to retain the abs, however, if you want to generalize to some other distance metric later. To see what I mean, compare the formulas for Manhattan, Minkowski, Chebyshev and Euclidean distance.

(The distance metric for CIE LAB is a whole other rabbit hole, and I prefer to simplify by choosing a variant LAB space instead of tackling it directly.)

The go-to doc for general Lua performance tips is a pdf by Roberto Ierusalimschy: https://www.lua.org/gems/sample.pdf . It includes advice such as localizing global functions that are used in loops, e.g., local sqrt = math.sqrt and simplifying tables, e.g., rgbaTable[1 + i * channelCount + rChannelOffset] = red instead of rgbaTable[1 + i] = { r = red, g = green, b = blue }.

Measure elapsed time for your script. I just use os.clock, then subtract the start time from the end. Are there better ways? Probably.

Lastly, I guess others were looking into / found a way to write in another programming language, with the Lua handling primarily the UI? Not sure though. See Calling a C function from Lua inside Aseprite? .

Hope that helps some,
Jeremy

2 Likes