<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">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 constants of this class indicate a color for monochrome images.*/
    /** Color gray */
    public static final int GRAY= 0;
    
    /** Color sepia */
    public static final int SEPIA= 1;
    
    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 &lt; 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 &lt;&lt; 24) | (red &lt;&lt; 16) | (green &lt;&lt; 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 &lt; 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() {
        
        
    }
    
    /** 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() {
        // Note: You do not have to write this procedure, and if you do write it, it
        // wll not be graded. BUt do it if you have the time!
        
        /* INSTRUCTION: FIRST make a copy of the image.
         THEN transform the copy using the values in the current image.
         THEN copy the entire transformed copy into the current image.
         Thus, the average will be the average of values in the "original"
         current image, NOT of values that have already been fuzzified.
         */
        
        
        
        
    }
    
    
    /** 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 &lt;= x  &amp;&amp;  x+2 &lt; 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 &lt; cols; c= c+1) {
            int alpha= DM.getAlpha(currentIm.getPixel(x,c));
            currentIm.setPixel(x, c, (alpha &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | b);
            currentIm.setPixel(x+1, c, (alpha &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | b);
            currentIm.setPixel(x+2, c, (alpha &lt;&lt; 24) | (r &lt;&lt; 16) | (g &lt;&lt; 8) | b);
        }
    }
    
    
    /** Convert the current image to monochrome according to parameter c.
      Precondition: c is one of the two constants GRAY or SEPIA of this class.
      
      If c is GRAY, then remove all color from the image by setting the three
      color components of each pixel to that pixels overall brightness, defined as
      0.3 * red + 0.6 * green + 0.1 * blue.  If c is SEPIA, make the same 
      computation but set green to 0.6 * brighness and blue to 0.4 * brightness.
      
      The alpha component is not changed.
      */
    public void monochromify(int c) {
        assert c == ImageProcessor.GRAY || c == ImageProcessor.SEPIA;
        
        
    }
    
    /** Simulate vignetting (corner darkening) characteristic of antique lenses. 
      Darken each pixel in the image by the factor
      
           (d / hfD)^2
      
      where d is the distance from the pixel to the center of the image and hfD (for
      (half diagonal) is the distance from the center of the image to any of the corners.
      
      The alpha component is not changed.
      */
    public void vignette() {
        int rows= currentIm.getRows();
        
        
    }
    
    
    /** = 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.
        
        return "";
    }
    
    
    /** 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) {
        
        
        return false;
    }
    
    /** = the number n that is hidden in pixel p of the current image. */
    public int getHidden(int p) {
        int rgb= currentIm.getPixel(p);
        int red= DM.getRed(rgb);
        int green= DM.getGreen(rgb);
        int blue= DM.getBlue(rgb);
        return  (red % 10) * 100  +  (green % 10) * 10  +  blue % 10;
    }
    
    /** Extract and return the message hidden in the current image.
      Return null if no message detected. */
    public String reveal1() {
       // Note: You do NOT have to write this method.
        
        
        return null;
    }
    
    /** Extract and return the message hidden in the current image.
      Return null if no message detected. */
    public String reveal() {
        
        
        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 &lt; nr  and  0 ² col &lt; 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 &lt; height; r= r+1) {
            for (int c= 0; c &lt; 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 &lt; ht; r= r+1) {
            for (int c= 0; c &lt; 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();
    }
    
    /** Provided file fname does not appear in the current directory, store the
      current image in file fname in the current directory, as a png file.
      Write a message on the console indicating whether or not the write was successful.
      The png format is lossless, so if the image has a hidden message, it will indeed be
      saved in the file. The jpg format is lossy, and saving it can actually change pixels,
      so the message woudl generally be lost.*/
    public void writeImage(String fname) throws java.io.IOException {
        System.out.println("Writing the image.");
        
        File f= new File(fname);
        if (f.exists()) {
            System.out.println("File " + f.getAbsolutePath() + " exists. It was not overwritten.");
            return;
        }
        
        int r= currentIm.getRows();
        int c= currentIm.getCols();
        int roa[]= currentIm.getRmoArray();
        
        // Obtain a buffered image with the right size and format to save out this image
        // (only the RGB components, not alpha).
        BufferedImage bimage= new BufferedImage(c, r, BufferedImage.TYPE_INT_RGB);
        
        // Copy the image data into that BufferedImage.
        bimage.setRGB(0, 0, c, r, roa, 0, c);
        
        // Finally, write the image onto the file and give the appropriate message
        ImageIO.write(bimage, "png", f);
        System.out.println("Image written to " + f.getAbsolutePath());
    }  
    
    
    
}
</pre></body></html>