API: Unexpected behavior with Image:drawImage()

I’m currently working on a script to combine grouped layers. Using the Aseprite API, destImage:drawImage(sourceImage) seems to only be capable of replacing pixels of the destination image, with no consideration for transparency:


On the left is the result I’d expect. Multiple layers being drawn on top of each other - the hair is a separate layer than the head. When the hair is drawn on top, it should not replace head pixels with transparent pixels. On the right is what drawImage actually produces; the head pixels are replaced with transparent pixels.

Is it possible to achieve the expected result without going through every individual pixel in a loop, checking each for transparency?

I guess this might be achievable through the use of commands? Anyone have any tips for using these? Unfortunately most commands seem to be undocumented…

hi, benpm!
i think that’s because drawImage can’t merge two images, just replace the old content with new one.
you may try using app.command.MergeDownLayer()

1 Like

thanks, ill try that!

how do i specify which layer to merge? does app.command.MergeDownLayer() take a layer index, or do i have to select it somehow?

yeah, you’ll need to select it and it will work just like layer → merge down would. i was looking at the aseprite/gui.xml at main · aseprite/aseprite · GitHub and there are no parameters.

how do you select a specific layer through the API? and how do you know which layer is selected?

sprite has an array of layers: api/sprite.md at main · aseprite/api · GitHub
so do the groups: api/layer.md at main · aseprite/api · GitHub (Layer.layers), i think you’d might be able to filter them out through Layer.name.
Also, you can get currently active layer with app.activeLayer api/app.md at main · aseprite/api · GitHub

right, but the MergeDownLayer() command takes no arguments. app.activeLayer only returns the active layer - but how do you set the active layer? ive tried app.command.GotoNextLayer(), but it doesnt seem to change the active layer - app.activeLayer.name is always the name of the first layer, no matter how many times i call GotoNextLayer.

with app.activeLayer = layer

ah thats it! thanks! i guess i just didnt expect that to work…

looks like its doing exactly what i want now:

here’s my working script in case anyone needs it:

local spr = app.sprites[1]
if not spr then return print "No sprite" end

-- Loop through all the sprite's layers and flatten groups
for _, layer in ipairs(spr.layers) do
    for _, l in ipairs(layer.layers) do
        app.activeLayer = l

spr:saveAs(string.format("%s_flattened.ase", string.match(spr.filename, "^(.*).ase$")))

nice! :+1:

1 Like