Lowtech Painting Machine

Published by Tim on Friday April 7, 2023

Last modified on January 25th, 2024 at 14:06

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

Lena Weber about her collaboration with A. G. Cook

Lena: This 10-minute visualiser for A. G. Cooks album teaser featuring my python archive generator, is one of my favourite […]

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 […]

Computer Cursive by Tay Papon Punyahotra

One of the first exercises I assign to my students in my seminars is called “Random Compositions”. Basically, it’s quite […]

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 […]

Preview: Random Compositions

One of the most exciting and maybe even unsettling discoveries in the learning process of Creative Coding in Graphic Design […]

What Creative Coding can teach you beyond crafting visuals

Learning to code has had a bad reputation for ages. Many people have the impression that it’s all about acquiring […]