The programs use the following Java classes:
The programs and .jpg files are available for download in the ENGR 131 Code Repository. Specifically, the programs are
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;
public class jpg2pngHC
{
// Needed b/c I didn't use try-catch; see D&D, p. 647
// vvvvvvvvvvvvvvvvvv
public static void main (String args[]) throws IOException {
// open and read the input image
File inputFile = new File("bakeonceeatanywhere.jpg");
BufferedImage input = ImageIO.read(inputFile);
// write the output image
File outputFile = new File("bakeonceeatanywhere.png");
ImageIO.write(input, "png", outputFile);
}
}
This assumes that the file bakeonceeatanywhere.jpg exists in the same directory as the Java program jpg2pngHC
Here are the two images (they look nearly identical because they
are just the same image stored in different formats):
|
| |
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;
public class jpg2png
{
public static void main (String args[]) throws IOException {
System.out.println("Converting "+args[0]+".jpg to "+args[0]+".png ...");
File inputFile = new File(args[0]+".jpg");
BufferedImage input = ImageIO.read(inputFile);
File outputFile = new File(args[0]+".png");
ImageIO.write(input, "png", outputFile);
}
}
Example usage (at DrJava Interactions Console or MS-DOS or MacOSX Terminal prompt):
java jpg2png bakeonceeatanywhere java jpg2png cooljava java jpg2png javaiscool
This assumes that the files bakeonceeatanywhere.jpg, cooljava.jpg, and javaiscool.jpg exist in the same directory as the Java program jpg2png
Here are the input and output images for the latter two cases
(again looking expectedly identical):
| | | | |
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;
public class NewImage
{
// 0xNUM is how to input HEXadecimal numbers (base 16: digits 0-F) in Java
public static final int BLACK = 0, WHITE = 0xFFFFFF;
public static void main (String args[]) throws IOException {
// create a new, "blank" 300 by 300 image
BufferedImage myimage = new BufferedImage(300,300,BufferedImage.TYPE_INT_RGB);
// set the values for the image
for (int i=0; i<300; i++) {
for (int j=0; j<300; j++) {
if (i%2==0) myimage.setRGB(i,j,WHITE);
else myimage.setRGB(i,j,BLACK);
}
}
// store the image in a file
File outImage = new File("myimage.jpg");
ImageIO.write(myimage, "jpg", outImage);
}
}
The output of this file looks like:We can add some color to the above using the following program:
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;
public class NewImage2
{
// See http://cloford.com/resources/colours/500col.htm for HEX color codes
public static final int BLACK = 0, WHITE = 0xFFFFFF;
public static final int BLUE = 0xFF, GREEN = 0xFF00, RED=0xFF0000;
public static final int CYAN = GREEN+BLUE, MAGENTA = RED+BLUE, YELLOW = RED+GREEN;
// Converts R-G-B values to a single integer
// See http://www.tayloredmktg.com/rgb/ for RGB color codes
public static int RGBint (int R, int G, int B) {
return (R*256*256+G*256+B);
}
public static void main (String args[]) throws IOException {
// create a new, "blank" 500 by 300 image
BufferedImage myimage = new BufferedImage(500,300,BufferedImage.TYPE_INT_RGB);
// See http://www.tayloredmktg.com/rgb/ for RGB color codes
int goldenrod = RGBint(184, 134, 11);
int thistle = RGBint(216, 191, 216);
// set the values for the image
for (int i=0; i<500; i++) {
for (int j=0; j<300; j++) {
if (i<50) myimage.setRGB(i,j,BLACK);
else if (i<100) myimage.setRGB(i,j,WHITE);
else if (i<150) myimage.setRGB(i,j,RED);
else if (i<200) myimage.setRGB(i,j,GREEN);
else if (i<250) myimage.setRGB(i,j,BLUE);
else if (i<300) myimage.setRGB(i,j,CYAN);
else if (i<350) myimage.setRGB(i,j,MAGENTA);
else if (i<400) myimage.setRGB(i,j,YELLOW);
else if (i<450) myimage.setRGB(i,j,goldenrod);
else myimage.setRGB(i,j,thistle);
}
}
// store the image in a file
File outImage = new File("myimage2.jpg");
ImageIO.write(myimage, "jpg", outImage);
}
}
The output image of this program looks like:
Here was my first piece of code to understand some BufferedImage class methods
import java.awt.image.*;
import javax.imageio.*;
import java.io.*;
public class ImageFun
{
// 0xNUM is how to input HEXadecimal numbers (base 16: digits 0-F) in Java
// See http://cloford.com/resources/colours/500col.htm for HEX color codes
public static final int BLACK = 0, WHITE = 0xFFFFFF;
public static void main (String args[]) throws IOException {
// open and read the input image
File inputFile = new File("bakeonceeatanywhere.jpg");
BufferedImage input = ImageIO.read(inputFile);
///////// BEGIN COMMANDS THAT CHANGED FROM VERSION TO VERSION ////////
// test some methods that told me ranges of pixel indices
System.out.println("MinX: "+input.getMinX());
System.out.println("MinY: "+input.getMinY());
System.out.println("Height: "+input.getHeight());
System.out.println("Width: "+input.getWidth());
// my commands to do a simple mod to the picture
for (int i=0; i<100; i++) {
for (int j=0; j<100; j++) {
input.setRGB(i,j,BLACK);
}
}
///////// END COMMANDS THAT CHANGED FROM VERSION TO VERSION ////////
File outImage = new File("imagemod.jpg");
ImageIO.write(input, "jpg", outImage);
}
}
After compiling, I ran the code, which gave the following output
on the screen:
MinX: 0 MinY: 0 Height: 333 Width: 500It also produced a new file called "imagemod.jpg". I viewed this new image file using an application on my computer (Preview on MacOSX). It looked like this:
Notice that there is a 100x100 black square in the top-left corner (which is
a little hard to see because the picture itself is black in that
corner).
So (0,0) is in the top-left corner, and apparently
the bottom-right is (499, 332) [counting starts from 0].
In any case, I wanted to see my square a little better,
so I modified a small piece of the code above as follows,
with the following result:
for (int i=100; i<200; i++) {
for (int j=100; j<200; j++) {
input.setRGB(i,j,BLACK);
}
}
|
|
I then noticed that Duke was nearly covered and decided to try to cover him up a little more.
for (int i=150; i<250; i++) {
for (int j=100; j<200; j++) {
input.setRGB(i,j,BLACK);
}
}
|
|
Cool, he's pretty much covered. But it would be neater if he was covered in white, so it looks like he was never there.
for (int i=150; i<250; i++) {
for (int j=100; j<200; j++) {
input.setRGB(i,j,WHITE);
}
}
|
|
But he's not fully covered, so let's tweak it a bit:
for (int i=150; i<250; i++) {
for (int j=95; j<208; j++) {
input.setRGB(i,j,WHITE);
}
}
|
|
Almost! But we really should be covering him with a trapezoid, not a square, so we don't mess up that orange border. For that, we need to have the horizontal position getting smaller as the vertical one gets larger. I did this by swapping the for loops and trying some linear function (slope).
for (int j=95; j<208; j++) {
for (int i=150-(j-95)/2; i<250; i++) {
input.setRGB(i,j,WHITE);
}
}
|
|
Hmm. Slope is too big, and the white portion begins too far left and ends just a bit too soon.
for (int j=95; j<208; j++) {
for (int i=165-(j-95)/3; i<255; i++) {
input.setRGB(i,j,WHITE);
}
}
|
|
Nailed it! Now it would be nice if the square wasn't so obviously white. Instead of pure white, I'll sample the color of a nearby cake-colored pixel and use that:
for (int j=95; j<208; j++) {
for (int i=165-(j-95)/3; i<255; i++) {
int cakecolor = input.getRGB(256,100);
input.setRGB(i,j,cakecolor);
}
}
|
|
That matches nicely at the top, but is too dark at the bottom. Let's take a sample that's a little lower vertically:
for (int j=95; j<208; j++) {
for (int i=165-(j-95)/3; i<255; i++) {
int cakecolor = input.getRGB(256,200);
input.setRGB(i,j,cakecolor);
}
}
|
|
Now that matches nicely at the bottom, but is too light at the top! Let's take samples from all along vertically to achieve a nice blending all the way down:
for (int j=95; j<208; j++) {
for (int i=165-(j-95)/3; i<255; i++) {
int cakecolor = input.getRGB(256,j);
input.setRGB(i,j,cakecolor);
}
}
|
|
I declare success! My Scrat-like persistence paid off!