Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java How to Program, Fourth Edition - Deitel H., Deitel P.pdf
Скачиваний:
58
Добавлен:
24.05.2014
Размер:
14.17 Mб
Скачать

1070

Multimedia: Images, Animation, Audio and Video

Chapter 18

We need programming languages that make creating multimedia applications easy. Most programming languages do not have built-in multimedia capabilities. However, Java provides extensive multimedia facilities that enable you to start developing powerful multimedia applications immediately.

This chapter presents a series of “live-code” examples that cover several interesting multimedia features you will need to build useful applications, including:

1.the basics of manipulating images

2.creating smooth animations

3.customizing an animation applet via parameters supplied from the HTML file that invokes an applet

4.playing audio files with the AudioClip interface

5.creating image maps that can sense when the cursor is over them even without a mouse click

We will continue our coverage of Java’s multimedia capabilities in Chapter 22, where we discuss the Java Media Framework (JMF) and the Java Sound APIs. JMF and Java Sound enable Java programs to play and record audio and video. The JMF even enables Java programs to send audio and video streams—so-called streaming media—across a network or the Internet. The chapter exercises for this chapter and Chapter 22 suggest dozens of challenging and interesting projects and even mention some “million-dollar” ideas that could help you make your fortune! When we were creating these exercises, it seemed that the ideas just kept flowing. Multimedia seems to leverage creativity in ways that we have not experienced with “conventional” computer capabilities.

18.2 Loading, Displaying and Scaling Images

Java’s multimedia capabilities include graphics, images, animations, sounds and video. We begin our multimedia discussion with images.

The applet of Fig. 18.1 demonstrates loading an Image (package java.awt) and loading an ImageIcon (package javax.swing). The applet displays the Image in its original size and scaled to a larger size, using two versions of Graphics method drawImage. The applet also draws the ImageIcon using its method paintIcon. Class ImageIcon is easier than Image to use, because its constructor can receive arguments of several different formats, including a byte array containing the bytes of an image, an Image already loaded in memory, a String representing the location of an image and a URL representing the location of an image.

1// Fig. 18.1: LoadImageAndScale.java

2// Load an image and display it in its original size

3 // and scale it to twice its original width and height. 4 // Load and display the same image as an ImageIcon.

5

6// Java core packages

7 import java.applet.Applet;

8import java.awt.*;

Fig. 18.1 Loading and displaying an image in an applet (part 1 of 2).

Chapter 18

Multimedia: Images, Animation, Audio and Video

1071

9

10// Java extension packages

11import javax.swing.*;

12

13public class LoadImageAndScale extends JApplet {

14private Image logo1;

15private ImageIcon logo2;

16

17// load image when applet is loaded

18public void init()

19{

20logo1 = getImage( getDocumentBase(), "logo.gif" );

21logo2 = new ImageIcon( "logo.gif" );

22}

23

24// display image

25public void paint( Graphics g )

26{

27// draw original image

28g.drawImage( logo1, 0, 0, this );

30// draw image scaled to fit width of applet

31// and height of applet minus 120 pixels

32g.drawImage( logo1, 0, 120,

33

getWidth(), getHeight() - 120, this );

34

 

35// draw icon using its paintIcon method

36logo2.paintIcon( this, g, 180, 0 );

37}

38

39 } // end class LoadImageAndScale

Fig. 18.1 Loading and displaying an image in an applet (part 2 of 2).

1072

Multimedia: Images, Animation, Audio and Video

Chapter 18

Lines 14 and 15 declare an Image reference and an ImageIcon reference, respectively. Class Image is an abstract class; therefore, the applet cannot create an object of class Image directly. Rather, the applet must call a method that causes the applet container to load and return the Image for use in the program. Class Applet (the superclass of JApplet) provides a method that does just that. Line 20 in method init uses Applet method getImage to load an Image into the applet. This version of getImage takes two argu- ments—the location of the image file and the file name of the image. In the first argument, Applet method getDocumentBase returns a URL representing the location of the image on the Internet (or on your computer if the applet was loaded from your computer). The program assumes that the image is stored in the same directory as the HTML file that invoked the applet. Method getDocumentBase returns the location of the HTML file on the Internet as an object of class URL. The second argument specifies an image file name. Java supports several image formats, including Graphics Interchange Format (GIF), Joint Photographic Experts Group (JPEG) and Portable Network Graphics (PNG). File names for each of these types end with .gif, .jpg (or .jpeg) and .png, respectively.

Portability Tip 18.1

Class Image is an abstract class and, as a result, programs cannot instantiate Image objects. To achieve platform independence, the Java implementation on each platform provides its own subclass of Image to store image information.

When line 20 invokes method getImage to set up loading of the image from the local computer (or downloading of the image from the Internet). When the image is required by the program, the image is loaded in a separate thread of execution. This enables the program to continue execution while the image loads. [Note: If the requested file is not available, method getImage does not indicate an error.]

Class ImageIcon is not an abstract class; therefore, a program can create an ImageIcon object. Line 21 in method init creates an ImageIcon object that loads the same logo.gif image. Class ImageIcon provides several constructors that enable programs to initialize ImageIcon objects with images from the local computer or with images stored on the Internet.

The applet’s paint method (lines 25–37) displays the images. Line 28 uses Graphics method drawImage to display an Image. Method drawImage receives four arguments. The first argument is a reference to the Image object to display (logo1). The second and third arguments are the x- and y-coordinates at which to display the image on the applet; the coordinates indicate the upper-left corner of the image. The last argument is a reference to an ImageObserver object. Normally, the ImageObserver is the object on which the program displays the image. An ImageObserver can be any object that implements interface ImageObserver. Class Component (one of class Applet’s indirect superclasses) implements interface ImageObserver. Therefore, all Components (including our applet) are ImageObservers. The ImageObserver argument is important when displaying large images that require a long time to download from the Internet. It is possible that a program will execute the code that displays the image before the image downloads completely. The ImageObserver is notified to update the displayed image as the remainder of the image loads. When executing this applet, watch carefully as pieces of the image display while the image loads. [Note: On faster computers, you might not notice this effect.]

Lines 32–33 use another version of Graphics method drawImage to output a scaled version of the image. The fourth and fifth arguments specify the width and height of

Chapter 18

Multimedia: Images, Animation, Audio and Video

1073

the image for display purposes. Method drawImage scales the image to fit the specified width and height. In this example, the fourth argument indicates that the width of the scaled image should be the width of the applet, and the fifth argument indicates that the height should be 120 pixels less than the height of the applet. Line 33 determines the width and height of the applet by calling methods getWidth and getHeight (inherited from class

Component).

Line 36 uses ImageIcon method paintIcon to display the image. The method requires four arguments—a reference to the Component on which to display the image, a reference to the Graphics object that will render the image, the x-coordinate of the upperleft corner of the image and the y-coordinate of the upper-left corner of the image.

If you compare the two techniques for loading and displaying images in this example, you can see that using ImageIcon is simpler. You can create objects of class ImageIcon directly, and there is no need to use an ImageObserver reference when displaying the image. For this reason, we use class ImageIcon for the remainder of the chapter. [Note: Class ImageIcon’s paintIcon method does not allow scaling of an image. However, the class provides method getImage, which returns an Image reference that Graphics method drawImage can use to display a scaled image.]

18.3 Animating a Series of Images

The next example demonstrates animating a series of images that are stored in an array. The application uses the same techniques to load and display ImageIcons as shown in Fig. 18.1. The animation presented in Fig. 18.2 is designed as a subclass of JPanel (called LogoAnimator) that can be attached to an application window or possibly to a JApplet. Class LogoAnimator also defines a main method (defined at lines 96–117) to execute the animation as an application. Method main defines an instance of class JFrame and attaches a LogoAnimator object to the JFrame to display the animation.

1 // Fig. 18.2: LogoAnimator.java

2 // Animation a series of images

3

4 // Java core packages

5import java.awt.*;

6 import java.awt.event.*;

7

8 // Java extension packages

9 import javax.swing.*;

10

11public class LogoAnimator extends JPanel

12implements ActionListener {

13

 

 

14

protected ImageIcon images[];

// array of images

15

 

 

16

protected int totalImages = 30,

// number of images

17

currentImage = 0,

// current image index

18

animationDelay = 50,

// millisecond delay

19

width,

// image width

20

height;

// image height

Fig. 18.2 Animating a series of images (part 1 of 3).

1074

Multimedia: Images, Animation, Audio and Video

Chapter 18

21

22protected String imageName = "deitel"; // base image name

23protected Timer animationTimer; // Timer drives animation

25// initialize LogoAnimator by loading images

26public LogoAnimator()

27{

28initializeAnimation();

29}

30

31// initialize animation

32protected void initializeAnimation()

33{

34images = new ImageIcon[ totalImages ];

36// load images

37for ( int count = 0; count < images.length; ++count )

38

images[ count ] = new ImageIcon(

getClass().getResource(

39

"images/" +

imageName + count + ".gif"

) );

 

40

 

 

 

 

 

41

width = images[ 0

].getIconWidth();

// get

icon

width

42height = images[ 0 ].getIconHeight(); // get icon height

43}

44

45// display current image

46public void paintComponent( Graphics g )

47{

48super.paintComponent( g );

49

50images[ currentImage ].paintIcon( this, g, 0, 0 );

51currentImage = ( currentImage + 1 ) % totalImages;

52}

53

54// respond to Timer's event

55public void actionPerformed( ActionEvent actionEvent )

56{

57repaint(); // repaint animator

58}

59

60// start or restart animation

61public void startAnimation()

62{

63if ( animationTimer == null ) {

64

currentImage =

0;

65

animationTimer

= new Timer( animationDelay, this );

66animationTimer.start();

67}

68else // continue from last image displayed

69

if ( ! animationTimer.isRunning() )

70

animationTimer.restart();

71

}

72

 

 

 

Fig. 18.2 Animating a series of images (part 2 of 3).

Chapter 18

Multimedia: Images, Animation, Audio and Video

1075

73// stop animation timer

74public void stopAnimation()

75{

76animationTimer.stop();

77}

78

79// return minimum size of animation

80public Dimension getMinimumSize()

81{

82return getPreferredSize();

83}

84

85// return preferred size of animation

86public Dimension getPreferredSize()

87{

88return new Dimension( width, height );

89}

90

91// execute animation in a JFrame

92public static void main( String args[] )

93{

94// create LogoAnimator

95LogoAnimator animation = new LogoAnimator();

97// set up window

98JFrame window = new JFrame( "Animator test" );

100Container container = window.getContentPane();

101container.add( animation );

102

103 window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

104

105// size and display window

106window.pack();

107Insets insets = window.getInsets();

109 window.setSize( animation.getPreferredSize().width +

110 insets.left + insets.right,

111 animation.getPreferredSize().height +

112 insets.top + insets.bottom );

113

114window.setVisible( true );

115animation.startAnimation(); // begin animation

117 } // end method main

118

119 } // end class LogoAnimator

Fig. 18.2 Animating a series of images (part 3 of 3).

1076

Multimedia: Images, Animation, Audio and Video

Chapter 18

Class LogoAnimator maintains an array of ImageIcons that are loaded in method initializeAnimation (lines 32–43), which is called from the constructor. As the for structure (lines 37–39) creates each ImageIcon object, the ImageIcon constructor loads one of the animation’s 30 images. The constructor argument uses String concatenation to assemble the file name from the pieces "images/", imageName, count and ".gif". Each of the images in the animation is in a file called deitel#.gif, where # is a value in the range 0–29 specified by the loop’s control variable count. Lines 41–42 determine the width and height of the animation from the size of the first image in array images.

Performance Tip 18.1

It is more efficient to load the frames of the animation as one image than to load each image separately. (A painting program can be used to combine the frames of the animation into one image. If the images are being loaded from the Web, every image loaded requires a separate connection to the site containing the images.

Performance Tip 18.2

Loading all the frames of an animation as one large image can force your program to wait to begin displaying the animation.

After the LogoAnimator constructor loads the images, method main sets up the window in which the animation will appear and calls startAnimation (defined at lines 61–71) to begin the animation. The animation is driven by an instance of class Timer (package javax.swing). A Timer generates ActionEvents at a fixed interval in milliseconds (normally specified as an argument to the Timer’s constructor) and notifies all of its ActionListeners that the event occurred. Lines 63–67 determine whether the Timer reference animationTimer is null. If so, line 64 sets currentImage to 0, to indicate that the animation should begin with the image in the first element of array images. Line 65 assigns a new Timer object to animationTimer. The Timer constructor receives two arguments—the delay in milliseconds (animationDelay is 50 in this example) and the

ActionListener that will respond to the Timer’s ActionEvents. Class LogoAnimator implements ActionListener so line 65 specifies this as the listener. Line 66 starts the Timer object. Once started, animationTimer will generate an ActionEvent every 50 milliseconds. Lines 69–70 enable a program to restart an animation that the program stopped previously. For example, to make an animation “browser friendly” in an applet, the animation should stop when the user switches Web pages. If the user returns to the Web page with the animation, method startAnimation can be called to restart the animation. The if condition at line 73 uses Timer method isRunning to determine whether the Timer is running (i.e., generating events). If it is not running, line 70 calls Timer method restart to indicate that the Timer should start generating events again.

In response to every Timer event in this example, the program calls method actionPerformed (lines 55–58). Line 57 calls LogoAnimator’s repaint method to schedule a call to the LogoAnimator’s update method (inherited from class JPanel) which, in turn, calls LogoAnimator’s paintComponent method (lines 46– 52). Remember that any subclass of JComponent that performs drawing should do so in its paintComponent method. As mentioned in Chapter 13, the first statement in any paintComponent method should be a call to the superclass’s paintComponent method to ensure that Swing components are displayed correctly.

Chapter 18

Multimedia: Images, Animation, Audio and Video

1077

Lines 50–51 paint the ImageIcon at element currentImage in the array and prepare for the next image to be displayed by incrementing currentImage by 1. Notice the modulus calculation to ensure that the value of currentImage is set to 0 when it is incremented past 29 (the last element subscript in the array).

Method stopAnimation (lines 74–77) stops the animation with line 76, which calls Timer method stop to indicate that the Timer should stop generating events. This prevents actionPerformed from calling repaint to initiate the painting of the next image in the array.

Software Engineering Observation 18.1

When creating an animation for use in an applet, provide a mechanism for disabling the an- imation when the user browses a new Web page separate from the page on which the animation applet resides.

Methods getMinimumSize (lines 80–83) and getPreferredSize (lines 86– 89) override the corresponding methods inherited from class Component and enable layout managers to determine the appropriate size of a LogoAnimator in a layout. In this example, the images are 160 pixels wide and 80 pixels tall, so method getPreferredSize returns a Dimension object containing the numbers 160 and 80. Method getMinimumSize simply calls getPreferredSize (a common programming practice).

Lines 107–112 of main size the application window based on the LogoAnimator’s preferred size and the window’s insets. The insets specify the number of pixels for the window’s top, bottom, left and right borders. Using the insets of the window ensures that the window’s client area is large enough to display the LogoAnimator correctly. The client area is the part of a window in which the window displays GUI components. The program obtains the window’s insets by calling method getInsets at line 107. The method returns an Insets object that contains public data members top, bottom, left and right.

18.4 Customizing LogoAnimator via Applet Parameters

When browsing the World Wide Web, you often will come across applets that are in the public domain—you can use them free of charge on your own Web pages (normally in exchange for crediting the applet’s creator). One common feature of such applets is the ability to be customized via parameters that are supplied from the HTML file that invokes the applet. For example, the HTML

<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>

from file LogoApplet.html, invokes the applet LogoApplet (Fig. 18.4) and specifies three parameters. The param tag lines must appear between the starting and ending applet tags. Each parameter has a name and a value. Applet method getParameter returns a String representing the value associated with a specific parameter name. The argument to getParameter is a String containing the name of the parameter in the param tag. For example, the statement

1078

Multimedia: Images, Animation, Audio and Video

Chapter 18

parameter = getParameter( "animationdelay" );

gets the value 200 associated with parameter animationdelay and assigns it to String reference parameter. If there is not a param tag containing the specified parameter name, getParameter returns null.

Class LogoAnimator2 (Fig. 18.3) extends class LogoAnimator and adds a constructor that takes three arguments—the total number of images in the animation, the delay between displaying images and the base image name. Class LogoApplet (Fig. 18.4) allows Web page designers to customize the animation to use their own images. Three parameters are provided in the applet’s HTML document. Parameter animationdelay is the number of milliseconds to sleep between displaying images. This value will be converted to an integer and used as the value for instance variable sleepTime. Parameter imagename is the base name of the images to be loaded. This String will be assigned to instance variable imageName. The applet assumes that the images are in a subdirectory named images that can be found in the same directory as the applet. The applet also assumes that the image file names are numbered from 0 (as in Fig. 18.2). Parameter totalimages represents the total number of images in the animation. Its value will be converted to an integer and assigned to instance variable totalImages.

1 // Fig. 18.3: LogoAnimator2.java

2 // Animating a series of images

3

4 // Java core packages

5 import java.awt.*;

6

7 // Java extension packages

8 import javax.swing.*;

9

10 public class LogoAnimator2 extends LogoAnimator {

11

12// default constructor

13public LogoAnimator2()

14{

15super();

16}

17

18// new constructor to support customization

19public LogoAnimator2( int count, int delay, String name )

20{

21totalImages = count;

22animationDelay = delay;

23imageName = name;

24

25initializeAnimation();

26}

27

Fig. 18.3 LogoAnimator2 subclass of LogoAnimator (Fig. 18.2) adds a constructor for customizing the number of images, animation delay and base image name (part 1 of 2).

Chapter 18

Multimedia: Images, Animation, Audio and Video

1079

28// start animation as application in its own window

29public static void main( String args[] )

30{

31// create LogoAnimator

32LogoAnimator2 animation = new LogoAnimator2();

34// set up window

35JFrame window = new JFrame( "Animator test" );

37Container container = window.getContentPane();

38container.add( animation );

39

40 window.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

41

42// size and display window

43window.pack();

44Insets insets = window.getInsets();

46

window.setSize(

animation.getPreferredSize().width +

47

insets.left + insets.right,

48

animation.getPreferredSize().height +

49

insets.top +

insets.bottom );

50

 

 

51window.setVisible( true );

52animation.startAnimation(); // begin animation

54 } // end method main

55

56 } // end class LogoAnimator2

Fig. 18.3 LogoAnimator2 subclass of LogoAnimator (Fig. 18.2) adds a constructor for customizing the number of images, animation delay and base image name (part 2 of 2).

1// Fig. 18.4: LogoApplet.java

2// Customizing an applet via HTML parameters.

3//

4// HTML parameter "animationdelay" is an int indicating

5// milliseconds to sleep between images (default 50).

6//

7// HTML parameter "imagename" is the base name of the images

8// that will be displayed (i.e., "deitel" is the base name

9// for images "deitel0.gif," "deitel1.gif," etc.). The applet

10// assumes that images are in an "images" subdirectory of

11// the directory in which the applet resides.

12//

13// HTML parameter "totalimages" is an integer representing the

14// total number of images in the animation. The applet assumes

15// images are numbered from 0 to totalimages - 1 (default 30).

17// Java core packages

18import java.awt.*;

Fig. 18.4 Customizing an animation applet via the param HTML tag (part 1 of 2).

1080

Multimedia: Images, Animation, Audio and Video

Chapter 18

19

20// Java extension packages

21import javax.swing.*;

22

23 public class LogoApplet extends JApplet {

24

25// obtain parameters from HTML and customize applet

26public void init()

27{

28String parameter;

29

30// get animation delay from HTML document

31parameter = getParameter( "animationdelay" );

33 int animationDelay = ( parameter == null ?

34 50 : Integer.parseInt( parameter ) );

35

36// get base image name from HTML document

37String imageName = getParameter( "imagename" );

39// get total number of images from HTML document

40parameter = getParameter( "totalimages" );

41

42 int totalImages = ( parameter == null ?

43 0 : Integer.parseInt( parameter ) );

44

45// create instance of LogoAnimator

46LogoAnimator2 animator;

47

48 if ( imageName == null || totalImages == 0 )

49animator = new LogoAnimator2();

50else

51

animator = new LogoAnimator2( totalImages,

52

animationDelay, imageName );

53

 

54// attach animator to applet and start animation

55getContentPane().add( animator );

56animator.startAnimation();

57

58 } // end method init

59

60 } // end class LogoApplet

Fig. 18.4 Customizing an animation applet via the param HTML tag (part 2 of 2).