butterfly is an object-oriented 2D graphics library for Lua, targeting the Quartz graphics engine.
-
Build and install the library and header files:
make && make install
You can specify the deployment target using the
MACOSX_DEPLOYMENT_TARGET
environment variable, for exampleexport MACOSX_DEPLOYMENT_TARGET=10.13
. -
Set the Xcode build settings for your target:
- Add
/usr/local/include
to Header Search Paths (HEADER_SEARCH_PATHS
). - Add
/usr/local/lib/libbutterfly.a
to Other Linker Flags (OTHER_LDFLAGS
).
- Add
-
Load butterfly graphics classes in your Lua state:
- Add
#include <butterfly/lua.h>
to the file where you initialize your Lua state. - Call
bf_lua_load
to set up the globals and metatables for the butterfly graphics classes.
- Add
-
Create a canvas object for your Lua code to draw into:
- Add
#include <butterfly/quartz.h>
. - Call
BFCanvasMetricsCreate
andBFCanvasCreateForDisplay
to create a butterfly canvas from a Quartz graphics context. - Call
bf_lua_push
to push the canvas onto the Lua stack. You can use Lua APIs likelua_setglobal
orlua_pcall
to assign the canvas to a global variable or call a function passing it as a parameter.
- Add
-
Draw into the canvas from your Lua scripts.
The bf_lua_load
C function installs the following global variables in the Lua state:
Color
Font
Gradient
Icon
PaintMode
Path
StyledString
Transformation
A canvas represents a Quartz graphics context that can be drawn to. This can be a view or an offscreen image. Unlike the other classes which can be instantiated from Lua scripts, canvases must be provided to Lua from the host environment.
canvas:setPaint(color)
canvas:setFont(font)
canvas:setOpacity(opacity)
canvas:setThickness(thickness)
canvas:concatTransformation(transformation)
canvas:fill(path)
canvas:stroke(path)
canvas:drawText(text, x, y)
canvas:strokeText(text, x, y)
local color = Color.rgba(red, green, blue, alpha)
red
, green
, blue
, and alpha
range from 0 to 1.
canvas:setPaint(color)
Applies the color to subsequent drawing operations in the canvas.
local params = { name = 'Comic Sans MS', size = 18 }
local font = Font.get(params)
In addition to the font name and size, the parameters can include the following key-value pairs to request additional font features if they’re supported by the font:
lowercase = 'smallCaps'
numberCase = 'lowercase'
ornumberCase = 'uppercase'
numberSpacing = 'proportional'
ornumberSpacing = 'monospaced'
local systemFont = Font.system(size)
local boldSystemFont = Font.boldSystem(size)
canvas:setFont(font)
Applies the font to subsequent text drawing operations in the canvas.
Also see Creating a styled string.
local path = Path.new()
path:addSubpath({ x = x, y = y })
Starts a new subpath starting at x
and y
.
path:addLine({ x = x, y = y })
Continues from the current point to x
and y
.
path:addCurve({ cx1 = cx1, cy1 = cy1, cx2 = cx2, cy2 = cy2, x = x, y = y })
Adds a cubic Bézier curve using the specified control points and ending at x
and y
.
path:closeSubpath()
Returns to the starting point of the current subpath and closes the subpath.
path:addRect({ left = left, bottom = bottom, right = right, top = top }, radius)
Adds a new subpath for a rectangle with the specified boundaries. radius
is optional and if specified will produce a rounded rectangle.
path:addOval({ left = left, bottom = bottom, right = right, top = top })
Adds a new subpath for an oval with the specified boundaries.
A path is not drawn until it’s passed to the canvas fill
or stroke
method:
canvas:fill(path)
canvas:stroke(path)
local params = { font = font }
local styledString = StyledString.new(string, params)
local styledString = styledString1 .. styledString2
canvas:drawText(styledString, x, y)
canvas:strokeText(styledString, x, y)
local transformation = Transformation.identity()
transformation:translate(x, y)
transformation:scale(multiple)
transformation:rotate(radians)
transformation:concat(anotherTransformation)
canvas:concatTransformation(transformation)
Applies the transformation to subsequent drawing operations in the canvas. It’s often a good idea to put this in a preserve
block so that you can easily return to the original coordinate system:
canvas:preserve(function(canvas)
canvas:concatTransformation(transformation)
-- drawing commands here use the transformed coordinate system
end)
-- drawing commands here use the original coordinate system
make lua2png
./lua2png <width> <height> <input.lua> <output.png>
The Lua script returns a function taking a canvas object as its only argument. For example:
return function(canvas)
local rect = canvas:metrics():rect()
local path = Path.new()
:addSubpath{ x = 0.5, y = 0.7 }
:addLine{ x = 0.8, y = 1.0 }
:addLine{ x = 1.0, y = 0.7 }
:addLine{ x = 0.7, y = 0.4 }
:addLine{ x = 0.8, y = 0.2 }
:addLine{ x = 0.6, y = 0.0 }
:addLine{ x = 0.5, y = 0.2 }
:addLine{ x = 0.4, y = 0.0 }
:addLine{ x = 0.2, y = 0.2 }
:addLine{ x = 0.3, y = 0.4 }
:addLine{ x = 0.0, y = 0.7 }
:addLine{ x = 0.2, y = 1.0 }
:closeSubpath()
canvas:concatTransformation(Transformation.identity():scale(rect.right - rect.left))
:setPaint(Color.rgba(1.0, 0.4, 0.3, 1.0))
:fill(path)
end