Get Started
p5.Riso.js is a p5.js library for generating files suitable for Risograph printing. It helps turn your sketches into multi-color prints.
A Risograph is sort of like a photocopier combined with a screen printer. Just like in screen printing, it prints one color at a time, each as a separate layer. To prepare digital files for riso printing, images need to be separated into individual colors, each saved out as a file. The p5.Riso Library helps automate color separation and lets you preview of how your prints will look. It makes it possible to turn your interactive p5 sketches into print art!
Full source and examples on GitHub.
<script src="p5.riso.js"></script>
<script src="p5.riso.js"></script>
Examples
Click to see the source code.
See additional examples here. Let us know if you make prints with p5.riso and we will add your work to the gallery.
Reference
The base Riso object is a single-color p5 graphics object. It's constructor can take 3 parameters:
Internally, the riso object extends p5s built in graphics object. You use it mostly the same way with a few exceptions, as detailed in this documentation.
let blueChannel; //declare riso object
function setup(){
createCanvas(500, 500);
blueChannel = new Riso("blue"); // instantiate riso object as blue layer
blueChannel.fill(128); //set opacity
blueChannel.rect(20, 20, 100, 100); //draw rect to blue layer
drawRiso(); //draw to screen
}
Here we create a blue color layer, set it's fill to be 128 (or half opacity) and then draw a rectangle in it.
Pay attention to the order that you create each Riso object (each color layer). The drawRiso() function that previews your sketch, will display the layers in the order they are created, with the last created layer on top. Note that if your top layer has an opacity of 255, you may not be able to see the layers underneath. Different color combination may result in different blended colors.
The following default colors are available:
The fill method for Riso objects takes a single number value between 0 and 255. 0 is completely transparent, and 255 is completely opaque.
function setup(){
createCanvas(500, 500);
let blueChannel = new Riso("blue"); //create riso object, set to blue
blueChannel.fill(255); // completely opaque
blueChannel.ellipse(0, 0, 100, 100); //draw ellipse on blue layer
blueChannel.fill(50); // fairly transparent
blueChannel.ellipse(50, 50, 100, 100);
blueChannel.fill(3); // almost invisible
blueChannel.ellipse(75, 75, 100, 100);
drawRiso();
}
Just like fill, the stroke method for Riso objects takes a single number value between 0 and 255.
function setup(){
createCanvas(500, 500);
let orange = new Riso("orange");
orange.stroke(255);
orange.strokeWeight(5);
orange.rect(50, 50, 100, 100);
drawRiso();
}
Convenience function that calls noFill() on all riso layers.
risoNoFill();
Convenience function that calls noStroke() on all riso layers.
risoNoStroke();
Completely clears all riso layers. Useful if you are drawing to riso layers in the draw loop rather than just in setup.
clearRiso();
Draws an image onto a riso layer. Acts just like p5's image function, but converts the image to greyscale. It will then print in the color of the layer it is drawn on. Use fill to set the opacity of the image.
let img;
function preload() {
img = loadImage("cat.jpg");
}
function setup(){
createCanvas(500, 500);
let orange = new Riso("orange");
orange.fill(200);
orange.image(img, 0, 0);
drawRiso();
}
This function is the inversion of the mask function. It removes (or masks) portions of one layer that overlap with another layer or graphics object. This is useful for printing in layers when you don't want overlapping colors.
function setup(){
createCanvas(500, 500);
let blue = new Riso("blue"); //blue layer
let red = new Riso("red"); //red layer
blue.ellipse(0, 0, 100, 100);
red.ellipse(0, 0, 150, 150);
//completely removes any intersection of red and blue
//layers from the blue layer
blue.cutout(red);
drawRiso();
}
Extracts a red, blue or green color channels from an image, and saves as a new image. Takes in two parameters:
// convert a color image into a red and blue print
let img;
function preload() {
img = loadImage('cat.jpg')
}
function setup(){
createCanvas(500, 500);
let blue = new Riso("blue");
let red = new Riso("red");
let justBlues = extractRGBChannel(img, "blue"); //extract blue from img
let justReds = extractRGBChannel(img, "red"); //extract red from img
blue.draw(justBlues); //draw justblues to blue layer
red.draw(justReds); //draw justred to red layer
drawRiso();
}
Extracts the cyan, magneta, yellow and/or black color channels from an image, and saves as a new image. Takes in two parameters:
// convert a color image into a cyan and magenta print
let img;
function preload() {
img = loadImage('cat.jpg')
}
function setup(){
createCanvas(500, 500);
let blue = new Riso("blue");
let red = new Riso("red");
let justCyan = extractCMYKChannel(img, "cyan"); //extract cyan from img
let justMagenta = extractCMYKChannel(img, "magenta"); //extract magenta from img
blue.draw(justCyan); //draw justCyan to blue layer
red.draw(justMagenta); //draw justMagenta to red layer
drawRiso();
}
Reduces an image to one color using patterns of dots to create greys.
Takes three parameters. The first is the image object. the second is the dither type (choose between atkinson, floydsteinberg, bayer or none). The third sets the threshold (it only applies to bayer and none). Dither type 'none' simply applies a threshold, turning pixels above and below the threshold clear and black.
let black;
let img;
let ditherType = 'atkinson';
function preload() {
img = loadImage('data/no_threat.jpg');
}
function setup() {
pixelDensity(1);
createCanvas(img.width, img.height);
black = new Riso('black'); //create black layer
}
function draw() {
background(220);
let threshold = map(mouseX, 0, width, 0, 255); //change dither threshold with mouse position
clearRiso();
let dithered = ditherImage(img, ditherType, threshold);//pass image to dither
black.image(dithered, 0, 0); //draw dithered image
drawRiso();
}
function keyReleased() { //function to change dither type with a keypress
if (key == 1) ditherType = 'atkinson';
else if (key == 2) ditherType = 'floydsteinberg';
else if (key == 3) ditherType = 'bayer';
else if (key == 4) ditherType = 'none';
}
Draws all Riso objects/layers to the screen. Should be used at the end of your draw or setup functions. Useful for previewing what your prints will look like.
function setup(){
createCanvas(500, 500);
let colors = ["red", "blue", "green", "black"];
for (let i = 0; i < colors.length; i++) {
let channel = new Riso(colors[i]); //create four color channels from array
channel.fill(random(100, 200));
channel.ellipse(random(0, width), random(0, height), 100, 100); //put a random ellipse on each
}
drawRiso(); //preview on screen
}
Use this function when you are ready to print. It exports all riso layers as individual png files, that can be printed in different ink colors. You should call this function in an event listener like mousePressed, or at the end of your setup function.
let blue;
let red;
function setup(){
createCanvas(500, 500);
blue = new Riso("blue");
red = new Riso("red");
}
function draw() {
clearRiso(); //clear screen every loop of draw
blue.fill(map(mouseX, 0, width, 0, 255)); //set blue fill by mouse position
red.fill(map(mouseY, 0, height, 0, 255)); //set red fill by mouse position
blue.ellipse(200, 200, 100, 100); //draw ellipse to blue layer
red.ellipse(250, 250, 100, 100); //draw ellipse to red layer
}
function mousePressed() { //when mouse is pressed
exportRiso(); //export red and blue layers as pngs for printing
}
Troubleshooting
This library will only work with the latest version of the p5.js library (release 0.9.0 onwards).
Set the pixel density of your sketches to 1, using the pixelDensity function in setup(). Else p5.riso will export your images at the default pixel density of your screen (for retina screens, this results in images coming out twice as large as what is set in CreateCanvas). With a pixel density of 1, the exported images will be sized with resolution of 72 dpi. Therefore an image of 600 pixels, will come out to be 600/72 = 8.3 inches wide. If you want to print your image at a higher resolution but smaller physical size, eg. at a dpi of 300, then you need to resize it using photoshop or a tool like this one.
Credits
p5.Riso was created by Sam Lavigne and Tega Brain with web design and contributions from Crystal Chen and Paolla Bruno Dutra. Made with the support of the Integrated Digital Media Program, NYU. Thanks for getting the printer :)
Full source and examples on Github: https://github.com/antiboredom/p5.riso