This post could fall under both the scripts and feature request category.
I noticed that when I import a .gif with a transparent background, for example,
into Aseprite, the cel images (or layer edges) are not closely cropped to exclude transparent pixels. I’m using version 1.3-beta6 on Windows 10.
To show what I mean, when I hold down the
Ctrl key (or go to
View > Show > Layer Edges), I expect to see this:
This might not seem all that important. But any Lua script that iterates over a cel image’s pixels is performance sensitive; such scripts need to be handed as little work to do as possible.
---Creates a copy of the image where excess ---transparent pixels have been trimmed from ---the edges. Adapted from the Stack Overflow ---implementation by Oleg Mikhailov: ---https://stackoverflow.com/a/36938923 . ---Returns a tuple containing the cropped image, ---the top left x and top left y. The top left ---should be added to the position of the cel ---that contained the source image. ---@param image table aseprite image ---@return table ---@return number ---@return number function AseUtilities.trimImageAlpha(image) local width = image.width local height = image.height local left = 0 local top = 0 local right = width - 1 local bottom = height - 1 local minRight = width - 1 local minBottom = height - 1 local breakTop = false for t = top, bottom - 1, 1 do for x = 0, width - 1, 1 do if image:getPixel(x, t) & 0xff000000 ~= 0 then minRight = x minBottom = t top = t breakTop = true break end end if breakTop then break end end local breakLeft = false for l = left, minRight - 1, 1 do for y = height - 1, top + 1, -1 do if image:getPixel(l, y) & 0xff000000 ~= 0 then minBottom = y left = l breakLeft = true break end end if breakLeft then break end end local breakBottom = false for b = bottom, minBottom + 1, -1 do for x = width - 1, left, -1 do if image:getPixel(x, b) & 0xff000000 ~= 0 then minRight = x bottom = b breakBottom = true break end end if breakBottom then break end end local breakRight = false for r = right, minRight, -1 do for y = bottom, top, -1 do if image:getPixel(r, y) & 0xff000000 ~= 0 then right = r breakRight = true break end end if breakRight then break end end local trgWidth = 1 + (right - left) local trgHeight = 1 + (bottom - top) local target = Image(trgWidth, trgHeight) local sampleRect = Rectangle(left, top, trgWidth, trgHeight) local srcItr = image:pixels(sampleRect) for elm in srcItr do target:drawPixel(elm.x - left, elm.y - top, elm()) end return target, left, top end
Then I used this in the following way:
dofile("../support/aseutilities.lua") local activeSprite = app.activeSprite if activeSprite then local cels = activeSprite.cels local celsLen = #cels local trimImage = AseUtilities.trimImageAlpha for i = 1, celsLen, 1 do local cel = cels[i] local srcPos = cel.position local srcImg = cel.image if srcImg then local trgImg, x, y = trimImage(srcImg) cel.position = Point(srcPos.x + x, srcPos.y + y) cel.image = trgImg end end app.refresh() else app.alert("There is no active sprite.") end
If any of this was part of the GUI or scripting API and I just didn’t realize it, whoops! My bad! Feel free to disregard this post. Otherwise, on to the feature requests:
I think it’d be nice if getting a subset of an image were part of the scripting API. In other words, to replace the need for this mess:
local target = Image(trgWidth, trgHeight) local sampleRect = Rectangle(left, top, trgWidth, trgHeight) local srcItr = image:pixels(sampleRect) for elm in srcItr do target:drawPixel(elm.x - left, elm.y - top, elm()) end
This could be a new method or could be added to existing functions like the constructor –
Image(sourceImage, x, y, w, h) – or to clone –
sourceImage:clone(x, y, w, h) – where
y default to
h default to the source image’s width and height. You could also specify the parameters as top-left x and y and bottom-right x and y.
And then secondly, the trim or crop routine above would probably be faster if done in C++, not Lua.
What I don’t know is whether it’s as important for general Aseprite users working via the GUI as it is for scripters. Do people notice or care if an imported image doesn’t have close-cropped cel images?
[Edit: Changing the canvas size with the
Trim content Outside the canvas checkbox marked as true will trim a cel image smaller than sprite bounds, but it’s not exactly what I have in mind. It’s possible for a cel to have image data that extends beyond the canvas, and this data would be lost.]
I case you wanted more motivation for why I’m posting this: I thought this thread on baking Onion Skins was a cool idea and tried writing a script for it. Using Akuma from Street Fighter Alpha 2 ( source ) as a test, I could make this well enough,
even though the script was slow. This, however, is more sophsiticated and requires a bigger refactor to make it easier to create:
All that I wrote above about trimming cel images came about from hunting the sources of slow-down in the onion skinning script.
Thanks for reading! Have a good weekend all.