Created
May 20, 2025 12:23
-
-
Save ruccho/589615b38cc8abbb9648a8b4f7e56a7c to your computer and use it in GitHub Desktop.
Aseprite script that generates SDF (Signed Distance Field)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------------------------------------------------------- | |
-- Generate SDF | |
-- | |
-- It works only for RGB color mode. | |
---------------------------------------------------------------------- | |
if app.apiVersion < 1 then | |
return app.alert("Unsupported version") | |
end | |
local currentCel = app.activeCel | |
if not currentCel then | |
return app.alert("There is no active image") | |
end | |
local dlg = Dialog() | |
dlg:slider{ id="width", | |
label="Distance", | |
min=1, | |
max=16, | |
value=16 } | |
dlg:button{ id="confirm", text="Generate" } | |
dlg:button{ id="cancel", text="Cancel" } | |
dlg:show() | |
if dlg.data.confirm == false then | |
return | |
end | |
local width = dlg.data.width | |
local function processLayer(layer) | |
local sprite = app.activeSprite | |
local newLayerName = layer.name .. "_SDF" | |
local newLayer = nil | |
for i, layer in ipairs(sprite.layers) do | |
if layer.name == newLayerName then | |
newLayer = layer | |
end | |
end | |
if newLayer == nil then | |
newLayer = sprite:newLayer() | |
newLayer.name = newLayerName | |
end | |
for i, cel in ipairs(layer.cels) do | |
local frame = cel.frame | |
local img = Image(cel.image.width + width * 2, cel.image.height + width * 2) | |
local position = cel.position | |
if img.colorMode == ColorMode.RGB then | |
local rgba = app.pixelColor.rgba | |
local rgbaA = app.pixelColor.rgbaA | |
for it in img:pixels() do | |
local x = it.x - width | |
local y = it.y - width | |
local s = false | |
if x < 0 or y < 0 or x >= cel.image.width or y >= cel.image.height then | |
s = true | |
else | |
s = rgbaA(cel.image:getPixel(x, y)) < 255 | |
end | |
local nearest = width | |
for dx = -width, width do | |
for dy = -width, width do | |
local px = x + dx | |
local py = y + dy | |
local ps = false | |
if px < 0 or py < 0 or px >= cel.image.width or py >= cel.image.height then | |
ps = true | |
else | |
ps = rgbaA(cel.image:getPixel(px, py)) < 255 | |
end | |
if ps ~= s then | |
local d = math.sqrt(dx * dx + dy * dy) | |
if d < nearest then | |
nearest = d | |
end | |
end | |
end | |
end | |
if s then | |
nearest = -nearest | |
end | |
local value = 128 + nearest / width * 128 | |
local color = rgba(value, value, value, 255) | |
it(color) | |
end | |
elseif img.colorMode == ColorMode.GRAY then | |
return app.alert("This script is only for RGB Color Mode") | |
elseif img.colorMode == ColorMode.INDEXED then | |
return app.alert("This script is only for RGB Color Mode") | |
end | |
local newCel = sprite:newCel(newLayer, frame, img, Point(position.x - width, position.y - width)) | |
end | |
end | |
for i, layer in ipairs(app.range.layers) do | |
processLayer(layer) | |
end | |
app.refresh() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment