Lecture : Graphics Programming 1
In the previous lecture:
In this lecture:
What is a digital image?
There are basically two types of images, Bitmap and Vector images.
Bitmap Images
|
Enlarged, pixellated bitmap . If you look too closely at a bitmap image you can see the individual pixels. |
Note: Sometimes black and white images laid out in a grid of pixels are referred to as "bitmaps" since they require one bit per pixel to specify. |
It is simple but space hungry to write every pixel value into a file as a (Red, Green, Blue) triple. Typically this takes 8 bits per channel (24 bits per pixel). If transparency (an alpha channel) is added to an RGB image we need 32 bits per pixel for Red, Green, Blue and Alpha (an RGBA image). An alternative is to construct a colour palette for a particular image from the most frequently encountered pixel values in that image. The GIF image file format does this. Each colour in the 256 colour palette takes 24 bits to specify but each pixel in the image can now be stored as a single 8 bit index into the colour palette. |
||
An image and its GIF 256 colour palette. For this palette, 255=Black, 044=Red, 000=White. |
Homework: | Calculate the space savings for a few different image sizes using this encoding scheme. |
Bitmap image compression
Image compression schemes may be lossy or lossless.
Lossy schemes
Lossless schemes
Skull image - captured using a camera. |
||
GIF 38kBytes (lossless*) | 50% JPEG 4kBytes (lossy) | 25% JPEG 2.5kBytes (lossy) |
Spider image - synthesized digitally. |
||
GIF 15kBytes (lossless*) | 50% JPEG 3kBytes (lossy) | 25% JPEG 2kBytes (lossy) |
Text image - synthesized digitally. |
||
GIF (lossless) |
JPEG (lossy) This image is under very high compression to accentuate the edge artefacts. |
* Footnote: GIF is lossless only if the source of the image has 256 colours or less!
Working with bitmap images in Java
Java graphics libraries include:
java.awt - the abstract window toolkit. An early, basic toolkit for using a platform's native GUI elements.
javax.imageio - classes for reading and writing bitmap images in JPEG, PNG and GIF.
Java AWT draws to the screen in a Frame and within it a Canvas or lately, with Swing, within a JFrame and a JPanel. In the program below we create a JFrame (that includes the window title bar) and within this we create a JPanel on which to draw (that doesn't include the window title bar). A Java graphics context is the environment in which Java's graphics routines operate when drawing to the screen. A Graphics object is responsible for controlling this drawing to the screen within a graphics context. To use it, the Graphics object needs to be passed as a parameter to a paint() (or paintComponent()) method. The paint() or paintComponent() method is not usually called directly by the programmer. It will be called automatically when the window is created, resized or uncovered. If a programmer wants to force a call to paint() they may do so by calling repaint() which requests an update of the window... and calls paint(). |
This simple program opens a window suitable for performing graphics and loads an image file into it for display. You could easily use such code to load a series of icons onto a map.
import java.awt.*; public class ImageDisplayer extends JFrame { public static void main(String[] args) { new ImageDisplayer(); } ImageDisplayer() { super("Image Displayer"); // Set up the window to receive a quit event that closes it addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) {System.exit(0);} } ); // Set the size of the new JFrame setSize (300,300); // Place a new CanvasImageDisplayer (defined below) in the frame add("Center", new PanelImageDisplayer()); // Make the new window visible setVisible(true); } } // Make a subclass of the JPanel class PanelImageDisplayer extends JPanel { // The paintComponent method of the canvas class is automatically // called when the window is created or resized public void paintComponent(Graphics g) { // Get the dimensions of the JPanel so that if // the window is resized we can re-position the image Dimension d = getSize(); int maxX = d.width - 1; int maxY = d.height - 1; String fileName1 = "tent.GIF"; // Java will read GIFs String fileName2 = "tree.PNG"; // Java will read PNGs (and JPEGs) too try { // Try to load an image from the file and display it // Note: the origin of the JPanel is the top left corner Image image1 = ImageIO.read(new File (fileName1)); g.drawImage(image1, (int)(maxX*0.3), (int)(maxY*0.3), null); Image image2 = ImageIO.read(new File (fileName2)); g.drawImage(image2, (int)(maxX*0.7), (int)(maxY*0.7), null); } catch (IOException e) { System.out.println("ERROR: " + e.getMessage()); } } } |
The output displayed by the program above. |
The addWindowListener() method in the code above takes an argument that is an object of a class implementing the WindowListener interface. One of the methods of this interface is a windowClosing() method.
Object-based / Vector images
|
Bitmap of vector image (control points marked) |
Working with vector images in Java
Java allows the programmer to draw vector images using standard graphics routines. Here we'll only investigate drawing 2D graphics.
import java.awt.*; public class VectorDisplayer extends JFrame { public static void main(String[] args) { new VectorDisplayer(); } VectorDisplayer() { super("Vector Displayer"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); setSize (300, 300); add("Center", new PanelVectorDisplayer()); // You can change the cursor over the JFrame as you like... setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); setVisible(true); } } class PanelVectorDisplayer extends JPanel { public void paintComponent(Graphics g) { Dimension d = getSize(); int maxX = d.width-1; int maxY = d.height-1; g.drawString("d.width = " + d.width, 10, 30); // write a string to the display g.drawString("d.height = " + d.height, 10, 60); g.setColor(Color.red); // set the colour using predefined color objects g.drawLine(150, 120, 180, 140); // draw lines (start_x, start_y, finish_x, finish_y) g.drawLine(180, 140, 120, 140); g.drawLine(120, 140, 150, 120); g.setColor(new Color(120, 95, 200)); // set the colour using a programmer-defined color object g.fillRect(130, 140, 40, 30); // draw a filled rectangle (start_x, start_y, width, height) g.setColor(Color.green); g.drawLine(100, 170, 200, 170); } } |
The output displayed by the program above. |
Homework: | In addition to setColor(), you can call a Graphics object's getColor() method to get the current colour. Try it! The call returns a Color object. There are also routines getBlue(), getGreen() and getRed(). |
Generating bitmap files from vector graphics
After you've drawn a vector image, you can save it to a bitmap image file.
The process involves rasterisation of the vectors into pixels. This process also happens when the vector image is displayed on a raster display device (like an LCD or CRT monitor).
import java.awt.*; public class ImageSaver { public static void main(String[] args) throws IOException { int size = 300; |
The output saved to ImageSaved.png by the program above. |
This program demonstrates the basics of rendering into an image that is stored in memory (and not displayed on-screen). It also utilises Java's ability to write graphics files to disk. Explore the other methods of the graphics libraries in your own time. We'll look at drawing vector graphics in more detail in a later lecture.