Building a digital painting studio from scratch with Processing

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

Published by Tim on Saturday June 18, 2022

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


Related

Creative Coding as a School of Thought

Essays Projects Updates

What is Creative Coding?

Essays Highlights

Creative Coding as an Experience

Essays Highlights

The workshop at International Assembly was amazing!

Events Workshops

DEMO Festival 2022 – Open Call

Events Updates

Interview – Masters of Many Podcast

Conversations

An ode to the Gif

Essays

Spotlight: Lily Montague

Conversations

Curating the DESIGN IN MOTION Festival 2022

Events Updates

Spotlight: Yehwan Song

Conversations

Introducing “Quests”

Updates

Spotlight: André Burnier

Conversations

We need a sustainable perspective on life with technology

Essays

Book Review: Flexible Visual Systems

2021 was my year of liberation

Updates

Spotlight: Madame Robot

Conversations

The best programming language for Creative Coding in 2022

I challenged Daniel Shiffman and here’s his response

Tutorials

A mockup-design-tool built with Processing

Projects

Processing Community Day 2021 Recap

Updates

3 Tips to accelerate and optimize your learning process

Essays

The Infinite Layout Machine

Student Works

Processing Community Day 2021 – the recordings

Conversations Events Updates

PCD2021 – Q&A with Casey Reas

Conversations Events

PCD2021 – Vera van de Seyp

Conversations Events

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

Talking at Zuibishe / China

Creative Coding Manifesto 2021

Essays Films

Out now: Typemachines

Future Plans

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

New Course: Bauhaus Coding Workshop

Learnings from the Bauhaus about Art and Technology

Essays

TypeMachines – A workshop at écal Lausanne

Workshops

Interview with Tech+Art Podcast

Conversations

My Story (Part 1)

Essays

Processing-Tutorial: Rasterize 3D

Tutorials

Alpha-Release: “Creative Coding Essentials”

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

Processing or p5.js? My opinions

Programming Posters

Projects

The Bach-Project

Projects

Creative Coding as a Method

Essays Highlights

Creative Coding as a Chance

Essays Highlights
Exclusive

Digital Reality: Livestream Marathon

Sessions

Reflections on my master-studies

Essays

Spotlight: Sander Sturing

Conversations