Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
An Aseprite script to export all frames of every layer as individual sprites.
--[[
Description:
A script to save all different layers in different .png files.
Made by Gaspi.
- Itch.io: https://gaspi.itch.io/
- Twitter: @_Gaspi
--]]
-- Auxiliar functions.
function getPath(str,sep)
-- Source: https://stackoverflow.com/questions/9102126/lua-return-directory-path-from-path
sep=sep or'/'
return str:match("(.*"..sep..")")
end
function getFileName(str,sep)
--[[ Sources:
- https://codereview.stackexchange.com/questions/90177/get-file-name-with-extension-and-get-only-extension
- https://stackoverflow.com/questions/18884396/extracting-filename-only-with-pattern-matching
--]]
str = str:match("^.+"..sep.."(.+)$")
return str:match("(.+)%..+")
end
-- Hides all layers and sublayers inside a group, returning a list with all initial states of each layer's visibility.
function hideLayers(sprite)
local layerVisibility = {}
for i,layer in ipairs(sprite.layers) do
-- Avoid group layers.
if (not layer.isGroup) then
layerVisibility[i] = layer.isVisible
layer.isVisible = false
else
layerVisibility[i] = hideLayers(layer)
end
end
return layerVisibility
end
-- Restore layers visibility.
function restoreLayersVisibility(layerVisibility, sprite)
for i,layer in ipairs(sprite.layers) do
-- Avoid group layers.
if (not layer.isGroup) then
layer.isVisible = layerVisibility[i]
else
restoreLayersVisibility(layerVisibility[i], layer)
end
end
end
-- Save the layers as individual sprites.
function exportLayers(sprite, rootLayer, pathPrefix, pathSufix)
for i,layer in ipairs(rootLayer.layers) do
if (not layer.isGroup) then
-- Individual layer. Save it.
layer.isVisible = true
local layerName = "_" .. string.lower(layer.name)
sprite:saveCopyAs(pathPrefix .. layerName .. pathSufix .. ".png")
layer.isVisible = false
else
-- This is a group. of layers.
exportLayers(sprite, layer, pathPrefix .. "_" .. layer.name, pathSufix)
end
end
end
-- Identify current sprite.
local sprite = app.activeSprite
if (sprite == nil) then
-- Show error, no sprite active.
local dlg = Dialog("Error")
dlg:label{ id = 0,
text = "No sprite is currently active. Please, open a sprite first and run the script with it active."
}
dlg:newrow()
dlg:button{ id = 1,
text = "Close",
onclick = function()
dlg:close()
end
}
dlg:show()
return
end
-- Path where sprites are saved.
local spritePath = sprite.filename
-- Identify operative system.
local separator
if (string.sub(spritePath, 1, 1) == "/") then
separator = "/"
else
separator = "\\"
end
local spriteName = getFileName(spritePath, separator)
local path = getPath(spritePath, separator) .. spriteName .. separator
-- Add a '_' to the filename if it has multiple frames
local multipleFrames = ""
if (#sprite.frames > 1) then
multipleFrames = "_"
end
local layerVisibility = hideLayers(sprite)
exportLayers(sprite, sprite, path .. spriteName, multipleFrames)
restoreLayersVisibility(layerVisibility, sprite)
@MadeBySaints

This comment has been minimized.

Copy link

@MadeBySaints MadeBySaints commented Dec 6, 2019

This works great, however I'm leaving a comment because i cant create an issue. This script creates many folders that are unnecessary, and they are created based on how many words are in the parent folder. for instance, if i have a folder called 'player model - base' it will create 4 folders one called player, one model, one -, and one base folder. There are CLI commands to do this process. would it be easier to call a CLI command inside the script?

@rapsaGnauJ

This comment has been minimized.

Copy link
Owner Author

@rapsaGnauJ rapsaGnauJ commented Dec 8, 2019

This works great, however I'm leaving a comment because i cant create an issue. This script creates many folders that are unnecessary, and they are created based on how many words are in the parent folder. for instance, if i have a folder called 'player model - base' it will create 4 folders one called player, one model, one -, and one base folder. There are CLI commands to do this process. would it be easier to call a CLI command inside the script?

Thank you for your reporting. I have now updated the script and it should no longer create unnecessary folders.

@MadeBySaints

This comment has been minimized.

Copy link

@MadeBySaints MadeBySaints commented Dec 8, 2019

Thank you for your reporting. I have now updated the script and it should no longer create unnecessary folders.

Working as expected, no more extra folders. Excellent work! Super useful when you have actors with more than 5 layers.

@2kCarlos

This comment has been minimized.

Copy link

@2kCarlos 2kCarlos commented Apr 17, 2020

This is super helpful, I can confirm this works! :)

@Imaginesto

This comment has been minimized.

Copy link

@Imaginesto Imaginesto commented Jun 5, 2020

This Script is not working for me. Looking for some help. With every asset separated on a different layer in Aseprite, it still only seems to export a flattened image. Its trying to export but only exports 7 images with each having a slight change of which layer is visible.
Annotation layer export not working

@AdroitCell

This comment has been minimized.

Copy link

@AdroitCell AdroitCell commented Aug 14, 2020

I love this and works great for me! However I found that it doesn't export layers in groups, is there some way to do it with groups?

@rapsaGnauJ

This comment has been minimized.

Copy link
Owner Author

@rapsaGnauJ rapsaGnauJ commented Aug 16, 2020

I love this and works great for me! However I found that it doesn't export layers in groups, is there some way to do it with groups?

Thank you for your report, but I'm not quite sure what do you mean. Is it that layers inside a group do not get exported or that they aren't exported grouped?

@AdroitCell

This comment has been minimized.

Copy link

@AdroitCell AdroitCell commented Aug 16, 2020

Thank you for your report, but I'm not quite sure what do you mean. Is it that layers inside a group do not get exported or that they aren't exported grouped?

Yep! if they're in groups they don't get exported completely so I had to move them out of their groups before they get exported.

@rapsaGnauJ

This comment has been minimized.

Copy link
Owner Author

@rapsaGnauJ rapsaGnauJ commented Aug 16, 2020

Yep! if they're in groups they don't get exported completely so I had to move them out of their groups before they get exported.

Thanks again for the feedback! I remember that the script had the same issue a long time ago, but I recall fixing it. It turns out that due to a few changes on the Aseprite's API it doesn't work again. I made some changes and hopefully it works again now!

@Imaginesto

This comment has been minimized.

Copy link

@Imaginesto Imaginesto commented Aug 18, 2020

Thanks for responding to feedback and maintaining this code for everyone! :D Do you think there is a way to add a cropping factor to this script? So that when you export the layers, they crop to eliminate the excess white padding of the full size canvas
?

@rapsaGnauJ

This comment has been minimized.

Copy link
Owner Author

@rapsaGnauJ rapsaGnauJ commented Aug 18, 2020

Thanks for responding to feedback and maintaining this code for everyone! :D Do you think there is a way to add a cropping factor to this script? So that when you export the layers, they crop to eliminate the excess white padding of the full size canvas
?

Sorry but that looks very specific and not between my capabilities at all.

@pichlerer

This comment has been minimized.

Copy link

@pichlerer pichlerer commented Dec 19, 2020

Just leaving a comment to say thank you! :) I'm a bit baffled that aseprite doesn't have this as a built-in feature, it's so useful!

@ekangmonyet

This comment has been minimized.

Copy link

@ekangmonyet ekangmonyet commented Dec 25, 2020

I've patched it to export only visible layers, might not be suitable to be upstreamed so here:

@@ -50,17 +50,19 @@
 end
    
 -- Save the layers as individual sprites.
-function exportLayers(sprite, rootLayer, pathPrefix, pathSufix)
+function exportLayers(layerVisibility, sprite, rootLayer, pathPrefix, pathSufix)
    for i,layer in ipairs(rootLayer.layers) do
       if (not layer.isGroup) then
          -- Individual layer. Save it.
-         layer.isVisible = true
-         local layerName = "_" .. string.lower(layer.name)
-         sprite:saveCopyAs(pathPrefix .. layerName .. pathSufix .. ".png")
-         layer.isVisible = false
+         if (layerVisibility[i]) then
+             layer.isVisible = true
+             local layerName = "_" .. string.lower(layer.name)
+             sprite:saveCopyAs(pathPrefix .. layerName .. pathSufix .. ".png")
+             layer.isVisible = false
+        end
       else
          -- This is a group. of layers.
-         exportLayers(sprite, layer, pathPrefix .. "_" .. layer.name, pathSufix)
+         exportLayers(layerVisibility[i], sprite, layer, pathPrefix .. "_" .. layer.name, pathSufix)
       end
    end
 end
@@ -104,6 +106,6 @@
 
 local layerVisibility = hideLayers(sprite)
 
-exportLayers(sprite, sprite, path .. spriteName, multipleFrames)
+exportLayers(layerVisibility, sprite, sprite, path .. spriteName, multipleFrames)
 
 restoreLayersVisibility(layerVisibility, sprite)
@guitarmike

This comment has been minimized.

Copy link

@guitarmike guitarmike commented Jan 10, 2021

Very helpful. Thank you very much!

@depict1

This comment has been minimized.

Copy link

@depict1 depict1 commented Feb 13, 2021

Hey there! Are you still doing commissions? I have a hopefully simple one that I’d love to see if possible. Any way I can contact you?

@rapsaGnauJ

This comment has been minimized.

Copy link
Owner Author

@rapsaGnauJ rapsaGnauJ commented Feb 13, 2021

Hey there! Are you still doing commissions? I have a hopefully simple one that I’d love to see if possible. Any way I can contact you?

Hi! Yes, I do! You can DM me on twitter, @_Gaspi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment