Images
Using Java ImageIO to make an ASCII, grayscale, redscale, bluescale, and greenscale Mona Lisa art
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.awt.Graphics2D;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
public class Pics {
private final String inDir = "images/"; // location of images
private final String outDir = "images/tmp/"; // location of created files
private String inFile;
private String resizedFile;
private String asciiFile;
private String ext; // extension of file
private long bytes;
private int width;
private int height;
// Constructor obtains attributes of picture
public Pics(String name, String ext) {
this.ext = ext;
this.inFile = this.inDir + name + "." + ext;
this.resizedFile = this.outDir + name + "." + ext;
this.asciiFile = this.outDir + name + ".txt";
this.setStats();
}
// An image contains metadata, namely size, width, and height
public void setStats() {
BufferedImage img;
try {
Path path = Paths.get(this.inFile);
this.bytes = Files.size(path);
img = ImageIO.read(new File(this.inFile));
this.width = img.getWidth();
this.height = img.getHeight();
} catch (IOException e) {
}
}
// Console print of data
public void printStats(String msg) {
System.out.println(msg + ": " + this.bytes + " " + this.width + "x" + this.height + " " + this.inFile);
}
// Convert scaled image into buffered image
public static BufferedImage convertToBufferedImage(Image img) {
// Create a buffered image with transparency
BufferedImage bi = new BufferedImage(
img.getWidth(null), img.getHeight(null),
BufferedImage.TYPE_INT_ARGB);
// magic?
Graphics2D graphics2D = bi.createGraphics();
graphics2D.drawImage(img, 0, 0, null);
graphics2D.dispose();
return bi;
}
// Scale or reduce to "scale" percentage provided
public void resize(int scale) {
BufferedImage img = null;
Image resizedImg = null;
int width = (int) (this.width * (scale/100.0) + 0.5);
int height = (int) (this.height * (scale/100.0) + 0.5);
try {
// read an image to BufferedImage for processing
img = ImageIO.read(new File(this.inFile)); // set buffer of image data
// create a new BufferedImage for drawing
resizedImg = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
} catch (IOException e) {
return;
}
try {
ImageIO.write(convertToBufferedImage(resizedImg), this.ext, new File(resizedFile));
} catch (IOException e) {
return;
}
this.inFile = this.resizedFile; // use scaled file vs original file in Class
this.setStats();
}
// convert every pixel to an ascii character (ratio does not seem correct)
public void convertToAscii() {
BufferedImage img = null;
PrintWriter asciiPrt = null;
FileWriter asciiWrt = null;
try {
File file = new File(this.asciiFile);
Files.deleteIfExists(file.toPath());
} catch (IOException e) {
System.out.println("Delete File error: " + e);
}
try {
asciiPrt = new PrintWriter(asciiWrt = new FileWriter(this.asciiFile, true));
} catch (IOException e) {
System.out.println("ASCII out file create error: " + e);
}
try {
img = ImageIO.read(new File(this.inFile));
} catch (IOException e) {
}
for (int i = 0; i < img.getHeight(); i+=2) {
for (int j = 0; j < img.getWidth(); j+=1) {
Color col = new Color(img.getRGB(j, i));
double pixVal = (((col.getRed() * 0.30) + (col.getBlue() * 0.59) + (col
.getGreen() * 0.11)));
try {
asciiPrt.print(asciiChar(pixVal));
asciiPrt.flush();
asciiWrt.flush();
} catch (Exception ex) {
}
}
try {
asciiPrt.println("");
asciiPrt.flush();
asciiWrt.flush();
} catch (Exception ex) {
}
}
}
// conversion table, there may be better out there ie https://www.billmongan.com/Ursinus-CS173-Fall2020/Labs/ASCIIArt
public String asciiChar(double g) {
String str = " ";
if (g >= 240) {
str = " ";
} else if (g >= 210) {
str = ".";
} else if (g >= 190) {
str = "-";
} else if (g >= 170) {
str = "*";
} else if (g >= 160) {
str = "+";
} else if (g >= 150) {
str = "j";
}else if (g >= 140) {
str = "n";
}else if (g >= 130) {
str = "V";
} else if (g >= 120) {
str = "3";
} else if (g >= 110) {
str = "5";
} else if (g >= 100) {
str = "&";
} else if (g >= 90) {
str = "g";
}else if (g >= 80) {
str = "8";
} else if (g >= 60) {
str = "#";
} else {
str = "@";
}
return str;
}
// tester/driver
public static void main(String[] args) throws IOException {
Pics monaLisa = new Pics("MonaLisa", "png");
monaLisa.printStats("Original");
monaLisa.resize(33);
monaLisa.printStats("Scaled");
monaLisa.convertToAscii();
}
}
Pics.main(null);
Explanation of code
First, the monaLisa
object is created, which calls the Pics
constructor and passes in a name
of MonaLisa
and an ext
(extension) of .png
. These are assigned to the attributes, creating an input file (images/MonaLisa.png
), an output (resized) file (images/MonaLisa.png
), and an output (ASCII) file (images/tmp/MonaLisa.txt
).
Next, the setStats()
method is called. The path of the input file is assigned to the path
object. The number of bytes
is also assigned, and then ImageIO reads the input file and obtains its width and height, assigning them to their respective variables.
Now going back to the main method, the monaLisa
object calls the printStats()
method and passes in the argument of "Original"
. This basically outputs some information of the input file, such as its size, width, and height. As you can see in the output above, the printStats()
method outputs, Original: 499298 389x413 images/MonaLisa.png
.
Afterwards, the monaLisa
object calls the resize()
method with an argument of 33
(resize the image to 33%). An Image
object is created. Note: this is really important, the Image
object needs to be created out of the try catch
block, because if it is created within, the scope of the Image
object is within the try catch
block and can not be accessed outside. See this for more info. Moving on, the width
and height
are defined based on the resized scale
, and the input file is once again read into img
. The resizedImg
is obtained by using the getScaledInstance
method and assigning it the resized width
and height
. Next, resizedImg
is converted into a buffered image with the name of the resizedFile
(images/tmp/MonaLisa.png). The resizedFile
is then set as the path of the input file. Once again, the setStats()
method is called.
Because of scope of variables, some values of the variables have changed. The path of the input file (inFile
) is now assigned to path
. The size of the resized file is recorded, and the file is also read in by ImageIO. Additionally, the width and height of the resized file is recorded.
Going back to the main method, the printStats()
method is called. Same thing as before, this outputs Scaled: 55625 128x136 images/tmp/MonaLisa.png
.
Lastly, the convertToAscii()
method is called. Once again, the Image
object needs to be set as null
outside of the try catch
block in order to fulfill the scope of the variable. The first try catch
block ensures that if there is already an Ascii file in the output directory, the file would be removed. Next, the PrintWriter
and FileWriter
object is called to output text (ASCII characters) into the ASCII file (images/tmp/MonaLisa.txt
). ImageIO then reads the input file.
Onto the for loop, each pixel of the image is iterated, and a value is calculated based on the RGB value of the pixel. The larger the value (closer to white, or 255), the less space the ASCII character will pick up. As for smaller values (closer to black, or 0), the ASCII character will take up more space. This is called by the asciiChar(double g)
method, and it returns the ASCII character.
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.Image;
import java.awt.Graphics2D;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
abstract class Pics {
final String inDir = "images/"; // location of images
final String outDir = "images/tmp/"; // location of created files
String inFile;
String resizedFile;
String grayscaleFile;
String outFile;
String ext; // extension of file
long bytes;
int width;
int height;
// Constructor obtains attributes of picture
public Pics(String name, String ext) {
this.ext = ext;
this.inFile = this.inDir + name + "." + ext;
this.outFile = this.outDir + name + "New." + ext;
}
// convert every pixel to an ascii character (ratio does not seem correct)
public void changePic() {
BufferedImage img;
try {
File file = new File(this.outFile);
Files.deleteIfExists(file.toPath());
} catch (IOException e) {
System.out.println("Delete File error: " + e);
}
test();
}
protected abstract void test();
}
public class Grayscale extends Pics {
public Grayscale(String name, String ext) {
super(name, ext);
}
protected void test() {
BufferedImage img;
try {
img = ImageIO.read(new File(this.inFile));
for (int i = 0; i < img.getHeight(); i++) {
for (int j = 0; j < img.getWidth(); j++) {
Color col = new Color(img.getRGB(j, i));
int red = (int)(col.getRed() * 0.299);
int green = (int)(col.getGreen() * 0.587);
int blue = (int)(col.getBlue() * 0.114);
Color rgb = new Color(red + green + blue, red + green + blue, red + green + blue);
img.setRGB(j, i, rgb.getRGB());
}
}
ImageIO.write(img, "png", new File(super.outFile));
} catch (IOException e) {
}
}
// tester/driver
public static void main(String[] args) throws IOException {
// Pics monaLisa = new Pics("MonaLisa", "png");
Grayscale monaLisa = new Grayscale("MonaLisa", "png" );
monaLisa.changePic();
}
}
Grayscale.main(null);
public class Redscale extends Pics {
public Redscale(String name, String ext) {
super(name, ext);
}
protected void test() {
BufferedImage img;
try {
img = ImageIO.read(new File(this.inFile));
for (int i = 0; i < img.getHeight(); i++) {
for (int j = 0; j < img.getWidth(); j++) {
Color col = new Color(img.getRGB(j, i));
int red = (int)(col.getRed());
Color rgb = new Color(red, 0, 0);
img.setRGB(j, i, rgb.getRGB());
}
}
ImageIO.write(img, "png", new File(super.outFile));
} catch (IOException e) {
}
}
// tester/driver
public static void main(String[] args) throws IOException {
// Pics monaLisa = new Pics("MonaLisa", "png");
Redscale monaLisa = new Redscale("MonaLisa", "png" );
monaLisa.changePic();
}
}
Redscale.main(null);
public class Bluescale extends Pics {
public Bluescale(String name, String ext) {
super(name, ext);
}
protected void test() {
BufferedImage img;
try {
img = ImageIO.read(new File(this.inFile));
for (int i = 0; i < img.getHeight(); i++) {
for (int j = 0; j < img.getWidth(); j++) {
Color col = new Color(img.getRGB(j, i));
int blue = (int)(col.getBlue());
Color rgb = new Color(0, 0, blue);
img.setRGB(j, i, rgb.getRGB());
}
}
ImageIO.write(img, "png", new File(super.outFile));
} catch (IOException e) {
}
}
// tester/driver
public static void main(String[] args) throws IOException {
// Pics monaLisa = new Pics("MonaLisa", "png");
Bluescale monaLisa = new Bluescale("MonaLisa", "png" );
monaLisa.changePic();
}
}
Bluescale.main(null);
public class Greenscale extends Pics {
public Greenscale(String name, String ext) {
super(name, ext);
}
protected void test() {
BufferedImage img;
try {
img = ImageIO.read(new File(this.inFile));
for (int i = 0; i < img.getHeight(); i++) {
for (int j = 0; j < img.getWidth(); j++) {
Color col = new Color(img.getRGB(j, i));
int green = (int)(col.getGreen());
Color rgb = new Color(0, green, 0);
img.setRGB(j, i, rgb.getRGB());
}
}
ImageIO.write(img, "png", new File(super.outFile));
} catch (IOException e) {
}
}
// tester/driver
public static void main(String[] args) throws IOException {
// Pics monaLisa = new Pics("MonaLisa", "png");
Greenscale monaLisa = new Greenscale("MonaLisa", "png" );
monaLisa.changePic();
}
}
Greenscale.main(null);