In this lab, we will be turning images into ascii art. There are various kinds of ascii art, including 'hand-made' and more or less sophisticated algorithms for turning existing bitmap images into ascii characters. We will use a simple, but effective algorithm for converting bitmaps to ascii.

How it works

The basic idea is to replace the pixels of an image with text characters. Some characters (e.g.) have a very low pixel density (very few of the pixels in the character are black) whereas others (e.g. '#') are very dense, so we can use characters of different densities to approximate the grey levels in an image. Two important points to note:

1. We have to use a 'fixed width' font in which all characters are the same size. Most code editors (including Eclipse) and the command line terminal use fixed width fonts. Most of the fonts used for word processing are variable width (apart from the 'typewriter' fonts).

2. We need to take account of the aspect ratio of the font. Typically this is around 2:1 (in many cases exactly) so we can easily account for this by only using every second line of the image.

In exercise 1, we will use this process to make this asci image: see image.

We will use the following 10-level grey scale of characters (sometimes called a 'ramp'). Note, the quotes are not part of the set, and the last character (white) is a space.

"@%#*+=- :. "

Exercise 1

First we need to load the image from disk into memory. Follow these steps:

1. Create a new Java project, and add two classes: a main class and a class called Image2Ascii.

2. Copy the code in Listing 1 into your Image2Ascii class.

Listing 1

import java.awt.*;
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;

public class Image2Ascii {
BufferedImage bImage = null;
int imageWidth = 0;
int imageHeight = 0;

void LoadImage(String fileName) {
try {
bImage = ImageIO.read(new File(fileName));
imageWidth = bImage.getWidth();
imageHeight = bImage.getHeight();
} catch(Exception e) {
System.out.println("could not open image file " + fileName);
}
}
}

Listing 1 notes: There are some new concepts here that we will cover in depth later on, so you can treat this as a black box for now. Note we are using a try/catch block. This is used to handle exceptions (errors). The constructor of the file handling class (File) will 'throw an exception if the file can't be opened. If this happens, the code in the catch block is executed.

3. Add a 2D Array of integers to hold the image grey values. Construct this immediately after the image height and width are determined in the LoadImage method.

4. Fill the 2D array with greyscale values (again, in the LoadImage method). To do this use nested for loops. Use the following code to get the red green and blue values from a pixel at x = 1, y = j, and calculate a grey value. It is usual to emphasise green in this calculation (the human eye is most sensitive to green light).

Color pixel = new Color(bImage.getRGB(i, j));
int red = pixel.getRed();
int green = pixel.getGreen();
int blue = pixel.getBlue();
int grey = (red + 2*green + blue) / 4;

5. Download the cat.png image from Moodle and copy it to your eclipse project directory (for example, workspace/Week16), and check it loads by adding the following code to your main method. You won't see anything yet, but you can check it runs without error.

Image2Ascii image2ascii = new Image2Ascii();
image2ascii.LoadImage("cat.png");

6. Add a new method to the Image 2Ascii class called Print which prints the 2D array as an ascii image. There are some hints below to help you with this.

Hints:

a) Use nested for loops, with the outer loop representing the y coordinate (lines) and the inner loop the x coordinate. Make the outer loop skip every other line.

b) Add a String variable to the class to store the character lookup, e.g.

String ramp = "@%#*+=-:. ";

c) Use the charAt method of the string class to get single characters from the ramp string for printing.

d) Use System.out.print to print each character in a line, and System.out.println at the end of the line (after the inner for loop) to print the carriage return.

e) Convert a 0-255 grey level into a value between 0 and 9 (which you can use to look up the ramp) using

rampIndex = 10 * grey / 256;

7. Test the Print method and confirm it produces the correct image. If you use a light-on-dark colour scheme, you will need to reverse the ramp string.

Add a new method, PrintWarhol, that prints a 2x2 pop art style version of an image, with alternate images in negative. Test it using the mona.png image (64x64) on Moodle, which should produce the following result: see image.

Academic Honesty!
It is not our intention to break the school's academic policy. Posted solutions are meant to be used as a reference and should not be submitted as is. We are not held liable for any misuse of the solutions. Please see the frequently asked questions page for further questions and inquiries.
Kindly complete the form. Please provide a valid email address and we will get back to you within 24 hours. Payment is through PayPal, Buy me a Coffee or Cryptocurrency. We are a nonprofit organization however we need funds to keep this organization operating and to be able to complete our research and development projects.