Skip to content

Instantly share code, notes, and snippets.

@pancelor
Last active April 17, 2024 13:14
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pancelor/43512028087bf34e5d9773a61a03f93a to your computer and use it in GitHub Desktop.
Save pancelor/43512028087bf34e5d9773a61a03f93a to your computer and use it in GitHub Desktop.
aseprite to pico8/picotron exporter

picotron is in early alpha -- it doesn't seem to have a sprite editor yet but it does support sprites in a particular format, so I threw together this aseprite exporter.

picotron is out! importing sprites is still a bit tricky, so I built this script to help, along with this picotron cart

this script works great for pico8 too -- I use it often

how to use

you'll need Aseprite to use this.

  1. save this script to your aseprite scripts folder (File > Scripts > Open Scripts Folder) then reopen aseprite (or rescan scripts)
  2. load an image with the picotron palette (or pico-8 extended palette)
  3. (optional) change the image's color mode to "indexed" (Sprite > Color Mode > Indexed)
  • if you skip this step then the closest color in your palette will be used for each pixel
  1. launch this script, press "Export" to copy to clipboard. (alt-e should work too)
  • if there is a current selection, it will only copy that region
  • leave the script window open to copy again later
  • you can choose an export format: "pod" (for picotron) or "gfx" (for picotron or pico8)
  1. the string in your clipboard should look something like this:
  • gfx format: [gfx]08080000000000000000000000000700707007777007717177700777777000607070[/gfx]. This can be pasted into the pico8 or picotron sprite editors.
  • pod format: --[[pod,pod_type="image"]]userdata("u8",8,8,"00000000000000000000000000000000000000000000000000070000070007000007070707000007070107010707070000070707070707000000060007000700"). This can be pasted into the picotron sprite editor, or pasted into code, or pasted in a text file or a --[[multiline code comment]] (it will be drawn!) For other options, see the picotron alpha release notes.

changelog

  • 2024-04-07: fix bug with merge-all-layers
  • 2024-03-23: add support for pod format (this allows for images larger than 256x256)
  • 2024-03-22: fixed a bug where images with empty space around them would not export correctly
  • 2024-03-17: here's a tool for the other end, to import a spritesheet into picotron: https://www.lexaloffle.com/bbs/?tid=140800
-- Pico[8|tron] Export
-- by pancelor
-- a script to export sprites (whole image or current selection)
-- in the pico8 format, e.g.
-- [gfx]08080000000000000000000000000700707007777007717177700777777000607070[/gfx]
-- this can be pasted into pico8 or picotron
--[[
# helpers
]]
local os_windows = pcall(function() io.popen('cd') end) --replace this whole thing with true/false if you want
--print(os_windows)
--local os_windows = pcall(function() io.popen('cd') end) --replace this whole thing with true/false if you want
local os_windows = false
--print(os_windows)
function add(tab,elem)
table.insert(tab,elem)
return elem
end
-- 0=>"0", ... 15=>"f", 16=>"g", ... 31=>"v"
local function picohex(val)
if 0<=val and val<=9 then
return string.char(0x30+val)
elseif 10<=val and val<=31 then
return string.char(97+val-10)
else
assert(nil,"bad val for picohex: "..val)
end
end
local function export_pixels(cel,rect, mapper)
local res={}
mapper=mapper or function(...) return ... end
for y=rect.y,rect.y+rect.height-1 do
for x=rect.x,rect.x+rect.width-1 do
local ix=0
if 0<=x and x<cel.image.width and 0<=y and y<cel.image.height then
ix = Color(cel.image:getPixel(x,y)).index -- .index chooses the closest color in the current palette
-- ix = app.pixelColor.tileI(cel.image:getPixel(x,y))
end
add(res,mapper(ix))
end
end
return res
end
-- pico8 format (picotron can read it too)
local function export_gfx(cel,rect)
local build=export_pixels(cel,rect,picohex)
local res=string.format("[gfx]%02x%02x%s[/gfx]",rect.width,rect.height,table.concat(build,""))
return res
end
-- picotron format
local function export_pod(cel,rect)
local build=export_pixels(cel,rect,function(ix) return string.format("%02x",ix) end)
local res=string.format('--[[pod,pod_type="image"]]userdata("u8",%d,%d,"%s")',rect.width,rect.height,table.concat(build,""))
return res
end
-- copy string to host clipboard
-- https://community.aseprite.org/t/solved-copy-string-within-aseprite-extension/16344
local function xsel(str)
if os_windows then
io.popen('clip','w'):write(str):close()
else
-- io.popen('xsel -b','w'):write(str):close() -- PicoExport.lua:100: 'popen' not supported
print(str)
end
end
--[[
# main
]]
local dlg
function main()
local cel=app.cel or app.activeCel -- https://www.aseprite.org/api/app#appactivecel
if not cel then return app.alert("error: no sprite found") end
-- rect: the subrectangle to export tiles from
local spr=app.sprite or app.activeSprite
local rect=spr.selection.isEmpty and spr.bounds or spr.selection.bounds
rect.x=rect.x-cel.position.x -- the cel's position is different from the absolute xy position: https://www.aseprite.org/api/image#imagegetpixel
rect.y=rect.y-cel.position.y
if dlg.data.format=="gfx" then
if rect.width>=256 or rect.height>=256 then
return app.alert("sprite is too big for gfx format; use pod format instead")
end
xsel(export_gfx(cel,rect))
elseif dlg.data.format=="pod" then
xsel(export_pod(cel,rect))
end
end
dlg = Dialog("Pico Export")
dlg:combobox{
id = "format",
label = "Format",
options = {"pod", "gfx"},
option = "gfx", --default
}
dlg:check{
id = "merge",
label = "All Layers",
selected = false, --default
}
dlg:button{text="&Export", onclick=function()
if dlg.data.merge then
app.transaction(function()
app.command.FlattenLayers{visibleOnly=true}
end)
main()
app.command.Undo()
else
main()
end
end}
if not os_windows then
dlg:label{text="(then ctrl-c)"}
end
dlg:show{wait=false}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment