Posted 13 October 2013 - 11:04 AM
Hi, this API is designed to help with making high quality images and animations with ease and simplicity.
It adds a new image format and a load of functions that allow you to edit these images in fairly advanced ways, and save them in multiple formats.
Current features: ( shortened )
Loads of unbelievably useful functions to make great looking images
Animations & animation effects to create 100 frame long animations with a couple of lines
A framebufferSome code examples:
Things I will add in the near future:
More patterns
More animation effects
Inbuilt paint program that can be called as a function
Inbuilt demos
More support for invisibility
TemplatesThings I would like to add in the far future:
The primary functions, creating objects and changing how the API works:
Click me!
image = graphics.newImage( x, y, width, height ) – creates a new image object that is [width] wide and [height] high
buffer = graphics.newFrameBuffer( x, y, width, height ) – creates a new framebuffer object that is [width] wide and [height] high
graphics.setPixelFunction( function ) – acts like term.redirect. When using image:render( ) this function will be called with [x,y,bc,tc,char]
graphics.restorePixelFunction( ) – restores the pixel function to the original one
animation = graphics.newAnimation( ) – creates a new animation object
light = graphics.newLightEntity( ) – creates a new light entity object
map = graphics.newLightMap( ) – creates a new light map object
Image functions:
Click me!
basic functions
image:render( force ) – renders the image, set force to true to render all pixels, false to render changed pixels
image:move( mode, x, y ) – moves the image ( only affects rendering offset ) modes = "add" / "set"
image:pixel( x, y, bc, tc, char ) – sets the image pixel at [x][y] to [bc][tc][char] bc = background colour, tc = text colour, char = character. leave bc / tc blank to keep colour at that pixel, leave char blank to set it to " " ( just render the background colour like a normal paint image )
image:write( x, y, bc, tc, … ) – writes everything in … at [x][y] with [bc],[tc] colours, has basic wrapping
image:clear( x, y, w, h, col ) – all args are optional, x, y, w, h defaults to 1, 1, width, height, col defaults to white. clears all pixels from x, y to w, h using [col] colour or white. can be used to resize image
filesystem functions
image:newImage( type, data, x, y ) – used to add new images to [image], more on this later
image:saveImage( type, path ) – used to save images in [type] format
advanced functions – all functions use [bc][tc][char] for replacing pixels
image:floodFill( x, y, bc, tc, char, value ) – flood fills based on pixels with the same [value] value as the pixel at [x][y]. for example using value = "bc" would result in all pixels with the same bc as the one at [x][y] being changed ( uses a flood filling algorithm, not all pixels are always changed depending on things on the screen )
image:line( x1, y1, x2, y2, bc, tc, char ) – draws a line from [x1][y1] to [x2][y2], x2 can be smaller than x1 and vice versa
image:rectangle( mode, x, y, w, h, bc, tc, char ) – draws a rectangle from [x][y] to [x+w-1][y+h-1], modes = "fill" and "line"
image:circle( mode, x, y, r, bc, tc, char ) – draws a circle around point [x][y] with a radius of [r], modes = "line" and "fill"
image:scale( mode, w, h ) – scales image by [w][h] i.e. scaling by [2][2] would make it 4 times larger, modes are listed later
image:newLine( dir, keep ) – adds a new line to the image, dir = "up" or "down", keep determines whether to remove lines from the opposite side to keep the height the same. true to keep, false to destroy
very advanced functions
image:pattern( mode, x, y, bc, tc, char, seed, data ) – adds a pattern to the image, more on this later
image:fractal( x, y, bc, tc, char, seed, data ) – adds a fractal to the image, bc and tc can be input as a table and it will use a different value from the table every time it draws a line
image:applyLighting( t ) – adds lighting to the image from the table of lights input, more on this at bottom
FrameBuffer functions:
Click me!
use term.redirect( buffer ) to draw to the buffer
buffer would be given a set of functions ( everything in term ) that instead of drawing to the screen, draw to the window
buffer.window is an [Image], so you can use that to call [Image] functions i.e buffer.window:clear( )
buffer.data.cb is whether the cursor is blinking, but has to be applied using user code
buffer.candraw should be a boolean. in later versions, this will allow for it to draw directly to the screen as well as to the window
buffer:render( ) is coming soon, which will apply the cursor blink and let it draw to the screen if buffer.candraw is true
Animation functions:
Click me!
frame functions
image = an:newFrame( [d] or [x, y, w, h] ) – add a frame using a pre-created image or use x, y, w, h to make a new image of that size
an:setFrame( n ) – sets the current frame to n
an:deleteFrame( n ) – removes frame[n]
currentFrame = an:nextFrame( ) – cycles through the frames
frame = an:getFrame( n ) – returns the frame[n] or current frame if n isn't given
rendering
an:render( force, time ) – force is used for rendering the frames individually, time is optional, but if given, will render all frames with a [time] sleep inbetween
other
an:newEffect( mode, sf, ef, data, bc, tc, char ) – adds a new effect from frame[sf] to frame[ef], more on effects later…
all the functions available to an [Image] can be used here also
for example:
an:rectangle( 1, 10, mode, y, x, w, h, bc, tc, char ) would add a rectangle in frames 1 to 10
LightEntity functions:
Click me!
light:move( mode, x, y ) – moves the light, modes = "add" and "set"
light:setIntensity( mode, level ) – sets the light intensity, modes = "add" and "set"
LightMap functions:
Click me!
light = map:newLight( x, y, level ) – adds a new light
map:setMaxLightCount( n ) – sets the maximum amount of lights to [n], use 0 to make it infinite
map:applyTo( image ) – applies lighting to the image
map:move( mode, x, y ) – moves every light on the map, modes = "add" and "set"
map:setIntensity( mode, level ) – sets every light on the maps intensity, modes = "add" and "set"
File saving formats:
Click me!
paint - a standard paint image
use "loaded" to add a loaded image to another image in newImage( )
Patterns:
Click me!
give below variables to the function in the data table
speckle - creates a speckling effect around a point with a maximum radius, needs range ( radius ) and intensity ( how many speckles )
line - creates a random curvy line, needs length and degree
When using the image:pattern( ) function
the first arg should be the name of the pattern i.e. speckle or line
Fractals ( in depth ): Click me!
The green splodges are just something I added in to draw when the line stops, as you can see, it looks like some kind of plant or bush
A fractal ( in this API ) is a point and an angle that branches out to form new points and angles and connects them with lines
Think of a tree, you have the trunk, and then loads more branches branching off from other branches. This is somewhat like a fractal in this API
Fractals are one of the most advanced features of the API, so if you are looking to draw smiley faces, don't use fractals
Using large numbers can also crash your program because of stack_overflow and too_long_without_yielding, so watch out
to make a fractal, use image:fractal( x, y, bc, tc, char, seed, data )
x, y is the original point it starts from
bc, tc, char is the pixel data
seed is a random number, using the same seed and data will always result in the same fractal being generated
data is a table {
continue = the 1/[continue] chance of it carrying on, this is set to [continue] * 1.1 every time to stop infinite fractals
length = the length of the lines of the fractal
split = the maximum number of stems that appear from a point
angle = the angle of the start stem of the fractal
range = the range of the fractal i.e angle = 180, range = 20 means the rendered angle could be between 170 and 190
}
If you don't quite understand this, use the following guidelines:
set continue to about 2, 1 makes very big fractals, and can lag or crash, 1.5 is also a good one if you have a decent pc
set length to around 3-5
set split to 2 or 3
set range to about 60, the larger the range, the more blobish the fractal will look, the smaller, the more liney it will look
set angle to degrees ( between 0 and 360, 0 being up, 180 being down, 90 being right, 270 being left )
Animation effects:
Click me!
sripple - creates a square that travels outwards from a centrepoint
slowtext - slow_writes text over multiple frames
variables needed to work
pass them in table format in the data arg
i.e. animation:newEffect( "ripple", 1, 10, { x = 1, y = 1, range = 10, mode = "fill" }, bc, tc, char )
ripple - x and y = centrepoint, range = maximum radius at end of animation, mode = mode required for circle generator
sripple - same as ripple
slowtext - x and y = start of text location, text = text to write, [optional] speed = characters per frame
Note:
using an animation effect changes the frames when animation:newEffect( ) is called
the effects aren't just rendering effects, they change the image itself
Lighting:
Click me!
When you apply lighting to an image, it uses these colours to change the look of the image
The maximum radius of the lighting effect if the same as what light:setIntensity( n ) is
As it goes out, it will get darker and darker
White, lightBlue and yellow work quite well because there are lots of variations of their colour
When image:applyLighting is used, it returns a function that when called, will restore the image to what it was before
If you feel anything needs a bit more explaining, please ask in the comments or PM me. The API is so in-depth it is hard to explain everything in one post, and I am sure I have missed some things out.
If you have used / wish to use this, please comment: say what you like/dislike about the API, what I can add, what I can improve etc…
Thank you for reading
Download:
pastebin get wjQY3nCs graphics
It adds a new image format and a load of functions that allow you to edit these images in fairly advanced ways, and save them in multiple formats.
Current features: ( shortened )
Spoiler
A new image formatLoads of unbelievably useful functions to make great looking images
Animations & animation effects to create 100 frame long animations with a couple of lines
A framebuffer
Spoiler
function animation_test( )
local a = graphics.newAnimation( )
for i = 1, 40 do
a:newFrame( 1, 1, 51, 19 )
end
a:newEffect( "ripple", 1, 40, { range = 14, x = 26, y = 10, mode = "line" }, "blue", "white", " " )
a:newEffect( "ripple", 4, 30, { range = 8, x = 37, y = 12, mode = "line" }, "red", "white", " " )
a:newEffect( "ripple", 10, 31, { range = 20, x = 4, y = 2, mode = "line" }, "yellow", "white", " " )
a:newEffect( "ripple", 10, 38, { range = 12, x = 11, y = 14, mode = "line" }, "lime", "white", " " )
a:newEffect( "slowtext", 1, 40, { speed = 0.5, text = "Hello World!", x = 1, y = 1 }, "white", "black", " " )
a:render( false, 0.05 )
end
function light_test( )
local pic = graphics.newImage( 1, 1, 51, 19 )
pic:rectangle( "fill", 1, 1, 51, 19, "white", "white", " " )
pic:rectangle( "fill", 4, 7, 20, 4, "lightBlue", "white", " " )
pic:circle( "fill", 37, 3, 4, "yellow", "white", " " )
local map = graphics.newLightMap( )
map:setMaxLightCount( 3 )
os.startTimer( 0 )
while true do
local ev = { os.pullEvent( ) }
if ev[1] == "mouse_click" then
if ev[2] == 1 then
map:newLight( ev[3], ev[4], 5 )
else
map:move( "set", ev[3], ev[4] )
end
elseif ev[1] == "mouse_scroll" then
map:setIntensity( "add", ev[2] )
elseif ev[1] == "timer" then
os.startTimer( 0.1 )
elseif ev[1] == "key" then
return
end
local revert = map:applyTo( pic )
pic:render( )
revert( )
map:move( "add", 1, 0 )
end
end
function fractal_test( )
local seed = 0
while true do
term.setCursorPos( 1, 1 )
term.setBackgroundColour( colours.white )
term.setTextColour( colours.black )
term.write( seed )
local ev = { os.pullEvent( ) }
if ev[1] == "mouse_click" then
seed = seed + ( ev[2] == 1 and 1 or -1 )
local i = graphics.newImage( 1, 1, 51, 19 )
i:fractal( 1, 1, "blue", "white", " ", seed, { angle = 135, range = 60, split = 3, length = 3, continue = 2 } )
i:render( true )
elseif ev[1] == "key" then
return
end
end
end
Spoiler
Animation saverMore patterns
More animation effects
Inbuilt paint program that can be called as a function
Inbuilt demos
More support for invisibility
Templates
Spoiler
png -> TBI converterThe primary functions, creating objects and changing how the API works:
Click me!
Spoiler
using [os.loadAPI( "graphics" )] would result in the following…image = graphics.newImage( x, y, width, height ) – creates a new image object that is [width] wide and [height] high
buffer = graphics.newFrameBuffer( x, y, width, height ) – creates a new framebuffer object that is [width] wide and [height] high
graphics.setPixelFunction( function ) – acts like term.redirect. When using image:render( ) this function will be called with [x,y,bc,tc,char]
graphics.restorePixelFunction( ) – restores the pixel function to the original one
animation = graphics.newAnimation( ) – creates a new animation object
light = graphics.newLightEntity( ) – creates a new light entity object
map = graphics.newLightMap( ) – creates a new light map object
Image functions:
Click me!
Spoiler
using [image = graphics.newImage( x, y, w, h )] would result in the following…basic functions
image:render( force ) – renders the image, set force to true to render all pixels, false to render changed pixels
image:move( mode, x, y ) – moves the image ( only affects rendering offset ) modes = "add" / "set"
image:pixel( x, y, bc, tc, char ) – sets the image pixel at [x][y] to [bc][tc][char] bc = background colour, tc = text colour, char = character. leave bc / tc blank to keep colour at that pixel, leave char blank to set it to " " ( just render the background colour like a normal paint image )
image:write( x, y, bc, tc, … ) – writes everything in … at [x][y] with [bc],[tc] colours, has basic wrapping
image:clear( x, y, w, h, col ) – all args are optional, x, y, w, h defaults to 1, 1, width, height, col defaults to white. clears all pixels from x, y to w, h using [col] colour or white. can be used to resize image
filesystem functions
image:newImage( type, data, x, y ) – used to add new images to [image], more on this later
image:saveImage( type, path ) – used to save images in [type] format
advanced functions – all functions use [bc][tc][char] for replacing pixels
image:floodFill( x, y, bc, tc, char, value ) – flood fills based on pixels with the same [value] value as the pixel at [x][y]. for example using value = "bc" would result in all pixels with the same bc as the one at [x][y] being changed ( uses a flood filling algorithm, not all pixels are always changed depending on things on the screen )
image:line( x1, y1, x2, y2, bc, tc, char ) – draws a line from [x1][y1] to [x2][y2], x2 can be smaller than x1 and vice versa
image:rectangle( mode, x, y, w, h, bc, tc, char ) – draws a rectangle from [x][y] to [x+w-1][y+h-1], modes = "fill" and "line"
image:circle( mode, x, y, r, bc, tc, char ) – draws a circle around point [x][y] with a radius of [r], modes = "line" and "fill"
image:scale( mode, w, h ) – scales image by [w][h] i.e. scaling by [2][2] would make it 4 times larger, modes are listed later
image:newLine( dir, keep ) – adds a new line to the image, dir = "up" or "down", keep determines whether to remove lines from the opposite side to keep the height the same. true to keep, false to destroy
very advanced functions
image:pattern( mode, x, y, bc, tc, char, seed, data ) – adds a pattern to the image, more on this later
image:fractal( x, y, bc, tc, char, seed, data ) – adds a fractal to the image, bc and tc can be input as a table and it will use a different value from the table every time it draws a line
image:applyLighting( t ) – adds lighting to the image from the table of lights input, more on this at bottom
FrameBuffer functions:
Click me!
Spoiler
using [buffer = graphics.newAnimation( )] would result in the following…use term.redirect( buffer ) to draw to the buffer
buffer would be given a set of functions ( everything in term ) that instead of drawing to the screen, draw to the window
buffer.window is an [Image], so you can use that to call [Image] functions i.e buffer.window:clear( )
buffer.data.cb is whether the cursor is blinking, but has to be applied using user code
buffer.candraw should be a boolean. in later versions, this will allow for it to draw directly to the screen as well as to the window
buffer:render( ) is coming soon, which will apply the cursor blink and let it draw to the screen if buffer.candraw is true
Animation functions:
Click me!
Spoiler
using [an = graphics.newAnimation( )] would result in the following…frame functions
image = an:newFrame( [d] or [x, y, w, h] ) – add a frame using a pre-created image or use x, y, w, h to make a new image of that size
an:setFrame( n ) – sets the current frame to n
an:deleteFrame( n ) – removes frame[n]
currentFrame = an:nextFrame( ) – cycles through the frames
frame = an:getFrame( n ) – returns the frame[n] or current frame if n isn't given
rendering
an:render( force, time ) – force is used for rendering the frames individually, time is optional, but if given, will render all frames with a [time] sleep inbetween
other
an:newEffect( mode, sf, ef, data, bc, tc, char ) – adds a new effect from frame[sf] to frame[ef], more on effects later…
all the functions available to an [Image] can be used here also
for example:
an:rectangle( 1, 10, mode, y, x, w, h, bc, tc, char ) would add a rectangle in frames 1 to 10
LightEntity functions:
Click me!
Spoiler
using [light = graphics.newLightEntity( )] would result in the following…light:move( mode, x, y ) – moves the light, modes = "add" and "set"
light:setIntensity( mode, level ) – sets the light intensity, modes = "add" and "set"
LightMap functions:
Click me!
Spoiler
using [map = graphics.newLightMap( )] would result in the following…light = map:newLight( x, y, level ) – adds a new light
map:setMaxLightCount( n ) – sets the maximum amount of lights to [n], use 0 to make it infinite
map:applyTo( image ) – applies lighting to the image
map:move( mode, x, y ) – moves every light on the map, modes = "add" and "set"
map:setIntensity( mode, level ) – sets every light on the maps intensity, modes = "add" and "set"
File saving formats:
Click me!
Spoiler
TBI ( old was TIF but there is another file format for images called tif ) – saves text and text colour as well as background colourpaint - a standard paint image
use "loaded" to add a loaded image to another image in newImage( )
Patterns:
Click me!
Spoiler
These are still quite buggy and nowhere near finished. I won't give very much detail, you will have to play around / look at code to fully understand how they workgive below variables to the function in the data table
speckle - creates a speckling effect around a point with a maximum radius, needs range ( radius ) and intensity ( how many speckles )
line - creates a random curvy line, needs length and degree
When using the image:pattern( ) function
the first arg should be the name of the pattern i.e. speckle or line
Fractals ( in depth ): Click me!
Spoiler
Here is an image of the fractal generator in use in love2dThe green splodges are just something I added in to draw when the line stops, as you can see, it looks like some kind of plant or bush
A fractal ( in this API ) is a point and an angle that branches out to form new points and angles and connects them with lines
Think of a tree, you have the trunk, and then loads more branches branching off from other branches. This is somewhat like a fractal in this API
Fractals are one of the most advanced features of the API, so if you are looking to draw smiley faces, don't use fractals
Using large numbers can also crash your program because of stack_overflow and too_long_without_yielding, so watch out
to make a fractal, use image:fractal( x, y, bc, tc, char, seed, data )
x, y is the original point it starts from
bc, tc, char is the pixel data
seed is a random number, using the same seed and data will always result in the same fractal being generated
data is a table {
continue = the 1/[continue] chance of it carrying on, this is set to [continue] * 1.1 every time to stop infinite fractals
length = the length of the lines of the fractal
split = the maximum number of stems that appear from a point
angle = the angle of the start stem of the fractal
range = the range of the fractal i.e angle = 180, range = 20 means the rendered angle could be between 170 and 190
}
If you don't quite understand this, use the following guidelines:
set continue to about 2, 1 makes very big fractals, and can lag or crash, 1.5 is also a good one if you have a decent pc
set length to around 3-5
set split to 2 or 3
set range to about 60, the larger the range, the more blobish the fractal will look, the smaller, the more liney it will look
set angle to degrees ( between 0 and 360, 0 being up, 180 being down, 90 being right, 270 being left )
Animation effects:
Click me!
Spoiler
ripple - creates a circle that travels outwards from a centrepointsripple - creates a square that travels outwards from a centrepoint
slowtext - slow_writes text over multiple frames
variables needed to work
pass them in table format in the data arg
i.e. animation:newEffect( "ripple", 1, 10, { x = 1, y = 1, range = 10, mode = "fill" }, bc, tc, char )
ripple - x and y = centrepoint, range = maximum radius at end of animation, mode = mode required for circle generator
sripple - same as ripple
slowtext - x and y = start of text location, text = text to write, [optional] speed = characters per frame
Note:
using an animation effect changes the frames when animation:newEffect( ) is called
the effects aren't just rendering effects, they change the image itself
Lighting:
Click me!
Spoiler
To truly understand this, you have to see it in action, but basically, the API gives all colours 4 light levels when it is loadedWhen you apply lighting to an image, it uses these colours to change the look of the image
The maximum radius of the lighting effect if the same as what light:setIntensity( n ) is
As it goes out, it will get darker and darker
White, lightBlue and yellow work quite well because there are lots of variations of their colour
When image:applyLighting is used, it returns a function that when called, will restore the image to what it was before
If you feel anything needs a bit more explaining, please ask in the comments or PM me. The API is so in-depth it is hard to explain everything in one post, and I am sure I have missed some things out.
If you have used / wish to use this, please comment: say what you like/dislike about the API, what I can add, what I can improve etc…
Thank you for reading
Download:
pastebin get wjQY3nCs graphics