OPENRNDR & Processing - Slitscanning

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.

:point_down: Share your questions and comments below | :mag_right: Find other OPENRNDR & Processing posts

3 Likes