This summer I’m going to release a new album of solo electronic music that is heavily influenced by EDM and classic rock. For the past few weeks I’ve been trying to figure out what to do about the art on the new album.
The album is called “FYNIX Fights Back” so I decided to use images of animals fighting, but I didn’t just want to pull up generic images. I wanted to add my own special touch to each image. So I pulled out a tool that I haven’t used in years: the Processing programming language.
Processing is great for simple algorithmic art. In this case I wanted to glitch some images interactively, but I wasn’t exactly sure what I wanted to do.
So I just started experimenting. I played with colors and shapes and randomness. I like to derive randomess based on mouse movement. The more the mouse moves, the more randomness is imparted to whatever the user is doing.
I added image glitching based on mouse speed. The quicker the cursor moves, the more random are the generated shapes, and the more they are offset from their source position in the original image.
Here’s the end result.
Here’s the source code. Make it even better.
import java.awt.event.KeyEvent; // relationship between image size and canvas size float scalingFactor = 2.0; // image from unsplash.com String imageFilename = "YOUR_FILE_IN_DATA_FOLDER.jpg"; // image container PImage img; PImage scaledImage; int minimumVelocity = 40; int velocityFactorDivisor = 5; // the larger this is, the more vertices you will get int velocityFactor = 1; // this will be overridden below float minimumImageSize = 10.0f; boolean firstDraw = true; int currentImage = 1; void settings() { // load the source image img = loadImage(imageFilename); // load the pixel colors into the pixels array img.loadPixels(); // create a canvas that is proportional to the selected image size((int)(img.width / scalingFactor), (int)(img.height / scalingFactor)); // scale the image for the window size scaledImage = loadImage(imageFilename); scaledImage.resize(width, height); // override velocityFactor velocityFactor = (int)(width / velocityFactorDivisor); } void setup() { // disable lines noStroke(); } void keyPressed() { if(keyCode == KeyEvent.VK_R) { firstDraw = true; // if the user presses ENTER, then reset } } void draw() { if(firstDraw) { image(scaledImage, 0, 0); firstDraw = false; } // right click to render to image file if(mousePressed && mouseButton == RIGHT) { save(imageFilename.replace(".jpg", "") + "_render_" + currentImage + ".tga"); currentImage++; } if(mousePressed && mouseButton == LEFT && mouseX >= 0 && mouseX < width && mouseY >= 0 && mouseY < height) { int velocityX = minimumVelocity + (3 * velocity(mouseX, pmouseX, width)); int velocityY = minimumVelocity + (3 * velocity(mouseY, pmouseY, height)); color c = img.pixels[mousePositionToPixelCoordinate(mouseX, mouseY)]; int vertexCount = ((3 * velocityFactor) + velocityX + velocityY) / velocityFactor; int minimumX = mouseX - (velocityX / 2); int maximumX = mouseX + (velocityX / 2); int minimumY = mouseY - (velocityY / 2); int maximumY = mouseY + (velocityY / 2); PGraphics pg = createGraphics(maximumX - minimumX, maximumY - minimumY); pg.beginDraw(); pg.noStroke(); pg.fill(c); // first draw a shape into the buffer pg.beginShape(); for(int i = 0; i < vertexCount; i++) { pg.vertex(random(0, pg.width), random(0, pg.height)); } pg.endShape(); pg.endDraw(); pg.loadPixels(); // then copy image pixels into the shape // get the upper left coordinate in the source image int startingCoordinateInSourceImage = mousePositionToPixelCoordinate(minimumX, minimumY); // get the width of the source image int sourceImageWidth = (int)(img.width); // set the offset from the source image int offsetX = velocity(mouseX, pmouseX, width); int offsetY = velocity(mouseY, pmouseY, height); // ensure that the offset doesn't go off the canvas if(mouseX > width / 2) offsetX *= -1; if(mouseY > height / 2) offsetY *= -1; for(int y = 0; y < pg.height; y++) { for(int x = 0; x < pg.width; x++) { // calculate the coordinate in the destination image int newImageY = y * pg.width; int newImageX = x; int newImageCoordinate = newImageX + newImageY; // calculate the location in the source image //int sourceImageCoordinate = (int)(startingCoordinateInSourceImage + (x * scalingFactor) + ((y * scalingFactor) * sourceImageWidth)); //int sourceImageCoordinate = (int)(startingCoordinateInSourceImage + ((x + offsetX) * scalingFactor) + (((y + offsetY) * scalingFactor) * sourceImageWidth)); int sourceImageX = (int)(((x + offsetX) * scalingFactor)); int sourceImageY = (int)((((y + offsetY) * scalingFactor) * sourceImageWidth)); int sourceImageCoordinate = (int)(startingCoordinateInSourceImage + sourceImageX + sourceImageY); // ensure the calculated coordinates are within bounds if(newImageCoordinate > 0 && newImageCoordinate < pg.pixels.length && sourceImageCoordinate > 0 && sourceImageCoordinate < img.pixels.length && pg.pixels[newImageCoordinate] == c) { pg.pixels[newImageCoordinate] = img.pixels[sourceImageCoordinate]; } } } image(pg, minimumX, minimumY); } } // convert the mouse position to a coordinate within the source image int mousePositionToPixelCoordinate(int mouseX, int mouseY) { return (int)(mouseX * scalingFactor) + (int)((mouseY * scalingFactor) * img.width); } // This sort of calculates mouse velocity as relative to canvas size int velocity(float x1, float x2, float size) { int val = (int)(Math.abs((x1 - x2) / size) * size); return val; }