Arrays and Images
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
public class ImageIOTest {
public static void main( String[] args ){
BufferedImage img = null; // buffer type
try {
// Name of file and directories
String name = "MonaLisa";
String in = "../images/";
String out = "../images/tmp/";
// Either use URL or File for reading image using ImageIO
File imageFile = new File(in + name + ".png");
img = ImageIO.read(imageFile); // set buffer of image data
// ImageIO Image write to gif in Java
// Documentation https://docs.oracle.com/javase/tutorial/2d/images/index.html
ImageIO.write(img, "gif", new File(out + name + ".gif") ); // write buffer to gif
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Success");
}
}
ImageIOTest.main(null);
-
The java.awt.Image class is the superclass that represents graphical images as rectangular arrays of pixels.
-
The java.awt.image.BufferedImage class, which extends the Image class to allow the application to operate directly with image data (for example, retrieving or setting up the pixel color). Applications can directly construct instances of this class.
-
The BufferedImage class is a cornerstone of the Java 2D immediate-mode imaging API. It manages the image in memory and provides methods for storing, interpreting, and obtaining pixel data. Since BufferedImage is a subclass of Image it can be rendered by the Graphics and Graphics2D methods that accept an Image parameter.
-
A BufferedImage is essentially an Image with an accessible data buffer. It is therefore more efficient to work directly with BufferedImage. A BufferedImage has a ColorModel and a Raster of image data. The ColorModel provides a color interpretation of the image's pixel data.
Reading/Loading an Image
-
Java 2D supports loading these external image formats into its BufferedImage format using its Image I/O API which is in the javax.imageio package. Image I/O has built-in support for GIF, PNG, JPEG, BMP, and WBMP. Image I/O is also extensible so that developers or administrators can "plug-in" support for additional formats. For example, plug-ins for TIFF and JPEG 2000 are separately available.
-
To load an image from a specific file use the following code, which is from LoadImageApp.java:
BufferedImage img = null;
try {
img = ImageIO.read(new File("strawberry.jpg"));
} catch (IOException e) {
}
-
Image I/O recognises the contents of the file as a JPEG format image, and decodes it into a BufferedImage which can be directly used by Java 2D.
-
LoadImageApp.java shows how to display this image.
Image Scaling and ASCII Conversion
In this example we print out a row of text for each row in the image. However, it seems as if the image is too tall. To address this problem, try to output a single character per block of pixels. In particular, average the grayscale values in a rectangular block that’s twice as tall as it is wide, and print out a single character for this block.
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 final String greyscaleDir = "../images/tmp/greyscale/";
private final String redscaleDir = "../images/tmp/redscale/";
private final String greenscaleDir = "../images/tmp/greenscale/";
private final String bluescaleDir = "../images/tmp/bluescale/";
private String inFile;
private String resizedFile;
private String greyscaleFile;
private String redscaleFile;
private String greenscaleFile;
private String bluescaleFile;
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.greyscaleFile = this.greyscaleDir + name + "." + ext;
this.redscaleFile = this.redscaleDir + name + "." + ext;
this.greenscaleFile = this.greenscaleDir + name + "." + ext;
this.bluescaleFile = this.bluescaleDir + 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();) {
for (int j = 0; j < img.getWidth(); j++) {
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) {
}
i = i+3;
}
}
// 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 >= 120) {
str = "^";
} else if (g >= 110) {
str = "&";
} else if (g >= 80) {
str = "8";
} else if (g >= 60) {
str = "#";
} else {
str = "@";
}
return str;
}
//greyscale hack, reference website: https://medium.com/javarevisited/converting-rgb-image-to-the-grayscale-image-in-java-9e1edc5bd6e7
public void greyscale() {
BufferedImage img = null; //In Java programming, null can be assigned to any variable of a reference type (that is, a non-primitive type) to indicate that the variable does not refer to any object or array.
BufferedImage greyscaleImg = null;
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
greyscaleImg = img;
for (int i=0; i<img.getHeight(); i++) {
for (int j=0; j<img.getWidth(); j++) {
Color c = new Color(img.getRGB(j, i));
int red = (int) (c.getRed() * 0.299);
int green = (int) (c.getGreen() * 0.587);
int blue = (int) (c.getBlue() * 0.114);
Color newColor = new Color (red+green+blue, red+green+blue, red+green+blue);
greyscaleImg.setRGB(j, i, newColor.getRGB());
}
}
} catch (IOException e) {
return;
}
try {
ImageIO.write(convertToBufferedImage(greyscaleImg), this.ext, new File(greyscaleFile));
} catch (IOException e) {
return;
}
this.inFile = this.greyscaleFile; // use scaled file vs original file in Class
this.setStats();
}
public void redscale() {
BufferedImage img = null; //In Java programming, null can be assigned to any variable of a reference type (that is, a non-primitive type) to indicate that the variable does not refer to any object or array.
BufferedImage redscaleImg = null;
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
redscaleImg = img;
for (int i=0; i<img.getHeight(); i++) {
for (int j=0; j<img.getWidth(); j++) {
Color c = new Color(img.getRGB(j, i));
int red = (int) (c.getRed());
int green = 0;
int blue = 0;
Color newColor = new Color (red, green, blue);
redscaleImg.setRGB(j, i, newColor.getRGB());
}
}
} catch (IOException e) {
return;
}
try {
ImageIO.write(convertToBufferedImage(redscaleImg), this.ext, new File(redscaleFile));
} catch (IOException e) {
return;
}
this.inFile = this.redscaleFile; // use scaled file vs original file in Class
this.setStats();
}
public void greenscale() {
BufferedImage img = null; //In Java programming, null can be assigned to any variable of a reference type (that is, a non-primitive type) to indicate that the variable does not refer to any object or array.
BufferedImage greenscaleImg = null;
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
greenscaleImg = img;
for (int i=0; i<img.getHeight(); i++) {
for (int j=0; j<img.getWidth(); j++) {
Color c = new Color(img.getRGB(j, i));
int red = 0;
int green = (int) (c.getGreen());
int blue = 0;
Color newColor = new Color (red, green, blue);
greenscaleImg.setRGB(j, i, newColor.getRGB());
}
}
} catch (IOException e) {
return;
}
try {
ImageIO.write(convertToBufferedImage(greenscaleImg), this.ext, new File(greenscaleFile));
} catch (IOException e) {
return;
}
this.inFile = this.greenscaleFile; // use scaled file vs original file in Class
this.setStats();
}
public void bluescale() {
BufferedImage img = null; //In Java programming, null can be assigned to any variable of a reference type (that is, a non-primitive type) to indicate that the variable does not refer to any object or array.
BufferedImage bluescaleImg = null;
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
bluescaleImg = img;
for (int i=0; i<img.getHeight(); i++) {
for (int j=0; j<img.getWidth(); j++) {
Color c = new Color(img.getRGB(j, i));
int red = 0;
int green = 0;
int blue = (int) (c.getBlue());
Color newColor = new Color (red, green, blue);
bluescaleImg.setRGB(j, i, newColor.getRGB());
}
}
} catch (IOException e) {
return;
}
try {
ImageIO.write(convertToBufferedImage(bluescaleImg), this.ext, new File(bluescaleFile));
} catch (IOException e) {
return;
}
this.inFile = this.bluescaleFile; // use scaled file vs original file in Class
this.setStats();
}
// tester/driver
public static void main(String[] args) throws IOException {
Pics monaLisa = new Pics("MonaLisa", "png");
monaLisa.printStats("Original");
monaLisa.resize(33); //33 percent of the original
monaLisa.printStats("Scaled");
monaLisa.convertToAscii();
monaLisa.greyscale();
monaLisa.redscale();
monaLisa.greenscale();
monaLisa.bluescale();
Pics pumpkin = new Pics("pumpkin", "png");
pumpkin.printStats("Original");
pumpkin.resize(33);
pumpkin.printStats("Scaled");
pumpkin.convertToAscii();
pumpkin.greyscale();
pumpkin.greenscale();
monaLisa.bluescale();
}
}
Pics.main(null);
Problem (greyscale)
(output) Original: 499298 389x413 ../images/MonaLisa.png Scaled: 55625 128x136 ../images/tmp/greyscale/MonaLisa.png
java.lang.NullPointerException: null
at java.base/java.io.File. picture appeared in the tmp/greyscale/ is not greyscaled (original image) solved: public Pics(String name, String ext) {
this.ext = ext;
this.inFile = this.inDir + name + "." + ext;
this.resizedFile = this.outDir + name + "." + ext;
this.resizedFile = this.greyscaleDir + name + "." + ext;
this.asciiFile = this.outDir + name + ".txt";
this.setStats();
} public Pics(String name, String ext) {
this.ext = ext;
this.inFile = this.inDir + name + "." + ext;
this.resizedFile = this.outDir + name + "." + ext;
this.greyscaleFile = this.greyscaleDir + name + "." + ext;
this.asciiFile = this.outDir + name + ".txt";
this.setStats();
} forgot to change resizedFile to greyscaleFile, so the image appeared in the greyscale directory is the resized image Continue to work with Classes, Arrays, and 2D arrays. FYI, you may need to make a directory /tmp under notebook images. random notes when listening to the lecture: image buffer
(look additional resources if don't understand) changing float into int because you can't do half a pixel not one pixel at a time -> four by eight or eight by four average the rgb values - greyscale
make a new array and work with value inside the array for averaging resource -
conversion table, there may be better out there ie https://www.billmongan.com/Ursinus-CS173-Fall2020/Labs/ASCIIArt
Hacks