import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.imageio.*;
import java.net.*;
import java.io.*;
/** An instance contains
(1) an original image (of class ImageArray),
(2) a possibly altered (by methods in this instance) version of the original image,
(3) methods to process the image
*/
public class ImageProcessor {
/** DM provides methods for extracting components of an rgb pixel. */
public static final DirectColorModel DM= (DirectColorModel) ColorModel.getRGBdefault();
/** The following four constants of this class indicate a color.*/
/** Color gray */
public static final int GRAY= 0;
/** Color red */
public static final int RED= 1;
/** Color green */
public static final int GREEN= 2;
/** Color blue */
public static final int BLUE= 3;
private ImageArray originalIm; // The original image, for restoration purposes
private ImageArray currentIm; // The altered image
/** Constructor: an instance for im.
Precondition: im != null. */
public ImageProcessor(ImageArray im) {
originalIm= im;
currentIm= originalIm.copy();
}
/** = the current image. */
public ImageArray getCurrentImage() {
return currentIm;
}
/** = the original image. */
public ImageArray getOriginalImage() {
return originalIm;
}
/** Invert the current image, replacing each element with its color complement. */
public void invert() {
int len= currentIm.getRows() * currentIm.getCols();
// invert all pixels (leave alpha/transparency value alone)
// invariant: pixels 0..p-1 have been complemented.
for (int p= 0; p < len; p= p+1) {
int rgb= currentIm.getPixel(p);
int red= 255 - DM.getRed(rgb);
int blue= 255 - DM.getBlue(rgb);
int green= 255 - DM.getGreen(rgb);
int alpha= DM.getAlpha(rgb);
currentIm.setPixel(p,
(alpha << 24) | (red << 16) | (green << 8) | blue);
}
}
/** Transpose the current image. */
public void transpose() {
// Follow this plan:
// (1) Create a new ImageArray ia, using currentIM's row-major order array
// and rows and columns, but swap the roles of its numbers
// of rows and columns.
// (2) Store the transpose of the currentIm array in ia, using currentIm's
// 2-parameter getPixel function and ia's 3-parameter setPixel
// function.
// (3) assign ia to currentIm.
int rows= currentIm.getRows();
int cols= currentIm.getCols();
ImageArray ia= new ImageArray(currentIm.getRmoArray(), cols, rows);
//Copy each element ImageArray[r,c] to ia[c,r]
// invariant: rows 0..r-1 have been copied to ia[.., 0..r-1]
for (int r= 0; r != rows; r= r+1)
// invariant: elements [r..0..c-1] have been copied to ia[0..c-1, r]
for (int c= 0; c != cols; c= c+1) {
ia.setPixel(c, r, currentIm.getPixel(r,c));
}
currentIm= ia;
}
/** Reflect the current image around the horizontal middle. */
public void hreflect() {
int rows= currentIm.getRows();
int cols= currentIm.getCols();
int h= 0;
int k= rows-1;
//invariant: rows 0..h-1 and k+1.. have been inverted
while (h < k) {
// Swap row h with row k
// invariant: pixels 0..c-1 of rows h and k have been swapped
for (int c= 0; c != cols; c= c+1) {
currentIm.swapPixels(h, c, k, c);
}
h= h+1; k= k-1;
}
}
/** Reflect the current image around the vertical middle. */
public void vreflect() {
}
/* Filter out color from the current image according to parameter c.
Precondition: c is one of the four color constants GRAY,
RED, GREEN, BLUE of this class.
If c is one of RED, GREEN, BLUE, then filter out that color of the image
by setting it to 0 in all pixels. If c is GRAY, then filter all color out
of the image by setting the three color components of each pixel to the
average of the three.
The alpha component is not changed.
*/
public void filterOut(int c) {
assert c == ImageProcessor.GRAY || c == ImageProcessor.RED ||
c == ImageProcessor.GREEN || c == ImageProcessor.BLUE;
}
/** Put jail bars on the current image:
Put 3-pixel-wide horizontal bars across top and bottom,
Put 4-pixel vertical bars down left and right, and
Put n 4-pixel vertical bars inside, where n is (number of columns - 8) / 50.
The n+2 vertical bars must be evenly spaced. */
public void putInJail() {
}
/** Draw a horizontal 3-pixel-wide bar at row x of the current image
using the color given by rgb components r, g, and b.
Precondition: 0 <= x && x+2 < currentIm.getRows() */
private void drawHBar(int x, int r, int g, int b) {
int rows= currentIm.getRows();
int cols= currentIm.getCols();
/* inv: pixels currentIm[x..x+2][0..c-1] are color c */
for (int c= 0; c < cols; c= c+1) {
int alpha= DM.getAlpha(currentIm.getPixel(x,c));
currentIm.setPixel(x, c, (alpha << 24) | (r << 16) | (g << 8) | b);
currentIm.setPixel(x+1, c, (alpha << 24) | (r << 16) | (g << 8) | b);
currentIm.setPixel(x+2, c, (alpha << 24) | (r << 16) | (g << 8) | b);
}
}
/** Change the current image so that every pixel that is not on one of
* the four edges of the image is replaced with the average of its
* current value and the current values of its eight neighboring pixels.
*/
public void fuzzify() {
/* INSTRUCTION: FIRST make a copy of the image. You can use
currentIm.copy() to make a copy.
THEN transform the copy using the values in the current image.
THEN store the copy into currentIm.
Thus, the average will be the average of values in the "original"
current image, NOT of values that have already been fuzzified.
*/
}
/** = a String that contains the first n pixels of the current image, 5 to a line,
with annotation (i.e. something at the beginning to say what the string contains). */
public String getPixels(int n) {
// Hint: To have the string at some point begin a new line, put '\n' in it.
// For example, put this in the interactions pane and see what happens: "ABCDE\nEFGH".
// Instruction: Use function ImageArray.toString(int) to get the string
// representation of a pixel.
String s= "";
return s;
}
/** Hide message m in this image, using the ascii representation of m's chars.
Return true if this is possible and false if not.
If m has more than 999999 characters or the picture doesn't have enough
pixels, return false without storing the message.
*/
public boolean hide(String m) {
// Hint: it is best to write a method that hides a char in a pixel
return false;
}
/** Extract and return the message hidden in the current image.
Return null if no message detected. */
public String reveal() {
// Hint: it is best to write a method that gives the char that is
// hidden in a pixel.
return null;
}
/* Assuming the image is broken up into blocks, with nr rows
and nc columns of blocks, set all pixels of the
block at position (row, col) to pixel value pixel.
Precondition: 0 ² row < nr and 0 ² col < nc */
public void setBlock(int nr, int nc, int row, int col, int pixel) {
int height= currentIm.getRows() / nr;
int width= currentIm.getCols() / nc;
for (int r= 0; r < height; r= r+1) {
for (int c=0; c < width; c= c+1) {
currentIm.setPixel(row*height+r, col*width+c, pixel);
}
}
}
/* Assuming the image is broken up into blocks, with nr rows
of blocks and nc columns of blocks, swap all pixels of
the blocks at positions (row0, col0) and (row1, col1). */
public void swapBlocks(int row0, int col0, int row1, int col1, int nr, int nc) {
int rows= currentIm.getRows();
int cols= currentIm.getCols();
int ht= rows/nr;
int wd= cols/nc;
for (int r= 0; r < ht; r= r+1) {
for (int c= 0; c < wd; c= c+1) {
currentIm.swapPixels(row0*ht+r, col0*wd+c, row1*ht+r, col1*wd+c);
}
}
}
/** Restore the original image in the current one */
public void restore() {
currentIm= originalIm.copy();
}
}