Images

Dr Andy Evans

[Fullscreen]

Images

  • Images are stored in java.awt.Image objects.
  • Read them from files using a Toolkit
    • See "Key Ideas" page.
  • Make them yourself
    • These slides.

Images

  • Main way of making them from scratch is with a java.awt.image.MemoryImageSource object.
  • A MemoryImageSource object takes in an int[] array and turns it into an image in memory:
	
MemoryImageSource(int width, int height, 
  int[] pixel, int arrayStart, int scanLineWidth)

Making Images from data

  • We can create the pixel array ourselves. Pixels are made up of RGBA data. Again, each is 0 to 255.
  • The array is 1D as this is more efficient to dynamically process.
  • However, why is it just one array, not four?
  • With a bit of clever computing, we can squeeze all four RGBA values into one super-efficient array.

Packed ints

If we take four int values of up to 255:
	
00000000 00000000 00000000 00000001 = int 1
00000000 00000000 00000000 11111111 = int 255
00000000 00000000 00000000 01111111 = int 127
00000000 00000000 00000000 11111111 = int 255

The lefthand three bytes are wasted.
What we really need to do is this:

00000001                            = int 1
00000000 11111111                   = int 255
00000000 00000000 01111111          = int 127
00000000 00000000 00000000 11111111 = int 255
Joined together = compressed weirdness:
00000001 11111111 01111111 11111111 

Making pixels: the hard way

  • So that's what we do.
  • You can do this very efficiently, using a series of 'bitwise' operators Java has for interacting with bits.
  • This is about as much fun as being continually kicked in the groin by a battery of mules.

Making pixels: the easy way

  • The Color class has methods to help change 0 -> 255 r, g, and b values into a packed int:
    
    Color color = new Color(r,g,b);
    int packedInt = color.getRGB();	
    
    
  • You can also make a Color object using a compressed int:
    	
    Color color = new Color(packedInt);
    
    
	
int width = 16;
int height = 16;
int[] pixels = new int[width * height];

for (int h = 0; h < height; h++) {

    for (int w = 0; w < width; w++) {

		int value = 0;
		Color pixel = new Color(value,value,value);

		pixels[(h*width) + w] = pixel.getRGB();

    }

}

	
int width = 16;
int height = 16;
int[] pixels = new int[width * height];

for (int h = 0; h < height; h++) {

    for (int w = 0; w < width; w++) {

		int value = (w * h > 255) ? 255 : w * h;
		Color pixel = new Color(value,value,value);

		pixels[(h*width) + w] = pixel.getRGB();

    }

}

	
int width = 16;
int height = 16;
int[] pixels = new int[width * height];

for (int h = 0; h < height; h++) {

    for (int w = 0; w < width; w++) {

		int value = data[h][w];
		Color pixel = new Color(value,value,value);

		pixels[(h*width) + w] = pixel.getRGB();

    }

}

Must re-range our data between 0 and 255 if below or above this.

Using MemoryImageSource

  • With the array of pixels we can build the java.awt.image.MemoryImageSource.
  • Encapsulates an image in the computer's memory.
  • Computers can have multiple output devices on which an image is displayed, so this doesn't represent a displayed image. To do this, we need to use a Component to convert it. They know about the display.
    	
    MemoryImageSource memImage = 
          new MemoryImageSource(16,16,pixels,0,16);
    Panel panel = new Panel();
    Image image = panel.createImage(memImage);
    
    
  • We'll see how to draw the image in a bit.

Sequence

  • Get an image array.
  • Create a MemoryImageSource object.
  • Create an Image object.

Making Images:
PixelGrabbers

  • If we have an Image and we want the pixels, we can use a java.awt.image.PixelGrabber.
  • The PixelGrabber object does the exact opposite of MemoryImageSource.
	
PixelGrabber(Image img, int left, int top, 
  int width, int height, int [] pixels, 
  int startArray, int scanLineWidth)

	
int pixels[] = new int [100];
PixelGrabber pg = 
  new PixelGrabber(image,0,0, 16,16, pixels,0,16);
pg.grabPixels();  

Putting it all together

We now have all the methods we need to build a small image processor:
  • First we get an image.
  • Then we use a pixelGrabber to pull the pixels into an array.
  • We then expand the pixels into their alpha, red, green and blue values.
  • We manipulate the values - for example filtering the data.

Putting it all together

  • We then recode the values into the int array.
  • We use a MemoryImageSource to put the pixels back in an Image.
  • We draw the image on the screen.
  • We then run to the pub and drink ourselves unconscious to celebrate being geek gods/goddesses unfettered by the mere trifling difficulties of everyday human beings.