package org.nzdl.gsdl.GsdlCollageApplet; import java.awt.*; import java.awt.geom.*; import java.io.*; import java.net.*; import java.awt.image.*; /** * @author Katrina Edgar * @author David Bainbridge * * Data Structure to store an image once it is displayed in the applet. * This structure remembers the images graphical representation, source url, * name, width, height, position on the screen and whether or not it has * previously been displayed. It provides methods to set the dimensions and * position of the image. It also provides access methods to the translated * x and y co-ordinates of the image */ public class CollageImage { /** Decrements the alpha value between adjacent rows on the edge of an image
* Used to fade the edges faster than the rest of the image
* Only used when java2 parameter is true and advanced image processing * techniques may be applied */ static final int FADEVALUE = 3; /** Defines the shades of white used to colour the backgrounds of white images
* These colours are used because when several white images appear in the collage * simultaneously it is difficult to distinguish their edges
* Only used when java2 parameter is true and advanced image processing * techniques may be applied */ int colorMask [] = {0xF8FFFF, 0xFFF8FF, 0xFFFFF8, 0xF8F8FF, 0xFFF8F8, 0xF8FFF8, 0xFAFAFA}; /** Defines the number of shades of white used to colour the backgrounds of white images
* These colours are used because when several white images appear in the collage * simultaneously it is difficult to distinguish their edges
* Only used when java2 parameter is true and advanced image processing * techniques may be applied */ static final int NO_OF_COLORS = 7; /** Will fire a removal operation when 4 images in the collage overlap a single area */ static final int NO_IMAGES_OF_OVERLAP = 4; /** Source url of the image */ String from_url_ = null; /** Name of the image */ String name_ = null; /** Width of the image */ int image_x_dim_ = 0; /** Height of the image */ int image_y_dim_ = 0; /** Indicates whether or not the image has been drawn on the applet previously */ boolean fresh = true; URL url_ = null; /** Reflects the translation of the image from the origin to its position on the screen */ AffineTransform af_ = null; /** Left x co-ordinate */ protected int xl_ = 0; /** Top y co-ordinate */ protected int yt_ = 0; /** Right x co-ordinate */ protected int xr_ = 0; /** Bottom y co-ordinate */ protected int yb_ = 0; /** Refers to applet */ GsdlCollageApplet app_ = null; boolean isJava2_; Image image_; /** Constructs an CollageImage from the three specified parameters * * @param image The graphical representation of the image * @param from_url The source url for the image * @param name The file name of the image */ public CollageImage(GsdlCollageApplet app, boolean isJava2, DownloadImages.ImageUrlTriple iutriple) { image_ = iutriple.image(); from_url_ = iutriple.urlString(); name_ = iutriple.name(); url_ = iutriple.url(); isJava2_=isJava2; app_=app; process(); } /** Sets the translation for the image from the origin * And regenerate the image as the scaled version * * @param af The AffineTransform translation that has been calculated */ public void setAffineTransform(MyAffineTransform af, boolean is_java2_) { image_x_dim_ = (int) (image_x_dim_ * af.scaleX); image_y_dim_ = (int) (image_y_dim_ * af.scaleY); image_ = image_.getScaledInstance(image_x_dim_, image_y_dim_, Image.SCALE_DEFAULT); if (is_java2_) { af_ = new AffineTransform(); af_.translate(af.translateX, af.translateY); af_.scale(1.0, 1.0); calculate_rect(); } else { double trans_x = af.translateX; double trans_y = af.translateY; xl_ = Math.round((float)trans_x); xr_ = Math.round((float)(trans_x + image_x_dim_)) -1; yt_ = Math.round((float)trans_y); yb_ = Math.round((float)(trans_y + image_y_dim_)) -1; } } public void expand () { // still expands a little too fast... how to fix this? magnify(new Rectangle((int) (xl_ + (image_x_dim_ * 0.000001)), (int) (yt_ + (image_y_dim_ * 0.000001)), (int) (image_x_dim_ * 0.999998), (int) (image_y_dim_ * 0.999998))); } public void magnify(Rectangle border) { double magX = image_x_dim_/(double)border.width; double magY = image_y_dim_/(double)border.height; int x = border.x + border.width/2; int y = border.y + border.height/2; paintImage(x,y,magX, magY); } public void paintImage(int magCenterX, int magCenterY, double magX, double magY){ try { //Point2D mgp = null; //mgp = af_.inverseTransform((new Point(magCenterX, magCenterY)),(Point)mgp); //double x = (mgp.getX()*magX)-mgp.getX(); //double y = (mgp.getY()*magY)-mgp.getY(); //scale(-x,-y, magX, magY); }catch (Exception e) {System.out.println(e); } } public void scale(double magOffsetX, double magOffsetY, double magX, double magY){ af_.translate(magOffsetX,magOffsetY); af_.scale(magX, magY); } /** Calculates the new image co-ordinates after translation has occurred */ protected void calculate_rect() { double trans_x = af_.getTranslateX(); double trans_y = af_.getTranslateY(); xl_ = Math.round((float)trans_x); xr_ = Math.round((float)(trans_x + image_x_dim_)) -1; yt_ = Math.round((float)trans_y); yb_ = Math.round((float)(trans_y + image_y_dim_)) -1; } /** Determines whether a given co-ordinate is inside this image * * @param x The x co-ordinate * @param y The y co-ordinate */ public boolean inside(int x, int y) { return ((x>=xl_) && (x<=xr_)) && ((y>=yt_) && (y<=yb_)); } /** Gets the width of the translated image */ public double getX() { return af_.getTranslateX(); } /** Gets the height of the translated image */ public double getY() { return af_.getTranslateY(); } /** Fades and colours the image on a pixel-by-pixel basis
* First it grabs the pixels of the entire image and stores them in a 2D array. * Then a bound is calculated to indicate the point from which edge * fading should occur. The position of the bound will change in proportion * to the age of the image so that older images have a larger faded edge. * The area within the bounds, that forms the center of the image, is processed * first and faded by a standard alpha value. Then each edge of the image * is processed separately, creating a gradient fade from the true edge to the * position of the bound.
* The faded pixel array is then turned into a new image a returned. * * @param img the image that requires processing * @param x the x co-ordinate of the image * @param y the y co-ordinate of the image * @param w the width of the image * @param h the height of the image * @param p the position of the image in the applet (indicates age) * @param fresh whether the image is being processed for the first time */ public int[] handlepixels(int p) { int h = image_y_dim_; int w = image_x_dim_; // declare an array to hold the pixels int[] pixels = new int[w * h]; // get the pixels of the image into the pixels array PixelGrabber pg = new PixelGrabber(image_, 0, 0, w, h, pixels, 0, w); try { pg.grabPixels(); } catch (InterruptedException e) { System.err.println("interrupted waiting for pixels!"); } // check for any failures if ((pg.getStatus() & ImageObserver.ABORT) != 0) { System.err.println("image fetch aborted or errored"); } // calculates the bound from which fading should begin double bound = p * 0.01; if (w > h) bound *= w; else bound *= h; int upperboundheight = h - (int) bound; int upperboundwidth = w - (int) bound; int lowerbound = (int) bound; // loop through every pixel in the picture and handle it for (int j = lowerbound; j < upperboundheight; j++) { for (int i = lowerbound; i < upperboundwidth; i++) { // width and height: x+i y+j pixels[j * w + i] = handlesinglepixel(pixels[j * w + i], p, fresh, false, 255); } } int fade = 0; int fader = 0; int corealpha = (pixels[(h/2) * w + (w/2)] >> 24) & 0xff; // top edge for (int n = lowerbound; n >= 0; n--) { fader = corealpha - fade; if (fader < 0) fader = 0; for (int m = 0; m < w; m++){ int index = n* w + m; if (index = 0; n--) { fader = corealpha - fade; if (fader < 0) fader = 0; for (int m = 0; m < h; m++) { if ( m < lowerbound && n > m); else if ( m > upperboundheight && n > (h - m)); else { int index = m * w + n; if (index m); else if ( m > upperboundheight && (w - n) > (h - m)); else { int index = m * w + n; if (index * If the image is being drawn for the first time, the RGB values are * extracted. If the pixel is close to white (RGB > 250) then an offwhite * colour is applied to this pixel. * This is done because when several white images appear in the collage * simultaneously it is difficult to distinguish their edges.
* This function also fades the alpha value of the pixel as the image ages. * The alpha value is more heavily decremented as pixels get closer to the * edge of the image * * @param pixel the pixel to manipulate * @param p the position of the image in collage (representative of age) * @param fresh indicates whether or not the image is being drawn for the first time * @param edge indicates whether or not this pixel is near the edge of the image * @param fade the amount by which to fade this pixel * @return the adjusted pixel as an int */ public int handlesinglepixel(int pixel, int p, boolean fresh, boolean edge, int fade) { int newpixel = 0; //changes the colour of the picture, only when first drawn //and only if the pixel is close to white if (fresh) { int red = (pixel >> 16) & 0xff; int green = (pixel >> 8) & 0xff; int blue = (pixel ) & 0xff; if (red >= 250 && green >= 250 && blue >= 250) { int c = colorMask[((int) (p%NO_OF_COLORS))]; red = (c >> 16) & 0xff; green = (c >> 8) & 0xff; blue = (c) & 0xff; } newpixel |= (red << 16) & 0x00ff0000; newpixel |= (green << 8) & 0x0000ff00; newpixel |= blue & 0x000000ff; } else { newpixel |= pixel & 0x00ffffff; } int alpha = (pixel >> 24) & 0xff; if (edge) { // fade the edges more... alpha = fade; } else if (alpha > 10 && !fresh) { alpha -= 10; } newpixel |= (alpha << 24) & 0xff000000; return (newpixel); } /** Resets the alpha channel of an image so that it appears solid * * @param img the image to restore * @param x the x co-ordinate of the image * @param y the y co-ordinate of the image * @param w the width of the image * @param h the height of the image */ public void restoreAlpha() { int h = image_y_dim_; int w = image_x_dim_; // declare an array to hold the pixels int[] pixels = new int[w * h]; // get the pixels of the image into the pixels array PixelGrabber pg = new PixelGrabber(image_, 0, 0, w, h, pixels, 0, w); try { pg.grabPixels(); } catch (InterruptedException e) { System.err.println("interrupted waiting for pixels!"); } // check for any failures if ((pg.getStatus() & ImageObserver.ABORT) != 0) { System.err.println("image fetch aborted or errored"); } // loop through every pixel in the picture and handle it for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { pixels[j * w + i] |= (255 << 24) & 0xff000000; } } // set the pixels of the whole picture to the pixels array pg.setPixels(0, 0, w, h, pg.getColorModel(), pixels, 0, w); image_ = app_.createImage(new MemoryImageSource(w, h, pixels, 0, w)); } /** Checks whether an image has faded to the point where it must be removed * from the collage. * * @param img the image to restore * @param x the x co-ordinate of the image * @param y the y co-ordinate of the image * @param w the width of the image * @param h the height of the image */ public boolean checkFaded (int[] pixels) { int h = image_y_dim_; int w = image_x_dim_; // get the alpha value of the middle pixel of the image int corealpha = (pixels[(h/2) * w + (w/2)] >> 24) & 0xff; if (corealpha < 50) return true; return false; } public boolean isValid(){ image_x_dim_ = image_.getWidth(app_); image_y_dim_ = image_.getHeight(app_); return (image_x_dim_) >0 && ( image_x_dim_ >0); } public void process(){ // images x and y dimensions image_x_dim_ = image_.getWidth(app_); image_y_dim_ = image_.getHeight(app_); if (( image_x_dim_ >0) && ( image_x_dim_ >0)) { // places and sizes the image MyAffineTransform af = new MyAffineTransform(image_x_dim_,image_y_dim_); // sets location & size of collage image setAffineTransform(af, isJava2_); fresh = false; if (isJava2_ ) { restoreAlpha(); } } } }