PixelPad - add a 1px border to tile atlas
Posted: Tue Sep 28, 2021 6:39 pm
This is a tool written in Love. It adds a 1px border to all tiles of a spritesheet. I don't know about you, but I'm no artist so I source my graphics online. They come in a large tileset with no padding between tiles. This is problematic for Love if you do any scaling etc, and I got tired of manually editing images. Save the below as main.lua in its own folder, adjust the infile, outfile, and tiles parameters (and optionally the color table), and run it. Don't compile it to a .love or it won't be able to access local images. Also note that it saves the new image in folder its run from. You should be able to specify a relative path as part of outfile if you like.
Enjoy!
Enjoy!
Code: Select all
-- Corrected image is saved in current path - NOT Love's default storage locations - caveat emptor!
-- USER INPUT REGION
local infile = "input.png" -- Accepts any Love-valid image type
local outfile = "output.png" -- Output filetype MUST be png (or tga)
local tiles = {w=32, h=32} -- Size in pixels of tiles in infile
local color = {1, 1, 1, 0} -- Border color (default is transparent white)
-- File Exists?
function exists(file)
local ok, err, code = os.rename(file, file)
if not ok and code == 13 then return true end -- Permission denied, but it exists
return ok, err
end
function love.load()
-- Check for overwrites
if infile == outfile then
local response = love.window.showMessageBox("Overwrite source file?", "Source file:\n"..infile.."\n\nAre you sure you want to overwrite it?", {"Yes", "No", enterbutton = 1}, "warning")
if response ~= 1 then return end -- love.event.quit() doesn't fire during love.load
elseif exists(outfile) then
local response = love.window.showMessageBox("File exists!", "Output file already exists:\n"..outfile.."\n\nOverwrite it?", {"Yes", "No", enterbutton = 1}, "warning")
if response ~= 1 then return end
end
-- Initialize
local image = {img=love.graphics.newImage(infile)}
image.w, image.h = image.img:getDimensions()
image.wTiles = image.w / tiles.w
image.hTiles = image.h / tiles.h
assert(image.wTiles == math.floor(image.wTiles) and image.hTiles == math.floor(image.hTiles), "Non-integer tiles in image "..infile.."\nSize: "..image.w.." x "..image.h.."\nTile size: "..tiles.w.." x "..tiles.h)
-- Initialize canvas
canvas = {w=image.wTiles*(tiles.w+1)+1, h=image.hTiles*(tiles.h+1)+1}
canvas.c = love.graphics.newCanvas(canvas.w, canvas.h)
canvas.q = love.graphics.newQuad(0, 0, tiles.w, tiles.h, image.w, image.h)
-- Render tiles with 1px border
love.graphics.setCanvas(canvas.c)
if color then love.graphics.clear(color) end
for x = 0, image.wTiles - 1 do
for y = 0, image.hTiles - 1 do
canvas.q:setViewport(x * tiles.w, y * tiles.h, tiles.w, tiles.h, image.w, image.h)
love.graphics.draw(image.img, canvas.q, x * (tiles.w + 1) + 1, y * (tiles.h + 1) + 1)
end
end
love.graphics.setCanvas()
-- Write image to local file
local data = canvas.c:newImageData()
data = data:encode("png")
local file = io.open(outfile, "w")
io.output(file)
io.write(data:getString())
io.close(file)
print("done!")
end
function love.draw()
if not canvas then
love.event.quit()
return
end
love.graphics.draw(canvas.c)
end