Skip to content

Instantly share code, notes, and snippets.

@stillwwater
Created December 21, 2020 02:59
Show Gist options
  • Select an option

  • Save stillwwater/acebb2b47bef240501a05da92aaa37c1 to your computer and use it in GitHub Desktop.

Select an option

Save stillwwater/acebb2b47bef240501a05da92aaa37c1 to your computer and use it in GitHub Desktop.
Aseprite exporter for texture atlas files
------------------------------------------------------------------------
-- Export texture atlas file format
--
-- The file format is as follows:
--
-- # version VERSION_NUMBER
-- # ASEPRITE_FILE
-- i IMAGE_FILE NUMBER_OF_FRAMES
-- s SPRITE_X SPRITE_Y SPRITE_W SPRITE_H SPRITE_PIVOT_X SPRITE_PIVOT_Y
-- a ANIM_NAME ANIM_START ANIM_END ANIM_DIRECTON ANIM_FRAME_TIME_SECONDS
--
-- Do not use spaces in filenames!
-------------------------------------------------------------------------
local Version = 1
local json = dofile("lib/json.lua")
local function renameWithExtension(path, extension)
return app.fs.filePathAndTitle(path) .. "." .. extension
end
local function tempJsonFilename(filename)
return app.fs.joinPath(app.fs.tempPath, app.fs.fileTitle(filename) .. ".json")
end
local function nextPowerOfTwo(value)
return 2 ^ math.ceil(math.log(value) / math.log(2))
end
local function exportSpriteSheet(sprite, trimSprites, showUI, imFormat, w, h)
app.command.ExportSpriteSheet {
ui = showUI,
askOverwrite = false,
type = SpriteSheetType.PACKED,
columns = 0,
rows = 0,
width = w,
height = h,
bestFit = false,
textureFilename = renameWithExtension(sprite.filename, imFormat),
dataFilename = tempJsonFilename(sprite.filename),
dataFormat = SpriteSheetDataFormat.JSON_ARRAY,
borderPadding = 0,
shapePadding = 0,
innerPadding = 0,
trim = trimSprites,
extrude = false,
openGenerated = false,
layer = "",
tag = "",
splitLayers = false,
listLayers = true,
listTags = true,
listSlices = true
}
end
local function spriteSheetSize(sprite)
local atlasInput = io.open(tempJsonFilename(sprite.filename), "r")
if atlasInput == nil then
app.alert("Error: Could not open sprite sheet json file")
return
end
local data = json.decode(atlasInput:read("a"))
return {width = data.meta.size.w, height = data.meta.size.h}
end
local function exportAtlasFile(sprite, imFormat, pivotX, pivotY)
local atlasFilename = renameWithExtension(sprite.filename, "atlas")
local textureFilename = app.fs.fileTitle(sprite.filename) .. "." .. imFormat
local atlasOutput = io.open(atlasFilename, "w+")
local atlasInput = io.open(tempJsonFilename(sprite.filename), "r")
if atlasInput == nil then
app.alert("Error: Could not open sprite sheet json file %s")
return
end
local data = json.decode(atlasInput:read("a"))
io.output(atlasOutput)
-- Header
io.write("# version" .. Version .. "\n")
io.write("# " .. app.fs.fileName(sprite.filename) .. "\n")
io.write(string.format("i %s %d\n", textureFilename, #data.frames))
-- Frames
for i, v in ipairs(data.frames) do
io.write(string.format("s %d %d %d %d %.2f %.2f\n",
v.frame.x, v.frame.y, v.frame.w, v.frame.h, pivotX, pivotY))
end
-- Animations
local animationFrames = 0;
local directionMap = {forward = "Forward", pingpong = "PingPong"}
for i, v in ipairs(data.meta.frameTags) do
local name = v.name:gsub(" ", "_")
local direction = directionMap[v.direction]
local frameTimeS = data.frames[v.from + 1].duration / 1000.0
if direction == nil then
app.alert("Warning: Animation direction %s is not supported", v.direction)
end
io.write(string.format("a %s %d %d %s %.3f\n", name, v.from, v.to, direction, frameTimeS))
animationFrames = animationFrames + (v.to - v.from) + 1
end
if animationFrames ~= #data.frames then
app.alert("Warning: Missing animation tags on some frames")
end
io.close(atlasOutput)
return atlasFilename
end
local function exportAtlas(requirePowerOfTwoSize, trimSprites, showUI, imFormat, pivotX, pivotY)
local sprite = app.activeSprite
exportSpriteSheet(sprite, trimSprites, showUI and not requirePowerOfTwoSize, imFormat, 0, 0)
if requirePowerOfTwoSize then
local size = spriteSheetSize(sprite)
local w = nextPowerOfTwo(size.width)
local h = nextPowerOfTwo(size.height)
exportSpriteSheet(sprite, trimSprites, showUI, imFormat, w, h)
end
local atlasFilename = exportAtlasFile(sprite, imFormat, pivotX, pivotY)
end
local function onExport(dlg)
exportAtlas(dlg.data.pow2, dlg.data.trimSprites, dlg.data.preview, dlg.data.imFormat,
dlg.data.pivotX / 100.0, dlg.data.pivotY / 100.0)
dlg:close()
local prefsFile = io.open(app.fs.joinPath(app.fs.tempPath, "atlas_exporter_cache.json"), "w+")
io.output(prefsFile)
io.write(json.encode(dlg.data))
io.close(prefsFile)
end
local function showExportDialog()
local prefsFile = io.open(app.fs.joinPath(app.fs.tempPath, "atlas_exporter_cache.json"), "r")
local prefs = {
pow2 = true,
trimSprites = true,
preview = false,
imFormat = "png",
pivotX = "0",
pivotY = "0"
}
if prefsFile ~= nil then
prefs = json.decode(prefsFile:read("a"))
io.close(prefsFile)
end
local dlg = Dialog("Export Atlas")
local imFormatOptions = {"png", "tga", "bmp"}
dlg:combobox{id = "imFormat", label = "Image Format",
options = prefs.imFormat, options = imFormatOptions}
dlg:number{id = "pivotX", label = "Pivot", text = tostring(prefs.pivotX)}
dlg:number{id = "pivotY", text = tostring(prefs.pivotY)}
dlg:check{id = "pow2", text = "Power Of 2", selected = prefs.pow2}
dlg:newrow()
dlg:check{id = "trimSprites", text = "Trim Sprites", selected = prefs.trimSprites}
dlg:newrow()
dlg:check{id = "preview", text = "Preview", selected = prefs.Preview}
dlg:newrow()
dlg:separator()
dlg:button{id = "ok", text = "&Export", focus = true, onclick = function() onExport(dlg) end}
dlg:button{id = "cancel", text = "&Cancel", focus = false, onclick = function () dlg:close() end}
dlg:show {wait = false}
end
if app.isUIAvailable then
showExportDialog()
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment