# Make an ASCII Video

**URL:** https://discourse.processing.org/t/make-an-ascii-video/38507
**Category:** Libraries
**Created:** [August 27, 2022, 10:23am UTC](https://discourse.processing.org/t/make-an-ascii-video/38507 "2022-08-27T10:23:59Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![Roklair](https://avatars.discourse-cdn.com/v4/letter/r/e480ec/32.png) [@Roklair](https://discourse.processing.org/u/Roklair)
#### Post date: [August 27, 2022, 10:23am UTC](https://discourse.processing.org/t/make-an-ascii-video/38507/1 "2022-08-27T10:23:59Z")

</div>

Hello everyone.  
Recently I got interested in ASCII art, I could see that there was an example created by Ben Fry in the Processing library.  
My problem is that I want to use this code but with an imported video and not a live video from my webcam.  
I tried to modify the code as below but I still have this message that appears “ArrayIndexOutOfBoundsException: 0”  
Could someone help me to find a solution? I put the code that i modified below, maybe it can help !  
Thanks !

/\*\*

- ASCII Video
- by Ben Fry.
- 
- 
- Text characters have been used to represent images since the earliest computers.
- This sketch is a simple homage that re-interprets live video as ASCII text.
- See the keyPressed function for more options, like changing the font size.  
\*/

import processing.video.\*;  
Movie movie;  
boolean cheatScreen;

// All ASCII characters, sorted according to their visual density  
String letterOrder =  
" .`-\_':,;^=+/"|)\\<\>)iv%xclrs{\*}I?!][1taeo7zjLu" +  
“nT#JCwfy325Fp6mqSghVd4EgXPGZbYkOA&8U$@KHDBWNMR0Q”;  
char letters;

float bright;  
char chars;

PFont font;  
float fontSize = 1.5;

void setup() {  
size(800, 800);

// This the default video input, see the GettingStartedCapture  
// example if it creates an error  
movie = new Movie(this, “001.mp4”);  
movie.loop();

int count = movie.width \* movie.height;  
//println(count);

font = loadFont(“UniversLTStd-Light-48.vlw”);

// for the 256 levels of brightness, distribute the letters across  
// the an array of 256 elements to use for the lookup  
letters = new char[256];  
for (int i = 0; i \< 256; i++) {  
int index = int(map(i, 0, 256, 0, letterOrder.length()));  
letters[i] = letterOrder.charAt(index);  
}

// current characters for each position in the video  
chars = new char[count];

// current brightness for each point  
bright = new float[count];  
for (int i = 0; i \< count; i++) {  
// set each brightness at the midpoint to start  
bright[i] = 128;  
}  
}

void movieEvent(Movie m) {  
m.read();  
}

void draw() {  
background(255);  
//image(movie, 0, 0, width, height);

pushMatrix();

float hgap = width / float(movie.width);  
float vgap = height / float(movie.height);

scale(max(hgap, vgap) \* fontSize);  
textFont(font, fontSize);

int index = 0;  
movie.loadPixels();

for (int y = 1; y \< movie.height; y++) {

```
// Move down for next line
translate(0, 1.0 / fontSize);

pushMatrix();
for (int x = 0; x < movie.width; x++) {
  int pixelColor = movie.pixels[index];
  // Faster method of calculating r, g, b than red(), green(), blue() 
  int r = (pixelColor >> 16) & 0xff;
  int g = (pixelColor >> 8) & 0xff;
  int b = pixelColor & 0xff;

  // Another option would be to properly calculate brightness as luminance:
  // luminance = 0.3*red + 0.59*green + 0.11*blue
  // Or you could instead red + green + blue, and make the the values[] array
  // 256*3 elements long instead of just 256.
  int pixelBright = max(r, g, b);

  // The 0.1 value is used to damp the changes so that letters flicker less
  float diff = pixelBright - bright[index];
  bright[index] += diff * 0.1;

  fill(pixelColor);
  int num = int(bright[index]);
  text(letters[num], 0, 0);
  
  // Move to the next pixel
  index++;

  // Move over for next character
  translate(1.0 / fontSize, 0);
}
popMatrix();

```

}  
popMatrix();

if (cheatScreen) {  
//image(video, 0, height - video.height);  
// set() is faster than image() when drawing untransformed images  
set(0, height - movie.height, movie);  
}  
}

/\*\*

- Handle key presses:
- ‘c’ toggles the cheat screen that shows the original image in the corner
- ‘g’ grabs an image and saves the frame to a tiff image
- ‘f’ and ‘F’ increase and decrease the font size  
\*/  
void keyPressed() {  
switch (key) {  
case ‘g’: saveFrame(); break;  
case ‘c’: cheatScreen = !cheatScreen; break;  
case ‘f’: fontSize \*= 1.1; break;  
case ‘F’: fontSize \*= 0.9; break;  
}  
}

---

<div class="post-metadata">

### Author: ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)
#### Post date: [August 27, 2022, 10:43pm UTC](https://discourse.processing.org/t/make-an-ascii-video/38507/3 "2022-08-27T22:43:28Z")

</div>

Hello,

This topic may offer some insights:

> [@OpenCV error in Processing 4.0b2](https://discourse.processing.org/t/opencv-error-in-processing-4-0b2/33284/10):
>
> Hello @bhaskar1955, The example works with: Windows 10 Processing 4.01 (August 9, 2022) [Releases · jaegonlee/opencv-processing · GitHub](https://github.com/jaegonlee/opencv-processing/releases) I did get this error: And added this delay to correct that problem: void setup() { size(720, 480); video = new Movie(this, "street.mov"); opencv = new OpenCV(this, 720, 480); opencv.startBackgroundSubtraction(5, 3, false); println(frameCount, video.width, video.height); video.loop(); video.play(); int t1 = millis();…

I made the same check for the movie width otherwise I got an error.

I did get this working with the Processing examples converting live video to movie video:

 ![image](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/f/e/fe3ae74043b6e8e9bdda4af62601b5a411097e4f.jpeg)

Please format your code as per instructions here:  
[https://discourse.processing.org/faq#format-your-code](https://discourse.processing.org/faq#format-your-code)

`:)`

---

<div class="post-metadata">

### Author: ![Roklair](https://avatars.discourse-cdn.com/v4/letter/r/e480ec/32.png) [@Roklair](https://discourse.processing.org/u/Roklair)
#### Post date: [August 28, 2022, 7:31am UTC](https://discourse.processing.org/t/make-an-ascii-video/38507/4 "2022-08-28T07:31:05Z")

</div>

Sorry here the code formated.  
Thanks

```auto
/**
 * ASCII Video
 * by Ben Fry. 
 *
 * 
 * Text characters have been used to represent images since the earliest computers.
 * This sketch is a simple homage that re-interprets live video as ASCII text.
 * See the keyPressed function for more options, like changing the font size.
 */

import processing.video.*;
Movie movie;
boolean cheatScreen;

// All ASCII characters, sorted according to their visual density
String letterOrder =
  " .`-_':,;^=+/\"|)\\<>)iv%xclrs{*}I?!][1taeo7zjLu" +
  "nT#JCwfy325Fp6mqSghVd4EgXPGZbYkOA&8U$@KHDBWNMR0Q";
char[] letters;

float[] bright;
char[] chars;

PFont font;
float fontSize = 1.5;

void setup() {
  size(800, 800);

  // This the default video input, see the GettingStartedCapture 
  // example if it creates an error
  movie = new Movie(this, "001.mp4");
  movie.loop();  
  
  int count = movie.width * movie.height;
  //println(count);

  font = loadFont("UniversLTStd-Light-48.vlw");

  // for the 256 levels of brightness, distribute the letters across
  // the an array of 256 elements to use for the lookup
  letters = new char[256];
  for (int i = 0; i < 256; i++) {
    int index = int(map(i, 0, 256, 0, letterOrder.length()));
    letters[i] = letterOrder.charAt(index);
  }

  // current characters for each position in the video
  chars = new char[count];

  // current brightness for each point
  bright = new float[count];
  for (int i = 0; i < count; i++) {
    // set each brightness at the midpoint to start
    bright[i] = 128;
  }
}

void movieEvent(Movie m) {
  m.read();
}

void draw() {
  background(255);
  //image(movie, 0, 0, width, height);

  pushMatrix();

  float hgap = width / float(movie.width);
  float vgap = height / float(movie.height);

  scale(max(hgap, vgap) * fontSize);
  textFont(font, fontSize);

  int index = 0;
  movie.loadPixels();

  for (int y = 1; y < movie.height; y++) {

    // Move down for next line
    translate(0, 1.0 / fontSize);

    pushMatrix();
    for (int x = 0; x < movie.width; x++) {
      int pixelColor = movie.pixels[index];
      // Faster method of calculating r, g, b than red(), green(), blue() 
      int r = (pixelColor >> 16) & 0xff;
      int g = (pixelColor >> 8) & 0xff;
      int b = pixelColor & 0xff;

      // Another option would be to properly calculate brightness as luminance:
      // luminance = 0.3*red + 0.59*green + 0.11*blue
      // Or you could instead red + green + blue, and make the the values[] array
      // 256*3 elements long instead of just 256.
      int pixelBright = max(r, g, b);

      // The 0.1 value is used to damp the changes so that letters flicker less
      float diff = pixelBright - bright[index];
      bright[index] += diff * 0.1;

      fill(pixelColor);
      int num = int(bright[index]);
      text(letters[num], 0, 0);
      
      // Move to the next pixel
      index++;

      // Move over for next character
      translate(1.0 / fontSize, 0);
    }
    popMatrix();
  }
  popMatrix();

  if (cheatScreen) {
    //image(video, 0, height - video.height);
    // set() is faster than image() when drawing untransformed images
    set(0, height - movie.height, movie);
  }
}

/**
 * Handle key presses:
 * 'c' toggles the cheat screen that shows the original image in the corner
 * 'g' grabs an image and saves the frame to a tiff image
 * 'f' and 'F' increase and decrease the font size
 */
void keyPressed() {
  switch (key) {
    case 'g': saveFrame(); break;
    case 'c': cheatScreen = !cheatScreen; break;
    case 'f': fontSize *= 1.1; break;
    case 'F': fontSize *= 0.9; break;
  }
}

```
