Lowtech Painting Machine

Published by Tim on Friday April 7, 2023

Last modified on December 3rd, 2024 at 17:51

A few months ago I made a small app that allows you to create image collages with some kind of paintbrush tool. Basically, the tool works like an ordinary retouching brush: On the left half you see the source, on the right the painted image. The green square marks the image section that can be selected with the mouse.

paintingmachine.pde

PImage[] images;
PShader shade;
PGraphics source;
PGraphics target;

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(1160, 810, P2D);

  shade = loadShader("halftone.glsl");
  shade.set("pixelsPerRow", 2000);

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

  comp = createGraphics(POSTER_W, POSTER_H);

  images = new PImage[9];

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

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

void draw() {
  background(#FFFFFF);
  drawSource();
  drawTarget();

  image(source, 0, 0);

  noStroke();


  image(target, POSTER_W, 0);

  noFill();
  stroke(#00ff00);
  strokeWeight(3);
  drawArtboard();

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

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();
}

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();
}

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

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();
}

void drawTarget() {
  target.beginDraw();
  // target.filter(shade);

  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.filter(shade);
  target.endDraw();
}

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(0.1, 4);
    offsetX = random(-1200, 1200);
    offsetY = random(-1200, 1200);
  }

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

  if (keyCode == 37) {
    offsetX-=10;
  }

  if (keyCode == 39) {
    offsetX+=10;
  }
  if (keyCode == 40) {
    offsetY+=10;
  }

  if (keyCode == 38) {
    offsetY-=10;
  }

  if (key == '+') {
    scalar+=0.1;
  }

  if (key == '-') {
    scalar-=0.1;
  }
}

void mouseWheel(MouseEvent event) {
  float e = event.getCount();
  
}

Related

Enjoying the content?

I put a lot of love and effort into developing content on Creative Coding. Since 2018, I have published 219 interviews, case studies, and tutorials, along with over 280 lessons in 17 online courses – and there's more to come! If you'd like to support my work and help keep this platform evolving, please consider supporting me on Patreon. Thank you very much!

Speaking Image

Monthly Newsletter

Fresh perspectives circling around Creative Coding, Design and Technology, every first Friday of the month, directly to your inbox.

Related

p5studio

A prototype for a browser-based design-application, built with p5.js and vue.js.

Building Tools with p5.js (Playlist)

Click here to login or connect!To view this content, you must be a member of Tim's Patreon at €10 or […]

DEMO 2025 – My Submissions

Limitations have always been playing a major role in my creative work; I was only able to develop my best […]

The 128kb Framework and its Aesthetic Characteristics

One day in early 2024 I started to experiment with a new idea. I wrote down a set of rules […]

My new writing project “downgrade” is live

Hey folks, I hope you are doing great! You may have already read one or two of my essays that […]

Join the 128kb challenge!

Instagram, Twitter, TikTok… All the main platforms that technically have the required features to connect emerging communies for Creative Coding […]

A custom Mockup Tool, built with Processing (updated)

For my students at Elisava, I have created a new version of my mockup-tool. You need two different files for […]

Preview: When Computers create Collages

2023-12-01 Today I want to share with you a first prototype that will be the basis for a new course […]