Slitscanning
A program that loads an image and draws a horizontal line of pixels from that image stretched vertically to cover the whole window. The vertical position of the line of pixels - where are we looking at in the source photo - changes over time, slowly going from top to bottom in a loop producing an interesting animated effect.
Processing / Java
PImage img;
void setup() {
size(1280, 640, P2D);
img = loadImage("/path/to/your/photo.jpg");
img.loadPixels();
}
void draw() {
int yy = frameCount % img.height;
for(int x=0; x<width; x++) {
int xx = (int)map(x, 0, width, 0, img.width);
stroke(img.pixels[xx + yy * img.width]);
line(x, 0, x, height);
}
}
void keyPressed() {
if(key == 's') {
save("thumb.jpg");
}
}
OPENRNDR / Kotlin (version 1)
fun main() = application {
configure {
width = 1280
height = 640
}
program {
val img = loadImage("/path/to/your/photo.jpg")
val shadow = img.shadow
shadow.download()
extend(Screenshots())
extend {
val yy = frameCount % img.height
for (x in 0 until width) {
val xx = map(0.0, width.toDouble(), 0.0, img.width.toDouble(), x.toDouble()).toInt()
drawer.stroke = shadow[xx, yy]
drawer.lineSegment(x.toDouble(), 0.0, x.toDouble(), height.toDouble())
}
}
}
}
OPENRNDR / Kotlin (version 2)
fun main() = application {
configure {
width = 1280
height = 640
}
program {
val img = loadImage("/path/to/your/photo.jpg")
extend(Screenshots())
extend {
drawer.shadeStyle = shadeStyle {
fragmentTransform = "x_fill = texture(p_img, vec2(c_boundsPosition.x, fract(p_time)));"
parameter("img", img)
parameter("time", seconds * 0.05)
}
drawer.rectangle(drawer.bounds)
}
}
}
Differences to note:
Topic | Processing | OPENRNDR |
---|---|---|
accessing pixels on an image | The pixels are part of the image so you first img.loadPixels() and then access img.pixels
|
The pixels are downloaded from the shadow of the image, then you access them via that shadow object |
iteration | for(int x=0; x<width; x++) |
for (x in 0 until width) |
mapping | map(val, min0, max0, min1, max1) |
map(min0, max0, min1, max1, val) |
set line color | stroke(color) |
drawer.stroke = color |
drawing lines | line(x0, y0, x1, y1) |
drawer.lineSegment(x0, y0, x1, y1) |
upgrading integers to float or double | automatic. you can use integers where floats are expected | manual, use myInt.toDouble() or combine them with a double, for example myInt * 0.5
|
saving a screenshot | call save() inside void keyPressed() {}
|
extend(Screenshots()) and press the [space] key in your program |
draw a rectangle covering the screen | rect(0, 0, width, height) |
drawer.rectangle(drawer.bounds) |
The version 2 above shows that you can easily inline shaders in the program so you avoid drawing many lines in a for loop. This more advanced option is great for those experienced in GLSL shaders.
Two parameters are passed to the shader: the image and the current time scaled down to slow down the effect. The shader then copies to every pixel on the screen the color of a pixel somewhere above or below, the exact source location defined by the value of p_time
.
Share your questions and comments below | Find other OPENRNDR & Processing posts