xxxxxxxxxx
let img;
let pal;
let canvas;
let queue;
const magnitude = 1;
function preload(){
// img = loadImage(
// "Che.PNG"
// "ginsburg.jpeg"
// );
// img = loadImage("chaplin.jpg");
// img = loadImage("Abraham-Lincoln.jpg");
img = loadImage("rbg2.jpg");
}
const MAG = (prop) => prop * magnitude;
function setup() {
canvas = createCanvas(MAG(windowWidth), MAG(windowHeight));
background(255);
noStroke();
randomSeed(1)
// img.filter(BLUR,1);
// img.filter(GRAY)
// img.filter(POSTERIZE,2)
img.resize(0,MAG(height));
// image(img,0,0);
// fill(255,230)
// rect(0,0,width,height);
img.loadPixels();
stroke(0,0,200,100);
// strokeWeight(1)
// noFill();
pal = new Palette();
pal.swatch(1)
pal.setAlpha(100);
queue = new TinyQueue();
queue.onItemLoop=function(brush){
return brush.render();
}
queue.onFinish = function(){
console.log('FINISHED');
}
let scan = new BrushSeedScan(img);
randomSeed(5)
let maxScribbleAmount = 5000;
let minScribbleAmount = 100;
let maxBrightness = 150;
let minBrightness = 10;
let maxLength = MAG(40);
let minLength = MAG(10);
scan.maxBrightness = maxBrightness;
scan.maxPoints = 40;
// scan.type = "GRID-SPREAD";
scan.onFound = function(x,y,b){
let p = new PSingleLineBrush(img);
// let p = new PCurvedBrush(img);
// let p = new PBrush(img);
// let p = new PLine();
p.amount = floor(map(b,0,this.maxBrightness, maxScribbleAmount,minScribbleAmount));
p.maxBrightness = maxBrightness
p.minBrightness = minBrightness
p.maxLength = maxLength;
p.minLength = minLength;
// p.color = [pal.random(),pal.random()];
p.color = pal.random();
//p.color = color(0,0,200,100);
p.setArea(img.width,img.height);
// p.setPosition(x,y)
queue.add(p);
}
scan.run();
}
function draw(){
queue.loop();
}
////////////////////////////////////////////////////
// Reads image and finds pixels that match brightness
// required and seeds a queue of brushes
////////////////////////////////////////////////////
class BrushSeedScan{
constructor(img){
this.img = img;
this.maxBrightness = 100;
this.maxTries = 100;
this.maxPoints = 100;
this.type = 'RANDOM';
this.count=0;
this.grid = [3,3]
this.range = [];
}
run(){
switch(this.type){
case 'RANDOM': this.typeRandom(); break;
case 'GRID' : this.typeGrid(); break;
case 'GRID-SPREAD': this.typeGridSpread(); break;
}
}
typeGridSpread(){
let rows = this.grid[0];
let cols = this.grid[1];
let w = this.img.width/cols;
let h = this.img.height/rows;
let t = this.maxTries / (rows*cols);
let p = this.maxPoints / (rows*cols);
for(let x=0;x<this.img.width;x+=w){
for(let y=this.img.height;y>=0;y-=h){
this.typeGridSpreadCell(t,p,x,y,w,h);
}
}
this.onFinish();
}
typeGridSpreadCell(tries,points,x,y,w,h){
let x1,y1;
while(tries-- > 0){
x1 = floor(x+random(w));
y1 = floor(y+random(h));
let b = red(this.img.get(x1,y1));
if(b < this.maxBrightness){
if(points--<1){ break; }
this.onFound(x1,y1,b);
this.count++;
}
}
}
typeRandom(){
let x=0,y=0,b,v,i=0,m=this.maxTries,p=this.maxPoints;
while(m--){
x = floor(random(this.img.width));
y = floor(random(this.img.height));
b = red(this.img.get(x,y));
if(b < this.maxBrightness){
if(p-- <= 0){
break;
}
this.onFound(x,y,b);
}
}
this.onFinish();
}
typeGrid(blk){
this.blk = blk || width/5;
let mid = this.blk/2;
let i=0;
for(let x=this.img.width;x>0;x-=this.blk){
for(let y=this.img.height;y>0;y-=this.blk){
let b = red(this.img.get(x+mid,y+mid));
if(b < this.maxBrightness){
this.onFound(x+mid,y+mid,b);
}
}
}
this.onFinish();
}
onFound(x=0,y=0,b=null,i=0,m=0){
push()
stroke(0);
strokeWeight(MAG(4));
point(x,y)
pop();
}
onFinish(){}
}
////////////////////////////////////////////////////
// Simple queue that triggers objects over and over
// based on drawing
////////////////////////////////////////////////////
class TinyQueue{
constructor(){
this.queue = [];
}
add(item){
this.queue.push(item);
}
build(n,func,context){
for(let x=0;x<n;x++){
this.add(func.apply(null,[x]));
}
}
loop(){
let i=0
// console.log(this.queue.length)
for(let item of this.queue){
if(this.onItemLoop(item)){
this.queue.splice(i,1);
if(this.queue.length==0){
this.onFinish();
}
i++;
}
}
}
onItemLoop(item){
return true;
}
onFinish(){
noLoop();
}
}
////////////////////////////////////////////////////
// Brush class, find next point based on brightness
////////////////////////////////////////////////////
class PBrush{
constructor(img){
this.img = img || false;
this.amount = 1000;
this.count = 0;
this.maxLength = 100;
this.minLength = 10;
this.maxBrightness = 60;
this.minBrightness = 0;
this.maxTries = 30;
this.pos = false;
this.pos2 = false;
this.curveTightness = 0;
this.color = color(0,50);
this.isFinished = false;
this.w = width;
this.h = height;
this.validBoundary = function(vct){
return (vct.x < this.w && vct.y < this.h && vct.x > 0 && vct.y > 0);
}
this.getLength = function(){
return random(this.minLength,this.maxLength);
}
if(this.img){
this.w = this.img.width;
this.h = this.img.height;
this.getBrightness = false;
this.getBrightness = function(vct){
// let px = this.img.pixels[ 4 * (vct.x + vct.y * this.img.width ) ];
let px = this.img.get(vct.x,vct.y)[0];
// $('getBrightness',px,vct.x,vct.y,this.img)
return px
}
this.validPoint = false;
this.validPoint = function(vct){
let bri = this.getBrightness(vct);
if(bri >= this.minBrightness && bri <= this.maxBrightness){
this.img.set(vct.x,vct.y,0);
return true;
}
return false;
}
this.getLength = false;
this.getLength = function(vct){
let bri = this.getBrightness(vct);
// $('getLength',bri,x,this.minLength,this.maxLength)
return map(bri,this.minBrightness,this.maxBrightness,this.minLength,this.maxLength, true);
}
}
this.setPosition(random(this.w),random(this.h));
}
setArea(w,h){
this.w = w;
this.h = h;
}
setPosition(x,y){
this.x = floor(x);
this.y = floor(y);
this.pos = createVector(this.x,this.y);
}
render(){
this.pos2 = this.find(this.pos);
this.draw(this.pos, this.pos2);
this.pos = this.pos2;
// return true;
return this.isFinished = (this.amount <= this.count++);
}
draw(v1,v2){
stroke(this.color);
line(v1.x,v1.y, v2.x,v2.y);
}
next(vct,length){
return vct.add(floor(random(-length,length)), floor(random(-length,length)));
}
find(vct){
if(!vct){ return false}
let nvct,px,tries=this.maxTries;
let len = this.getLength(vct);
while(--tries > 0){
nvct = this.next(vct.copy(),len);
if( this.validBoundary(nvct) && this.validPoint(nvct) ){
return nvct;
}
}
return vct;
}
}
class PCurvedBrush extends PBrush{
render(){
let corner = this.find(this.pos);
this.nextPos = this.find(corner);
noFill();
stroke(this.color);
beginShape();
vertex(this.pos.x,this.pos.y)
quadraticVertex(corner.x,corner.y, this.nextPos.x,this.nextPos.y);
endShape();
this.pos = this.nextPos;
return this.isFinished = (this.amount <= this.count++);
}
}
class PSingleLineBrush extends PBrush{
render(){
push();
noFill();
strokeLinearGradient(this.color);
curveTightness(this.curveTightness);
beginShape();
while(this.amount--){
curveVertex(this.pos.x,this.pos.y);
this.pos = this.find(this.pos);
}
endShape();
pop();
return true;
}
}
class PLine extends PBrush{
constructor(){
super();
this.spacing = 50;
this.steps = 10;
this.angle = QUARTER_PI;
}
render(){
let spacing= this.maxLength/2 + this.spacing;
// for(let y=0;y<=this.h;y+=spacing){
this.draw(0,50);
// }
return true;
}
draw(x,y){
noStroke();
fill(0);
push();
// translate(x,y)
$(x,y)
beginShape();
for(let t=x;t<=this.w;t+=this.steps){
curveVertex(t,-this.modifier(t,y));
}
for(let t=this.w;t>=x;t-=this.steps){
curveVertex(t,this.modifier(t,y));
}
endShape();
pop();
}
modifier(x,y){
return this.maxLength/2;
}
}
function $(){
console.log(Array.prototype.join.apply(arguments,[" | "]))
}
function mousePressed(){
saveCanvas(canvas,"SingleLine",'png');
}