Introduction
For the purpose of learning how to work with pictures in Java, I created an ASCII-Art Generator. The program can do two things:
- Convert pictures into ASCII-Art
- Convert text into ASCII-Art
I splitted the task into several steps:
- Convert text to image
- Read image and its height and width
- Saving data of each pixel
- Convert pixel data into ASCII-char
- Printing
Code
Control.java
This class is responsible for the user-interaction and the creation of an instance of the needed class(-es).
import java.io.IOException;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Control {
public static void main(String[] args) {
System.out.println("Picture to ASCII (1) or text to ASCII (2)?");
Scanner scan = new Scanner(System.in);
int decision;
while(true) {
try {
decision = scan.nextInt();
if(decision > 2 || decision < 1) {
throw new InputMismatchException();
}
break;
}
catch(InputMismatchException e) { //User enters not a number or a number > 2 or < 1
System.out.println("Enter (1) or (2):");
scan.nextLine(); //Clear Scanner
}
}
scan.nextLine(); //To clear scanner
switch(decision) {
case(1):
System.out.println("Want to reverse brightness? (yes = 1, no = 2)");
int reverse;
while(true) {
try {
reverse = scan.nextInt();
if(reverse > 2 || reverse < 1) {
throw new InputMismatchException();
}
break;
}
catch(InputMismatchException e) { //User enters not a number or a number > 2 or < 1
System.out.println("Enter (1) or (2):");
scan.nextLine();
}
}
boolean reverseBrightness;
reverseBrightness = reverse == 1 ? true : false; //if(reserve == 1) {reverseBrightness = true} else {reverseBrightness = false};
System.out.println("Enter filename:");
scan.nextLine();
String filename;
while(true) {
try {
filename = scan.nextLine();
Picture picture = new Picture(filename, reverseBrightness);
System.out.println("Successful!");
break;
}
catch(IOException e) { //IIOException occurs when file not found
System.out.println("File not found. Enter filename:");
}
}
break;
case(2):
System.out.println("Enter text:");
String str = scan.nextLine();
try {
AsciiText text = new AsciiText(str);
}
catch(IOException e) {
e.printStackTrace();
}
System.out.println("Successful!");
break;
default:
System.out.println("An Error occured!"); //Impossible to happen, just to adhere to best practice
break;
}
scan.close();
}
}
Picture.java
Responsible for the conversion of pictures into ASCII-art.
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Picture {
private BufferedImage img;
private int height;
private int width;
private Triplet[][] array;
private int[][] brightness;
private final int MAX_BRIGHTNESS = 255;
private char[][] ascii;
private final String str = "$@B%8&MW#*oahkbdpqwmZ0OQLCJUYXzcvunxrjft/\\\\(|)1{}][?-_+~i!Il:;,\"\\^`"; //ASCII-chars
public Picture(String filename, boolean reverse) throws IOException {
img = ImageIO.read(new File(filename));
this.height = img.getHeight();
this.width = img.getWidth();
this.fillArray();
this.fillBrightnessArray();
if(reverse) {
this.reverseBrightness();
}
this.fillAscii();
this.printAscii();
}
//Saving the proportion of red, green and blue of each pixel
private void fillArray() {
array = new Triplet[height][width];
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
int getRGB = img.getRGB(j, i);
int red = (getRGB>>16) & 0xff;
int green = (getRGB>>8) & 0xff;
int blue = getRGB & 0xff;
array[i][j] = new Triplet(red, green, blue);
}
}
}
//Calculating the brightness of each pixel
private void fillBrightnessArray() {
brightness = new int[height][width];
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
brightness[i][j] = (array[i][j].getFirst() + array[i][j].getSecond() + array[i][j].getThird()) / 3;
}
}
}
//Reversing the brightness-values
private void reverseBrightness() {
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
brightness[i][j] = MAX_BRIGHTNESS - brightness[i][j];
if(brightness[i][j] < 0) {
brightness[i][j] *= -1;
}
}
}
}
//Converting brightness into appropriate ASCII-char
private void fillAscii() {
ascii = new char[height][width];
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
ascii[i][j] = str.charAt(brightness[i][j] / 4);
}
}
}
//print completed ASCII-art to file
private void printAscii() {
try {
FileWriter writer = new FileWriter("ascii.txt");
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
writer.write(ascii[i][j] + "" + ascii[i][j] + "" + ascii[i][j]);
}
writer.write("\n");
}
writer.close();
}
catch(IOException e) {
e.printStackTrace();
}
}
}
AsciiText.java
Responsible for the second task: The conversion of text.
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class AsciiText {
private final String filename = "text.jpg";
public AsciiText(String text) throws IOException {
int width = 200;
int height = 40;
int imageType = BufferedImage.TYPE_INT_RGB;
//Creating image with text
BufferedImage image = new BufferedImage(width, height, imageType);
Graphics graphic = image.getGraphics();
int fontSize = 15;
graphic.setFont(new Font("Arial", Font.PLAIN, fontSize));
Graphics2D graphics = (Graphics2D) graphic;
int xCoordinate = 5;
int yCoordinate = 25;
graphics.drawString(text, xCoordinate, yCoordinate);
ImageIO.write(image, "jpg", new File(filename));
//Converting created image to ASCII-art
Picture picture = new Picture(filename, true);
}
}
Triplet.java
Simple datastructure that is able to save three integers (a triplet of the form (a, b, c)); in this case the (RGB-values).
public class Triplet {
private int first;
private int second;
private int third;
public Triplet(int first, int second, int third) {
this.first = first;
this.second = second;
this.third = third;
}
public int getFirst() {
return first;
}
public int getSecond() {
return second;
}
public int getThird() {
return third;
}
}
Attribution
/*
* Attribution:
* The code in this question was created with the help of the following question(s) and their answer(s).
* These come from the Stack Exchange network, where content is licensed under CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/):
* Question by Jeel Shah (https://stackoverflow.com/users/681159/jeel-shah): https://stackoverflow.com/questions/7098972/ascii-art-java
* Answer by Peter Lawrey (https://stackoverflow.com/users/57695/peter-lawrey)
* Question by aneuryzm (https://stackoverflow.com/users/257022/aneuryzm): https://stackoverflow.com/questions/6010843/java-how-to-store-data-triple-in-a-list
* Answer by Bala R (https://stackoverflow.com/users/273200/bala-r)
*/
Example
One example of the text to ascii-art-conversion is the "Hello World!"-message at the beginning of this question.
To demonstrate the conversion of pictures, I used the well known poison-symbol, which you can find here:
Question
How can I improve the code? What about the general code structure? Did I miss anything significant? Do you have any other suggestions?