Please add a feature where with a click of a button a silhouette is created from a sprite (on a separate frame or layer).
In case this feature request doesn’t get any traction, you could make a Lua script to implement the feature per your needs. Scripts can be assigned keyboard shortcuts from in the edit menu. For sample code, see below.
While not as convenient as one button press, there are some built-in tools that are also helpful:
- The lock alpha ink plus the the pencil or paint bucket tool.
- Hue/Saturation adjustment can make silhouettes if you set the HSL lightness to -100 or +100. (RGB color mode only. In Grayscale it seems to work differently. In Indexed it targets the palette, not the canvas.)
- A selection can be made around non-zero alpha pixels in a cel image by holding down
Ctrl
and clicking on a layer’s name in the timeline. (It can be finicky, though, if the layer is already active or selected in a range.) There are also Lua scripts/plugins that use do the same with a hotkey.
Test image: Chun-Li from Street Fighter Chun-Li/Sprites | Street Fighter Wiki | Fandom
local activeSprite = app.activeSprite
if not activeSprite then return end
-- Unpack sprite spec.
local spec = activeSprite.spec
local colorMode = spec.colorMode
local alphaIndex = spec.transparentColor
local bkgLayer = activeSprite.backgroundLayer
if colorMode ~= ColorMode.INDEXED
and bkgLayer and bkgLayer.isVisible then
app.alert { title = "Error", text = "Sprite has an opaque background." }
return
end
-- Base silhouette color on foreground color.
local silhColor = app.fgColor
-- For RGB color mode.
local rSilh = silhColor.red
local gSilh = silhColor.green
local bSilh = silhColor.blue
local silhAbgr32 = app.pixelColor.rgba(rSilh, gSilh, bSilh, 255)
local silhBgr32 = silhAbgr32 & 0x00ffffff
-- For gray color mode.
-- Aseprite formula for luma gray conversion:
local gray = (rSilh * 2126 + gSilh * 7152 + bSilh * 722) // 10000
local silhAv16 = app.pixelColor.graya(gray, 255)
local silhV8 = silhAv16 & 0x00ff
-- For indexed color mode.
local silhIndex = silhColor.index
if silhIndex == alphaIndex or silhColor.alpha <= 0 then
local palettes = activeSprite.palettes
local palette = palettes[1]
local lenPalette = #palette
local h = 0
while h < lenPalette do
if h ~= alphaIndex and palette:getColor(h).alpha > 0 then
silhIndex = h
break
end
h = h + 1
end
end
app.transaction(function()
local silhLayer = activeSprite:newLayer()
silhLayer.name = "Silhouette"
local frames = activeSprite.frames
local lenFrames = #frames
local i = 0
while i < lenFrames do
i = i + 1
local frame = frames[i]
local flattened = Image(spec)
flattened:drawSprite(activeSprite, frame)
if colorMode == ColorMode.INDEXED then
for pixel in flattened:pixels() do
if pixel() ~= alphaIndex then
pixel(silhIndex)
else
pixel(alphaIndex)
end
end
elseif colorMode == ColorMode.GRAY then
for pixel in flattened:pixels() do
local sourceAv16 = pixel()
pixel(sourceAv16 & 0xff00 | silhV8)
end
else
for pixel in flattened:pixels() do
local sourceAbgr32 = pixel()
pixel(sourceAbgr32 & 0xff000000 | silhBgr32)
end
end
activeSprite:newCel(silhLayer, frame, flattened)
end
end)
The foreground color is used as the silhouette color. This creates a silhouette for all frames, not just the active frame. The silhouette images are not trimmed of extra alpha, though they could be either with app.command.CanvasSize or with a function dependent on Image:shrinkBounds (in newer versions of Aseprite).
1 Like