Skip to content

Instantly share code, notes, and snippets.

@dacap
Created December 11, 2019 12:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacap/92d4892b1885baf11fa98d073d82ca98 to your computer and use it in GitHub Desktop.
Save dacap/92d4892b1885baf11fa98d073d82ca98 to your computer and use it in GitHub Desktop.
WIP grafx2 API on Aseprite
----------------------------------------------------------------------
-- grafx2 compatibility by David Capello (C) 2018-2019
----------------------------------------------------------------------
local brush = nil
local spare = nil
local function getpicture()
return app.activeImage
end
local function getbrush()
if not brush then
brush = Image(1, 1, app.activeImage.colorMode)
end
return brush
end
local function getspare()
if not spare then
spare = Image(app.activeImage.spec)
end
return spare
end
local function getpal()
return app.activeSprite.palettes[1]
end
----------------------------------------------------------------------
-- Drawing
----------------------------------------------------------------------
-- putbrushpixel(x, y, c) set the color of pixel at coords (x, y) in the brush to c.
function putbrushpixel(x, y, c)
getbrush():drawPixel(x, y, c)
end
-- putpicturepixel(x, y, c) set the color of pixel at coords (x, y) in the picture to c.
function putpicturepixel(x, y, c)
getpicture():drawPixel(x, y, c)
end
-- putsparepicturepixel(x, y, c) set the color of pixel at coords (x, y) in the spare picture to c.
function putsparepicturepixel(x, y, c)
getspare():drawPixel(x, y, c)
end
-- drawline(x1,y1,x2,y2,c) draws a line in the picture.
-- drawfilledrect(x1,y1,x2,y2,c) draws a filled rectangle in the picture.
-- drawcircle(x1,y1,r,c) draws a circle in the picture. _r_ is radius in pixels.
-- drawdisk(x1,y1,r,c) draws a filled circle in the picture. _r_ is radius in pixels.
-- clearpicture(c) clears picture with color c.
function clearpicture(c)
getpicture():clear(c)
end
----------------------------------------------------------------------
-- Reading pixels
----------------------------------------------------------------------
-- getbrushpixel(x, y) returns the color of pixel at coords (x, y) in the brush.
function getbrushpixel(x, y)
return getbrush():getPixel(x, y)
end
-- getbrushbackuppixel(x, y) returns the color of pixel at coords (x, y) in the backup brush, before any of your changes.
-- getpicturepixel(x, y) returns the color of pixel at coords (x, y) in the picture. If there are several layers visible,this will pick "the color that you see".
-- getlayerpixel(x, y) returns the color of pixel at coords (x, y) in the current layer of the picture.
-- getbackuppixel(x, y) returns the color of pixel at coords (x, y) in the backup screen, that is, the picture before your script started to run.
-- getsparelayerpixel(x, y) returns the color of pixel at coords (x, y) in the current layer of the spare picture.
-- getsparepicturepixel(x, y) returns the color of pixel at coords (x, y) in the spare picture. If there are several layers visible, this will pick "the color that you see".
function getsparepicturepixel(x, y)
return getspare():getPixel(x, y)
end
-- Reading out of the brush will return the BackGround? color, ie. the one that marks transparent pixels in the brush.
----------------------------------------------------------------------
-- Changing sizes
----------------------------------------------------------------------
-- returns the brush size (w, h).
function getbrushsize()
local p = getbrush()
return p.width, p.height
end
-- sets the brush size. The new brush is initially filled with transparent pixels.
function setbrushsize(w, h)
brush = Image(w, h, getbrush().colorMode)
end
-- returns the picture size (w, h).
function getpicturesize()
local p = getpicture()
return p.width, p.height
end
-- sets the picture size. All layers are clipped accordingly. If you
-- have made changes on the picture, you should call finalizepicture()
-- first.
function setpicturesize(w, h)
local p = getpicture()
local i = Image(w, h, p.colorMode)
i:drawImage(p, 0, 0)
app.activeSprite:crop(0, 0, w, h)
app.activeCel.image = i
end
-- returns the spare image's size (w, h).
function getsparepicturesize()
local p = getspare()
return p.width, p.height
end
-- sets the spare picture size. All layers are clipped accordingly. If you have made changes on the picture, *you don't need to call finalizepicture()* first, this function does it by itself.
function setsparepicturesize(w, h)
spare = Image(w, h, getspare().colorMode)
end
----------------------------------------------------------------------
-- Palette and Colors
----------------------------------------------------------------------
-- getforecolor() returns the Foreground pen color (0-255).
function getforecolor()
return app.fgColor.index
end
-- getbackcolor() returns the Background pen color (0-255).
function getbackcolor()
return app.bgColor.index
end
-- setforecolor(c) sets the Foreground pen color (0-255).
function setforecolor(c)
app.fgColor = Color{ index=c }
end
-- setbackcolor(c) sets the Background pen color (0-255).
function setbackcolor(c)
app.bgColor = Color{ index=c }
end
-- gettranscolor() returns the picture's transparent color (0-255) for layers and GIF transparency.
function gettranscolor()
return app.activeSprite.transparentColor
end
-- setcolor(c,r,g,b) set color index c in palette to (r,g,b)
function setcolor(c,r,g,b)
local pal = getpal()
if c >= 1 and c <= #pal then
pal:setColor(c, Color{ red=r, green=g, blue=b })
end
end
-- returns the (r, g, b) value of color at index c.
function getcolor(c)
local pal = getpal()
if c >= 0 and c < #pal then
local v = pal:getColor(c)
return v.red, v.green, v.blue
else
return 0, 0, 0
end
end
-- matchcolor(r,g,b) return the index of the nearest color available in the palette.
-- matchcolor2(r,g,b) return the index of the nearest color available in the palette.
-- getbackupcolor(c) returns the (r, g, b) value of color at index c, from the original palette (before any changes done by your script).
-- getsparecolor(c) returns the (r, g, b) value of color at index c, from the spare's palette.
-- getsparetranscolor() returns the spare picture's transparent color (0-255) for layers and GIF transparency.
----------------------------------------------------------------------
-- Windows
----------------------------------------------------------------------
-- messagebox(message) or messagebox(window_title,message) Displays a multiline message. It performs word-wrapping automatically, but you can also include character \n in message to force some carriage-returns. If you need variables in the message, use Lua's concatenation operator .. (two dots) to assemble the message string.
function messagebox(title)
app.alert(title)
end
-- selectbox(caption,label_1,callback_1,label_2,callback_2) Opens a window where the user has to click on one of the buttons. You provide the button labels, and Grafx2 executes the associated callback, which must be a function : a pre-defined function (don't type the parentheses after function name) or an anonymous function that you build on the spot. The user can press Esc to cancel. Example:
-- selectbox("Menu",
-- "Sub-menu 1", sub_menu1_func,
-- "Sub-menu 2", sub_menu2_func,
-- "Say hello", function() messagebox("Hello"); end
-- );
function selectbox(title, ...)
local args = table.pack(...)
local d = Dialog(title)
for i = 1,#args,2 do
local buttonTitle = args[i]
local callback = args[i+1]
d:button{ text=buttonTitle,
onclick=function()
d:close()
callback()
end }
d:newrow()
end
d:show()
end
-- inputbox(window_title,label_1,initial_value_1,min_1,max_1,digits_1,...)
-- Opens a window that asks the user for one or several setting
-- values. The control only accepts values between the min and max
-- that you provide, and you can specify how many decimal places of
-- precision it should have with digits. You can ask for more than one
-- value by adding arguments: label_2, initial_value_2, min_2, max_2,
-- digits_2 etc, with a limit of 9 settings. This function returns one
-- value to tell if the user accepted or cancelled (true or false),
-- and one additional return value by setting. Example:
-- ok, w, h = inputbox("Modify brush size",
-- "Width", w, 1,100,0,
-- "Height", h, 1,100,0
-- );
-- If min and max are 0 and 1, and digits is 0, it will show a checkbox. Ex:
-- ok, xflip, yflip = inputbox("Transformation",
-- "X-Flip", 0, 0, 1,0,
-- "Y-Flip", 0, 0, 1,0
-- );
-- If min and max are 0 and 1, and digits is negative, it will show a radio button. Radio buttons with the same number of "digits" are grouped together. Ex:
-- ok, a, b ,c, d = inputbox("Your choice",
-- "A", 1, 0, 1,-1,
-- "B", 0, 0, 1,-1,
-- "C", 0, 0, 1,-1,
-- "D", 0, 0, 1,-1
-- );
-- If min and max are 0, the entry is just a label, the user can't input anything on this line.
function inputbox(title, ...)
local args = table.pack(...)
local d = Dialog(title)
local i = 1
for i = 1,#args,5 do
local label = args[i]
local initial_value = args[i+1]
local min = args[i+2]
local max = args[i+3]
local digits = args[i+4]
if min == 0 and max == 0 then
d:label{ label=label }
elseif min == 0 and max == 1 and digits == 0 then
d:check{ id=i, text=label }
elseif min == 0 and max == 1 and digits < 0 then
d:radio{ id=i, text=label }
else
d:slider{ id=i, label=label, value=initial_value, min=min, max=max }
end
end
d:button{ text="&OK", id="ok" }
d:button{ text="&Cancel" }
d:show()
local data = d.data
local array = { data.ok }
for k,v in ipairs(data) do
if k ~= "ok" then
table.insert(array, tonumber(k), v)
end
end
return table.unpack(array)
end
-- windowopen(w,h,label) Opens an empty window. It can then be populated using the functions below.
-- windowprint(x, y, text, foreground, background) prints some text in the window. The colors are in the range 0 to 3, from black to white.
-- windowbutton(x, y, w, h, label, key) Adds a button in the window, with the given label and shortcut key.
-- windowrepeatbutton(x, y, w, h, label, key) Adds a repeatable button. If the user holds the mouse button on it, events are generated repeatedly.
-- windowinput(x, y, nbchar) Creates a widget for text input. nbchar defines the width of it.
-- accept, val = windowreadline(x, y, value, nbchar, maxchar, decimal, inputtype) runs the text input procedure. x, y, nbchar should match the ones of a previously declared windowinput. nbchar defines the width of the control, while maxchar defines the max string length (the text can scroll if needed). This function blocks until the user is done editing the string. If the string is rejected (invalid format, or user pressed the escape key, accept is returned false. val is the new value of the string after editing.
-- windowslider(horizontal, x, y, height, nb_elements, thumb_height, initial_position) creates a slider/scroll bar.
-- windowmoveslider(slider, nb_elements, thumb_height, position) changes the position of a slider thumb.
-- button, button2, key = windowdodialog() waits for the user to interact with the open window. It returs the identifier of the widget clicked by the user, ???, and a keycode if any key was pressed.
-- windowclose() closes a window.
----------------------------------------------------------------------
-- Interactivity
----------------------------------------------------------------------
-- Forces a delay, in seconds (floating values are accepted, rounded to 0.01s). During this time, mouse can move, and if color cycling is active, you'll see it updated. If you use a delay of zero, the program only updates the mouse position and immediately continues. For safety, you can't request a delay of more than 10 seconds.
function wait(t)
end
-- Forces a delay, in seconds. Similar to wait(), except
-- that it returns early with a value of 1 if the user presses ESC,
-- otherwise 0 when the wait is over. waitbreak(0) is very useful, it
-- will only update mouse position (and color cycling if it's active)
-- and return 1 if ESC has been pressed since last call.
function waitbreak(t)
end
-- moved, key, mx, my, mb, px, py = waitinput(t) Waits for user
-- input. _moved_ is 1 if the mouse cursor moved, _key_ is set when
-- the user pressed a key, _mx_ and _my_ are the upadated mouse
-- coordinates on screen, and _mb_ is the mouse buttons state, ie 1
-- while left mouse button is pressed, and 2 while right mouse button
-- is pressed. _px_ and _py_ are the mouse coordinates in the picture
-- space.
-- Redraws the picture on the screen.
function updatescreen()
-- do nothing
end
-- statusmessage(message) Prints the given message in the status
-- bar. Use this when your script is doing long calculations, so the
-- user knows what is going on. Note the message is reset by
-- waitbreak(), so usually you have to display it again before each
-- call to updatescreen.
function statusmessage(message)
print(message)
end
----------------------------------------------------------------------
-- Others
----------------------------------------------------------------------
-- finalizepicture() ends your modifications in picture history. The
-- current state of the image (and palette) becomes the "backup", for
-- all functions that read backup state. This can be called multiple
-- times in a script, but remember the history size may be
-- limited. Don't use all of it.
-- (name, path) = getfilename() returns the picture name and the path
-- where it is saved. This is useful for saving data related to the
-- picture near to it, and finding it back later (or exporting it for
-- other uses)
-- selectlayer(1) select the layer or anim frame to use for pixel
-- access in the main page. If the layer doesn't exist, it throws an
-- error. There is no way to create a layer yet.
-- run(scriptname) calls another script. This is a lot like Lua's
-- built-in dofile(), but supports directories, and especially
-- relative paths: The called script will update its current directory
-- before running, and pop back to the original script's directory
-- afterwards.
function run(fn)
dofile(fn)
end
-- Sample script
-- Here is a very small sample script that generate a diagonal gradient.
-- -- get the size of the brush
-- w, h = getbrushsize()
-- -- Iterate over each pixel
-- for x = 0, w - 1, 1 do
-- for y = 0, h - 1, 1 do
-- -- Send the color for this pixel
-- putbrushpixel(x, y, (x+y)%256);
-- end
-- end
-- More reading
-- Lua is a well known programming language. Here are some pages from the internet you may want to look at for more information :
-- ​http://lua-users.org/wiki/MathLibraryTutorial Stuff about math.
-- ​http://lua-users.org/wiki/LuaDirectory The Lua wiki with a lot of pointers to informations.
-- ​http://code.google.com/p/grafx2/source/browse/#svn/trunk/share/grafx2/scripts The subversion holds a set of scripts you may use as a base for yours. You can send us your scripts if you want them to be added to the list.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment