Building a digital painting studio from scratch with Processing

Published by Tim on Saturday June 18, 2022

Last modified on June 22nd, 2022 at 14:52

A few weeks ago I met the German artist Arno Beck, whose work I find absolutely great. Arno is a painter and deals with the transfer of digital phenomena into the physical world. Inspired by his painting I developed a digital painting software with Processing in this session.

Thanks to johnny_ctrl for the editing!

YouTube

By loading the video, you agree to YouTube’s privacy policy.
Learn more

Load video

paintingstudio.pde

PImage[] images;

PGraphics source;
PGraphics target;
PGraphics result;

PGraphics comp;

PGraphics artboard;

PImage buffer;
PImage currImage;

int POSTER_W = 580;
int POSTER_H = 810;

float TILES_X = POSTER_W / 5;
float TILES_Y = POSTER_H / 5;

int sx, sy, sw, sh, dx, dy, dw, dh;

float scalar = 1;

float offsetX = 0;
float offsetY = 0;

float coutoutW = 30;

float threshold = 150;

void setup() {
  size(1740, 810);

  source = createGraphics(POSTER_W, POSTER_H);
  target = createGraphics(POSTER_W, POSTER_H);
  result = createGraphics(POSTER_W, POSTER_H);
  artboard = createGraphics(900, 900);

  comp = createGraphics(POSTER_W, POSTER_H);

  images = new PImage[9];

  images[0] = loadImage("1.jpg");
  images[1] = loadImage("2.jpg");
  images[2] = loadImage("3.jpg");
  images[3] = loadImage("4.jpg");
  images[4] = loadImage("5.jpg");
  images[5] = loadImage("6.jpg");
  images[6] = loadImage("7.jpg");
  images[7] = loadImage("8.jpg");
  images[8] = loadImage("9.jpg");

  currImage = images[int(random(images.length))];
}

void draw() {
  background(#00ff00);
  drawSource();
  drawTarget();
  drawResult();


  image(source, 0, 0);
  image(target, POSTER_W, 0);
  image(result, POSTER_W + POSTER_W, 0);
  noFill();
  stroke(#00ff00);
  strokeWeight(3);
  drawArtboard();

  rect(mouseX, mouseY, sw, sh);
  rect(mouseX + POSTER_W, mouseY, sw, sh);

  render();
}

artboard.pde

void drawArtboard() {
  artboard.beginDraw();
  artboard.background(0);
  artboard.imageMode(CENTER);
  PImage buffer = target.get();
  artboard.image(buffer,artboard.width/2,artboard.height/2);
  artboard.endDraw();
}

randomComposition.pde

void randomComposition() {
  
  int padding = 50;
  
  comp.beginDraw();
  comp.background(255);

  float diameter = random(300);

  comp.fill(0);
  comp.noStroke();
  comp.ellipse(random(padding,POSTER_W-padding), random(padding,POSTER_H-padding), diameter, diameter);
  comp.stroke(0);
  comp.strokeWeight(8);
  comp.strokeCap(RECT);
  comp.line(random(padding,POSTER_W-padding), random(padding,POSTER_H-padding), random(padding,POSTER_W-padding), random(padding,POSTER_H-padding));
  comp.endDraw();
}

render.pde

void render() {
  if (frameCount % 10 == 0) {
    artboard.save("out/" + nf(frameCount, 6) + ".png");
  }
}

result.pde

void drawResult() {

  float tileW = result.width / TILES_X;
  float tileH = result.height / TILES_Y;

  PImage buffer = target.get();

  result.beginDraw();
  result.background(#f1f1f1);

  result.noStroke();

  for (int x = 0; x < TILES_X; x++) {
    for (int y = 0; y < TILES_Y; y++) {

      int px = int(x*tileW);
      int py = int(y*tileH);
      color c = buffer.get(px, py);
      float b = brightness(c);

      if (b < threshold) {
        result.fill(0);
      } else {
        result.fill(#f1f1f1);
      }

      result.push();
      result.translate(x*tileW, y*tileH);
      result.rect(0, 0, tileW, tileH);
      result.pop();
    }
  }

  result.endDraw();
}

source.pde

void drawSource(){
  source.beginDraw();
  source.background(0);
  source.imageMode(CENTER);
  source.push();
  source.translate(source.width/2 + offsetX, source.height/2 + offsetY);
  source.scale(scalar);
  source.image(currImage,0,0);
  source.pop();
  source.endDraw();
}

target.pde

void drawTarget() {
  target.beginDraw();

  buffer = source.get();

  if (frameCount == 1) {
    target.background(#ffffff);
  }

  sx = mouseX;
  sy = mouseY;
  sw = int(coutoutW);
  sh = int(coutoutW);

  dx = mouseX;
  dy = mouseY;
  dw = int(coutoutW);
  dh = int(coutoutW);

  if (mousePressed) {
    target.copy(buffer, sx, sy, sw, sh, dx, dy, dw, dh);
  }


  target.endDraw();
}

ui.pde

void keyReleased() {
  if (key == '1') {
    currImage=images[0];
  }
  if (key == '2') {
    currImage=images[1];
  }
  if (key == '3') {
    currImage=images[2];
  }
  if (key == '4') {
    currImage=images[3];
  }
  if (key == '5') {
    currImage=images[4];
  }
  if (key == '6') {
    currImage=images[5];
  }
  if (key == '7') {
    currImage=images[6];
  }
  if (key == '8') {
    currImage=images[7];
  }
  if (key == '9') {
    currImage=images[8];
  }

  if (key == 'r') {
    scalar = random(1, 5);
    offsetX = random(-800, 800);
    offsetY = random(-800, 800);
  }

  if (key == 't') {
    randomComposition();
    currImage = comp.get();
  }
  if (key == 'e') {
    scalar = 1;
    offsetX = 0;
    offsetY = 0;
  }
}

void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  coutoutW += e*10;
}

Related links


Related

Music video for “Choreographs” – Slate and Ash’s new software instrument

Projects

DEMO Festival 2022 was a blast

Essays

Llum Negra/ La Luz Negra / Black Light

Projects

003: A conversation with Stig Møller Hansen

Conversations

Creative Coding as a School of Thought

Essays Projects

What is Creative Coding?

Essays

Creative Coding as an Experience

Essays Featured

The workshop at International Assembly was amazing!

Workshops

An ode to the Gif

Essays

Curating the DESIGN IN MOTION Festival 2022

unlisted

001: A conversation with Yehwan Song

Conversations

Spotlight: André Burnier

Conversations

We need a sustainable perspective on life with technology

Essays

2021 was my year of liberation

Spotlight: Madame Robot

Conversations

The best programming language for Creative Coding in 2022

unlisted

I challenged Daniel Shiffman and here’s his response

Tutorials unlisted

A mockup-design-tool built with Processing

Projects

Processing Community Day 2021 Recap

The Infinite Layout Machine

Student Stories

Processing Community Day 2021 – the recordings

Conversations

PCD2021 – Q&A with Casey Reas

Conversations

PCD2021 – Vera van de Seyp

Conversations

Two Perspectives – Episode 3

Conversations

Processing-Tutorial: A Grid of Arcs

Tutorials

Processing-Tutorial: Exploring Wave-Figures

Tutorials

Interactive Grid System (Livestream)

Tutorials

The Hidden Benefits of Learning to Code

unlisted

Creative Coding Manifesto 2021

Essays Films

My Story (part 2 – told at Taaalks Conference 2020)

New Course: Bauhaus Coding Workshop

unlisted

Learnings from the Bauhaus about Art and Technology

Essays

TypeMachines – A workshop at écal Lausanne

Workshops

My Story (Part 1)

Essays

Processing-Tutorial: Rasterize 3D

Tutorials

Processing-Tutorial: Image-Rasterizer

Tutorials

p5studio

Projects

Lifeline

Projects

Processing-Tutorial: Kinetic Typography 1

Tutorials

My 10 favorite Processing-libraries

4 alternative, free and well-curated resources for images, fonts and data

unlisted

Processing or p5.js? My opinions

Programming Posters

Projects

Generative Portraits for IBM

Projects

Project “Hybrid Curriculum”

Getting started with Processing

Tutorials

Ohne den Hype Podcast

Conversations

Entering the World Wide Web

Form follows Music: The Bach-Project

Projects