Multimedia: Images, Animation, Audio and Video

Java uses a API called the Java Media Framework (JMF 2.1.1e), this provides emhanced processing of images, audio and video playback.

Loading, Displaying and Scaling Images

Both java.awt and java.swing packages display images

Example
import java.applet.Applet;
import java.awt.*;
import javax.swing.*;


public class LoadImageAndScale extends JApplet {
   private Image logo1;  
   private ImageIcon logo2;   

   // load the image when the applet is loaded
   public void init()
   {
      logo1 = getImage( getDocumentBase(), "logo2.gif" );
      logo2 = new ImageIcon( "logo2.gif" );
   }

   // display the image
   public void paint( Graphics g )
   {
      // draw the original image
      g.drawImage( logo1, 0, 0, this );

      // draw the image scaled to fit the width of the applet
      // and the height of the applet minus 120 pixels
      g.drawImage( logo1, 0, 120,
                   getWidth(), getHeight() - 120, this );

      // draw the icon using its paintIcon method
      logo2.paintIcon( this, g, 180, 0 );
   }
}

## HTML Code
<html>
<applet code="LoadImageAndScale.class" width=340 height=340>
</applet>
</html> Note: the image can be found here

Loading and Playing Audio Clips

Java can manipulate and play audio clips, it provides two mechanisms for playing sounds in an applet

Example
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class LoadAudioAndPlay extends JApplet {
   private AudioClip sound1, sound2, currentSound;  
   private JButton playSound, loopSound, stopSound;
   private JComboBox chooseSound;

   // load the image when the applet begins executing
   public void init()
   {
      Container c = getContentPane();
      c.setLayout( new FlowLayout() );

      String choices[] = { "Welcome", "Hi" };
      chooseSound = new JComboBox( choices );
      chooseSound.addItemListener(
         new ItemListener() {
            public void itemStateChanged( ItemEvent e )
            {
               currentSound.stop();

               currentSound =
                  chooseSound.getSelectedIndex() == 0 ?
                     sound1 : sound2;
            }
         }
      );
      c.add( chooseSound );

      ButtonHandler handler = new ButtonHandler();
      playSound = new JButton( "Play" );
      playSound.addActionListener( handler );
      c.add( playSound );
      loopSound = new JButton( "Loop" );
      loopSound.addActionListener( handler );
      c.add( loopSound );
      stopSound = new JButton( "Stop" );
      stopSound.addActionListener( handler );
      c.add( stopSound );

      sound1 = getAudioClip(
                 getDocumentBase(), "welcome.wav" );
      sound2 = getAudioClip(
                 getDocumentBase(), "hi.au" );
      currentSound = sound1;
   }

   // stop the sound when the user switches Web pages
   // (i.e., be polite to the user)
   public void stop()
   {
      currentSound.stop();
   }

   private class ButtonHandler implements ActionListener {
      public void actionPerformed( ActionEvent e )
      {
         if ( e.getSource() == playSound ) 
            currentSound.play();
         else if ( e.getSource() == loopSound ) 
            currentSound.loop();
         else if ( e.getSource() == stopSound ) 
            currentSound.stop();
      }
   }
}

## HTML Code
<html>
<applet code="LoadAudioAndPlay.class" width=350 height=50>
</applet>
</html> Note: the sound files can be found here and here

The Java Media Player

The basic media player offered by Java can play multiple audio and video formats (avi, mpg, mpeg, mov). In order to use the media player you need the JFM package which can be downloaded from Sun.

Media Player Example
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.media.*;


public class MediaPlayerDemo extends JFrame {
   private Player player;
   private File file;

   public MediaPlayerDemo()
   {
      super( "Demonstrating the Java Media Player" );

      JButton openFile = new JButton( "Open file to play" );
      openFile.addActionListener(
         new ActionListener() {
            public void actionPerformed( ActionEvent e )
            {
               openFile();
               createPlayer();
            }
         }
      );
      getContentPane().add( openFile, BorderLayout.NORTH );
  
      setSize( 300, 300 );
      show();
   }

   private void openFile()
   {      
      JFileChooser fileChooser = new JFileChooser();

      fileChooser.setFileSelectionMode( JFileChooser.FILES_ONLY );
      int result = fileChooser.showOpenDialog( this );

      // user clicked Cancel button on dialog
      if ( result == JFileChooser.CANCEL_OPTION )
         file = null;
      else
         file = fileChooser.getSelectedFile();
   }

   private void createPlayer()
   {
      if ( file == null )
         return;

      removePreviousPlayer();

      try {
         // create a new player and add listener
         player = Manager.createPlayer( file.toURL() );
         player.addControllerListener( new EventHandler() );
         player.start();  // start player
      }
      catch ( Exception e ){
         JOptionPane.showMessageDialog( 
            this,
            "Invalid file or location", 
            "Error loading file",
            JOptionPane.ERROR_MESSAGE 
      );
      }
   }

   private void removePreviousPlayer()
   {
      if ( player == null )
         return;

      player.close();

      Component visual = player.getVisualComponent();
      Component control = player.getControlPanelComponent();

      Container c = getContentPane();
     
      if ( visual != null ) 
         c.remove( visual );

      if ( control != null ) 
         c.remove( control );
   }

   public static void main(String args[])
   {
      MediaPlayerDemo app = new MediaPlayerDemo();

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit(0);
            }
         }
      );
   }

   // inner class to handler events from media player
   private class EventHandler implements ControllerListener {
      public void controllerUpdate( ControllerEvent e ) {
         if ( e instanceof RealizeCompleteEvent ) {
            Container c = getContentPane();
         
            // load Visual and Control components if they exist
            Component visualComponent = player.getVisualComponent();

            if ( visualComponent != null )
               c.add( visualComponent, BorderLayout.CENTER );

            Component controlsComponent = player.getControlPanelComponent();

            if ( controlsComponent != null )
               c.add( controlsComponent, BorderLayout.SOUTH );

            c.doLayout();
         }
      }
   }
}

Animating a Series of Images

When you play some video games, you are not aware that the program is just using a number of images and animating them to give the appearance of a moving picture, movies and cartoons all use this method, just a numbers of pictures linked together and viewed at high speed.

The problems that you face when trying to create moving images is that the end result does not play smoothly, they appear choppy, or the characters do not appear to move properly.

The below example is a very basic animation program, there are complete gaming/graphics books on how to program animation in Java, explaining the problems of animating images and offering solutions.

Basic Animation
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class LogoAnimator extends JPanel implements ActionListener {
   protected ImageIcon images[];
   protected int totalImages = 30,
                 currentImage = 0,
                 animationDelay = 50; // 50 millisecond delay
   protected Timer animationTimer;

   public LogoAnimator()
   {
      setSize( getPreferredSize() );

      images = new ImageIcon[ totalImages ];

      for ( int i = 0; i < images.length; ++i ) 
         images[ i ] = new ImageIcon( "images/deitel" + i + ".gif" );

      startAnimation();
   }

   public void paintComponent( Graphics g )
   {
      super.paintComponent( g );

      if ( images[ currentImage ].getImageLoadStatus() == MediaTracker.COMPLETE ) {
         images[ currentImage ].paintIcon( this, g, 0, 0 );
         currentImage = ( currentImage + 1 ) % totalImages;
      }
   }

   public void actionPerformed( ActionEvent e )
   {
      repaint();
   }

   public void startAnimation()
   {
      if ( animationTimer == null ) {
         currentImage = 0;  
         animationTimer = new Timer( animationDelay, this );
         animationTimer.start();
      }
      else  // continue from last image displayed
         if ( ! animationTimer.isRunning() )
            animationTimer.restart();
   }

   public void stopAnimation()
   {
      animationTimer.stop();
   }

   public Dimension getMinimumSize()
   { 
      return getPreferredSize(); 
   }

   public Dimension getPreferredSize()
   {
      return new Dimension( 160, 80 );
   }

   public static void main( String args[] )
   {
      LogoAnimator anim = new LogoAnimator();

      JFrame app = new JFrame( "Animator test" );
      app.getContentPane().add( anim, BorderLayout.CENTER );

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

      // The constants 10 and 30 are used below to size the
      // window 10 pixels wider than the animation and
      // 30 pixels taller than the animation. 
      app.setSize( anim.getPreferredSize().width + 10,
                   anim.getPreferredSize().height + 30 );
   }
}

Note: the images can be located here

Customizing Applets via the HTML param Tag

One common feature of applets is the ability to customize the applet via parameters that are supplied from the HTML file that invokes the applet. Parameters are passed from the HTML file to the Java program which can then be used.

Customizing Applets example
// LogoAnimator Class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;


public class LogoAnimator extends JPanel
                          implements ActionListener {
   protected ImageIcon images[];
   protected int totalImages = 30,
                 currentImage = 0,
                 animationDelay = 50; // 50 millisecond delay
   protected String imageName = "deitel";
   protected Timer animationTimer;

   public LogoAnimator()
   {
      initializeAnim();
   }

   // new constructor to support customization 
   public LogoAnimator( int num, int delay, String name )
   {
      totalImages = num;
      animationDelay = delay;
      imageName = name;

      initializeAnim();
   }

   private void initializeAnim()
   {
      images = new ImageIcon[ totalImages ];

      for ( int i = 0; i < images.length; ++i ) 
         images[ i ] = new ImageIcon( "images/" +
                              imageName + i + ".gif" );

      // moved here so getPreferredSize can check the size of
      // the first loaded image.
      setSize( getPreferredSize() ); 

      startAnimation();
   }

   public void paintComponent( Graphics g )
   {
      super.paintComponent( g );

      if ( images[ currentImage ].getImageLoadStatus() ==
           MediaTracker.COMPLETE ) {
         images[ currentImage ].paintIcon( this, g, 0, 0 );
         currentImage = ( currentImage + 1 ) % totalImages;
      }
   }

   public void actionPerformed( ActionEvent e )
   {
      repaint();
   }

   public void startAnimation()
   {
      if ( animationTimer == null ) {
         currentImage = 0;  
         animationTimer = new Timer( animationDelay, this );
         animationTimer.start();
      }
      else  // continue from last image displayed
         if ( ! animationTimer.isRunning() )
            animationTimer.restart();
   }

   public void stopAnimation()
   {
      animationTimer.stop();
   }

   public Dimension getMinimumSize()
   { 
      return getPreferredSize(); 
   }

   public Dimension getPreferredSize()
   {
      return new Dimension( images[ 0 ].getIconWidth(),
                            images[ 0 ].getIconHeight() );
   }

   public static void main( String args[] )
   {
      LogoAnimator anim = new LogoAnimator();

      JFrame app = new JFrame( "Animator test" );
      app.getContentPane().add( anim, BorderLayout.CENTER );

      app.addWindowListener(
         new WindowAdapter() {
            public void windowClosing( WindowEvent e )
            {
               System.exit( 0 );
            }
         }
      );

      app.setSize( anim.getPreferredSize().width + 10,
                   anim.getPreferredSize().height + 30 );
      app.show();
   }
}

// LogoApplet Class
import java.awt.*;
import javax.swing.*;

public class LogoApplet extends JApplet{   
   public void init()
   {
      String parameter;

      parameter = getParameter( "animationdelay" );
      int animationDelay = ( parameter == null ? 50 :
                             Integer.parseInt( parameter ) );

      String imageName = getParameter( "imagename" );

      parameter = getParameter( "totalimages" );
      int totalImages = ( parameter == null ? 0 :
                          Integer.parseInt( parameter ) );

      // Create an instance of LogoAnimator
      LogoAnimator animator;

      if ( imageName == null || totalImages == 0 )
         animator = new LogoAnimator();
      else
         animator = new LogoAnimator( totalImages,
                       animationDelay, imageName );

      setSize( animator.getPreferredSize().width, animator.getPreferredSize().height );
      getContentPane().add( animator, BorderLayout.CENTER );

      animator.startAnimation();
   }
}

// HTML Code
<html>
<applet code="LogoApplet.class" width=400 height=400>
<param name="totalimages" value="30">
<param name="imagename" value="deitel">
<param name="animationdelay" value="200">
</applet>
</html>

Image Maps

An image map is an image that has hot areas that the user can click to accomplish a task such as loading a different web page into a browser. Normally when the mouse goes over the hot area a descriptive text is displayed.

Image Map example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class ImageMap extends JApplet {
   private ImageIcon mapImage;
   private int width, height;

   public void init()
   {
      addMouseListener(
         new MouseAdapter() {
            public void mouseExited( MouseEvent e )
            {
               showStatus( "Pointer outside applet" );
            }
         }
      );

      addMouseMotionListener(
         new MouseMotionAdapter() {
            public void mouseMoved( MouseEvent e )
            {
               showStatus( translateLocation( e.getX() ) );
            }
         }
      );

      mapImage = new ImageIcon( "icons2.gif" ); 
      width = mapImage.getIconWidth();
      height = mapImage.getIconHeight();
      setSize( width, height );
   }

   public void paint( Graphics g )
   {
      mapImage.paintIcon( this, g, 0, 0 );
   }

   public String translateLocation( int x )
   {
      // determine width of each icon (there are 6)
      int iconWidth = width / 6;

      if ( x >= 0 && x <= iconWidth ) 
         return "Common Programming Error";
      else if ( x > iconWidth && x <= iconWidth * 2 )
         return "Good Programming Practice";
      else if ( x > iconWidth * 2 && x <= iconWidth * 3 )
         return "Performance Tip";
      else if ( x > iconWidth * 3 && x <= iconWidth * 4 )
         return "Portability Tip";
      else if ( x > iconWidth * 4 && x <= iconWidth * 5 )
         return "Software Engineering Observation";
      else if ( x > iconWidth * 5 && x <= iconWidth * 6 )
         return "Testing and Debugging Tip";

      return ""; 
   }
} 

## HTML Code
<html>
<applet code="ImageMap.class" width=330 height=100>
</applet>
</html> Note: you can get the icon here