Graphics Library
Espruino has a built-in graphics library, exposed via the Graphics class.
On most boards (without built in displays) you can create your own instance(s) of the Graphics class using a module that is designed to interface to a display (see 'Graphics Drivers' below), or you can manually create you own using one of the Graphics.createXYZ
functions.
On the few boards that do contain LCDs, there is a predefined variable called g
(which is an instance of the Graphics Object).
Note: All coordinates in the Graphics library treat 0,0 as the top left corner of the display. However you can rotate or mirror what you draw using the Graphics.setRotation method.
Graphics Drivers
Below are a list of currently available modules that will interface to hardware and create a Graphics object for you:
Note: several of the graphics drivers use offscreen buffers. This means that
draw operations won't immediately effect the display, and a method needs calling
to copy the buffer's data onto the screen. By convention this method is usually
called .flip()
.
Internal (Offscreen) Use
If you don't already have a graphics object set up then you can create a Graphics class which renders to an ArrayBuffer:
Graphics.prototype.print = function() {
for (var y=0;y<this.getHeight();y++)
console.log(new Uint8Array(this.buffer,this.getWidth()*y,this.getWidth()).toString());
};
var g = Graphics.createArrayBuffer(8,8,8);
g.setColor(1);
g.drawString("Hi",0,0);
g.print();
// 1,0,1,0,0,1,0,0
// 1,0,1,0,0,0,0,0
// 1,1,1,0,1,1,0,0
// 1,0,1,0,0,1,0,0
// 1,0,1,0,1,1,1,0
// 0,0,0,0,0,0,0,0
// 0,0,0,0,0,0,0,0
// 0,0,0,0,0,0,0,0
See the Graphics.createArrayBuffer
reference for more information on possible arguments that can be used.
Or you can create a Graphics instance which calls your function whenever a pixel needs to be drawn:
var g = Graphics.createCallback(8,8,1,function(x,y,c) {
print(x+","+y);
});
g.drawLine(0,0,2,2)
//0,0
//1,1
//2,2
Dumping Graphics contents
Espruino can output the contents of a Graphics instance to the Web IDE's REPL
using g.dump()
.
For example you can just type g.dump()
in the REPL to see what
is in the Graphics instance g
.
Internally, g.dump()
works using
g.asURL()
which creates a base64
encoded bitmap of the Graphics instance.
Text / Fonts
Simple Hello World text using a bitmap font:
g.clear();
g.drawString("Hello World",0,0);
The final two arguments are colours (background and foreground)
Or use vector fonts, which are scaleable!
g.clear();
g.setFontVector(40);
g.setColor(1,0,0);
g.drawString("Hello",0,0); // 40px high in red
g.setFontVector(60);
g.setColor(0,1,0);
g.drawString("World",40,40); // 60px high in green
Note: Some non-official Espruino boards don't have vector font support built-in.
You can then switch back to the bitmap font using:
g.setFontBitmap();
You can also use custom Bitmap Fonts. For more information, see Fonts
Circles
In Espruino versions since 1.87, support for drawing circles has been added.
You can draw filled or outlined circles using the two circle functions. For each, the current foreground colour will be used.
The three required arguments are x,y,rad
. The x
and y
coordinates for the centre position of the circle and rad
the radius of the circle.
// Draw a circle
g.drawCircle(100,100,50); // A circle with a radius of 50, centred at 100x100
// Draw a filled circle
g.fillCircle(100,100,50); // A filled circle with a radius of 50, centred at 100x100
However if you want to add your own support in earlier versions then you can always do something like this:
g.fillCircle = function(x,y,rad) {
var pts = parseInt(rad)/2;
var a = [];
for (var i=0;i<pts;i++) {
var t = 2*i*Math.PI/pts;
a.push(x+Math.sin(t)*rad);
a.push(y+Math.cos(t)*rad);
}
g.fillPoly(a);
}
Random Lines
Randomly draw lines on the screen:
g.clear();
while (true) {
g.setColor(Math.random(),Math.random(),Math.random());
g.drawLine(
Math.random()*g.getWidth(), Math.random()*g.getHeight(),
Math.random()*g.getWidth(),Math.random()*g.getHeight())
}
Offscreen Graphics
Images / Bitmaps
Espruino has a function called Graphics.drawImage
which can be used to draw images.
Images are either a special kind of object or a String.
Objects
Objects are of the form:
{
width : int,
height : int,
bpp : int (bits per pixel, optional - default 1),
transparent : int (transparent colour index, optional),
palette : Uint16Array/string (colour palette),
buffer : string/arraybuffer (image data)
}
For instance this is a 8x8
pixel, 1 bit smiley face
where any pixel that is 0
is treated as transparent:
var img = {
width : 8, height : 8, bpp : 1,
transparent : 0,
buffer : new Uint8Array([
0b00000000,
0b01000100,
0b00000000,
0b00010000,
0b00000000,
0b10000001,
0b01111110,
0b00000000,
]).buffer
};
Strings
You can also specify the image as a string or arraybuffer, in the following form:
- For nontransparent:
[width, height, bpp, pixel data...]
- For nontransparent with 16 bit palette:
[width, height, bpp|64, col0_lo, col0_hi, col1_lo, col1_hi, ..., pixel data...]
- For transparent:
[width, height, bpp|128, transparent col, pixel data...]
- For transparent with 16 bit palette:
[width, height, bpp|64|128, transparent col, col0_lo, col0_hi, col1_lo, col1_hi, ..., pixel data...]
Multiple frames
An image can contain multiple frames of the same size (eg for an animation). To do this just ensure that the image bitmap contains all the frames one after the other, then specify
the frame when drawing with Graphics.drawImage
: g.drawImage(img, x, y, { frame : n });
.
To generate an image like this, the easiest way is to use the Image Converter with the images tiled vertically one after the other, and then change the width. As an example, if you want to store 10, 64x64px images:
- Arrange all images vertically into one bitmap, 64x640px
- Load this into the image converter, choose
Image Object
as the output, and convert - Change the
height
field in the output from640
to64
It is also possible to create an image with frames in an image string, but you would have to modify the height in the image string (second byte):
var tmp = atob("......"); // decode the image
E.toArrayBuffer(tmp)[1]=64; // or whatever you image height is
print(btoa(tmp)); // re-encode as base64
Note: For this to work, each frame of the image must contain a multiple of 8 bits - eg. (width * height * bpp) & 7 == 0
.
Creating images
You can:
- Specify images manually (as above)
- Use
Graphics.createImage
to specify a 1 bit image in a more compact, readable way:
var img = Graphics.createImage(`
X X
X
X X
XXXXXX
`);
Use
Graphics.asImage
to create these images from an existing Graphics instance.Upload images to your board's storage (and convert at the same time) with the Web IDE's
Storage
button.Use our online Image Converter to convert an image into Base64-encoded JavaScript that can be pasted into your code.
Load bitmaps directly (eg. from an SD card) with the BMPLoader module:
var img = require("BMPLoader").load(require('fs').readFileSync("foo.bmp"));
g.drawImage(img, 10, 10);
Beware: Microcontrollers don't have much memory - even a small 128x128 pixel 8 bit image may be too big to fit in Espruino's memory!
Rendering
You can then simply draw images to the screen wherever you want:
g.drawImage(img, 10, 10);
// or draw an image directly from Storage
g.drawImage(require("Storage").read("myimage.img"), 10, 10);
// draw an image twice the size
g.drawImage(img, 10, 10, {scale:2});
// draw a large, rotated image
g.drawImage(img, 10, 10, {scale:1.5, rotate:Math.PI/4});
If you use a single-bit image, the foreground and background colors will be used instead of the image's colors. Otherwise the color data will be copied directly so it's an idea to use a bitmap of the same bit depth as your display.
See the reference for Graphics.drawImage
for more information...
Creating an image via command-line
The easiest solution is to use our online Image Converter.
Or you can use command-line tools locally to create a raw image that can be uploaded separately. It's best to install ImageMagick. Then you can type commands like:
# Create a 24 bit RGB image called output.raw
convert myimage.png rgb:output.raw
# Create a 24 bit, 16x16 pixel RGB image called output.raw
convert myimage.png -resize 16x16\! -depth 8 rgb:output.raw
# Create an 8 bit, 16x16 pixel Greyscale image called output.raw
convert myimage.png -resize 16x16\! -depth 8 gray:output.raw
# Create a 1 bit, 16x16 pixel black and white image called output.raw
# Note this one only works if your image is a multiple of 8 pixels wide
convert myimage.png -resize 16x16\! -depth 1 gray:output.raw
On Linux, you can type base64 --wrap=0 myfilename.raw
to convert the raw file to base64 - or on other platforms you can use the File Converter webpage.
Once you've got the base64 encoded image, simply decode it with atob
and create an ArrayBuffer from it. For instance this is the Espruino logo:
var img = {
width : 32, height : 32, bpp : 1,
transparent : 0,
buffer : E.toArrayBuffer(atob("AAAAAAAAeAAAf/4AH/+bAH/ABQBoAAeAaAADwHQAAf5aAfCfS/8/sUXP//1G//AdQ/wAHUAAAB1AAAAdQAAAHWAAABNgAAAeYAAAEOAAABDgAAAQ8AAAGPgAABz4AAAcfAAAnD4AP/A+B//AHz//wA///4AAP+AAABgAAAAAAAA="))
};
Decoding encoded images
Sometimes you might want to turn an image that's in Espruino format back into a PNG file. The best way to do this is to just use Espruino.
You can just write to the existing Graphics instance and dump the whole thing out to the Web IDE's console (but then you'll have to manually crop it to size):
// the image to decode
let img = atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B/++B/8+B/5+B8z+B+H+B/P+B//+B//+B//+A//8AAAAAAAAAAAAA==")
// draw the image and dump it out
g.clear(1).drawImage(img).dump();
Or you can create a Graphics instance of the correct size and dump that out:
// the image to decode
let img = atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B/++B/8+B/5+B8z+B+H+B/P+B//+B//+B//+A//8AAAAAAAAAAAAA==")
// create a Graphics instance of the correct size
let m = g.imageMetrics(img);
let t = Graphics.createArrayBuffer(m.width,m.height,m.bpp,{msb:true});
// draw to the Graphics instance and dump it to the IDE console
t.drawImage(img).dump();
// you can also use .asBMP/.asURL to get the contents in a variable
Tutorials using Graphics
This page is auto-generated from GitHub. If you see any mistakes or have suggestions, please let us know.