epubjs
Version:
Render ePub documents in the browser, across many devices
176 lines (172 loc) • 22.3 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Displaying Images</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Displaying Images"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-20-SECT-7"/>Displaying Images</h1></div></div></div><p>So far, we’ve worked with methods for drawing simple shapes and
displaying text. For more complex graphics, we’ll be working with images.
In a typical Swing application, the simplest way to display an image in
your application is to use an <code class="literal">ImageIcon</code>
with a <code class="literal">JLabel</code> component. Here, we are
talking about working with image data at a lower level, for painting. The
2D API has a powerful set of tools for generating and displaying image
data. We’ll start with the basics of the <code class="literal">java.awt.Image</code> class and see how to load an
image into an application and draw it where you want it. The Java AWT
toolkit will handle most of the details for us. In the next chapter, we’ll
go further to discuss how to manage image loading manually as well as how
to create and manipulate raw pixel data, allowing you to create any kind
of graphics you can dream up.</p><p>The core AWT supports images encoded in JPEG, PNG, and GIF. (This
includes GIF89a animations so that you can work with simple animations as
easily as static images.) If you need to work with other types of images,
you can turn to the Java Advanced Imaging <code class="literal">javax.imageio</code> framework. We’ll mention it
briefly <code class="literal">here</code> and again in the next
chapter when we discuss the <code class="literal">BufferedImage</code> class.</p><p>In many ways, the ImageIO framework supercedes and replaces the
older image handling functionality of the core AWT just as Swing extends
and replaces the old AWT components. The ImageIO framework is easily
extensible for new image types through plug-ins. However, out of the box,
all that it adds in terms of image type support is the ability to read
bitmap (BMP) and wireless bitmap (WBMP) images. Since most Java code can
and does use the original AWT functionality, that is where we’ll
focus.</p><div class="sect2" title="The Image Class"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-7.1"/>The Image Class</h2></div></div></div><p><a id="idx11088" class="indexterm"/> <a id="idx11098" class="indexterm"/> <a id="idx11099" class="indexterm"/>The <a id="I_indexterm20_id813202" class="indexterm"/><code class="literal">java.awt.Image</code> class
represents a view of an image. The view is created from an image source
that produces pixel data. Images can be from a static source, such as a
JPEG file, or a dynamic one, such as a video stream or a graphics
engine.</p><p>AWT Images are created with the <a id="I_indexterm20_id813218" class="indexterm"/><code class="literal">getImage()</code> and
<a id="I_indexterm20_id813228" class="indexterm"/><code class="literal">createImage()</code> methods
of the <a id="I_indexterm20_id813239" class="indexterm"/><code class="literal">java.awt.Toolkit</code> class.
There are two forms of each method, which accept a URL or plain
filename, respectively. <code class="literal">createImage()</code>
can also accept a byte array of image data directly.</p><p>When bundling images with your application, you should use the
<code class="literal">Class</code> class’s <code class="literal">getResource()</code> method (discussed in <a class="xref" href="ch01.html" title="Chapter 1. A Modern Language">Chapter 1</a>) to construct a URL reference to the file
from the application classpath. <code class="literal">getResource()</code> allows you to bundle images
along with your application, inside JAR files or anywhere else in the
classpath. The following code fragment shows some examples of loading
images with the <code class="literal">getImage()</code>
method:</p><a id="I_20_tt1160"/><pre class="programlisting"> <code class="n">Toolkit</code> <code class="n">toolkit</code> <code class="o">=</code> <code class="n">Toolkit</code><code class="o">.</code><code class="na">getDefaultToolkit</code><code class="o">();</code>
<code class="c1">// Application resource URL - Best method</code>
<code class="n">URL</code> <code class="n">daffyURL</code> <code class="o">=</code> <code class="n">getClass</code><code class="o">().</code><code class="na">getResource</code><code class="o">(</code><code class="s">"/cartoons/images/daffy.gif"</code><code class="o">);</code>
<code class="n">Image</code> <code class="n">daffyDuckImage</code> <code class="o">=</code> <code class="n">toolkit</code><code class="o">.</code><code class="na">getImage</code><code class="o">(</code> <code class="n">daffyURL</code> <code class="o">);</code>
<code class="c1">// Absolute URL -</code>
<code class="n">URL</code> <code class="n">monaURL</code> <code class="o">=</code> <code class="k">new</code> <code class="n">URL</code><code class="o">(</code> <code class="s">"http://myserver/images/mona_lisa.png"</code><code class="o">);</code>
<code class="n">Image</code> <code class="n">monaImage</code> <code class="o">=</code> <code class="n">toolkit</code><code class="o">.</code><code class="na">getImage</code><code class="o">(</code> <code class="n">monaURL</code> <code class="o">);</code>
<code class="c1">// Local file -</code>
<code class="n">Image</code> <code class="n">elvisImage</code> <code class="o">=</code> <code class="n">toolkit</code><code class="o">.</code><code class="na">getImage</code><code class="o">(</code><code class="s">"c:/elvis/lateryears/fatelvis1.jpg"</code> <code class="o">);</code></pre><p>The <code class="literal">createImage()</code> method looks
just like <code class="literal">getImage()</code>; the difference
is that <code class="literal">getImage()</code> “interns” images
and shares them when it receives multiple requests for the same data.
The <code class="literal">createImage()</code> method does not do
this (it creates a new <code class="literal">Image</code> object
every time) and relies on you to cache and share the image. <code class="literal">getImage()</code> is convenient in an application
that uses a limited number of images for the life of the application,
but it may not ever release the image data. You should use <code class="literal">createImage()</code> and cache the <code class="literal">Image</code> objects yourself when it’s an
issue.</p><p>The <a id="I_indexterm20_id813353" class="indexterm"/><code class="literal">javax.imageio.ImageIO</code>
class similarly provides several static <code class="literal">read()</code> methods that can load images from a
<code class="literal">File</code>, <code class="literal">URL</code>, or <code class="literal">InputStream</code>:</p><a id="I_20_tt1161"/><pre class="programlisting"> <code class="n">URL</code> <code class="n">daffyURL</code> <code class="o">=</code> <code class="n">getClass</code><code class="o">().</code><code class="na">getResource</code><code class="o">(</code><code class="s">"/cartoons/images/daffy.gif"</code><code class="o">);</code>
<code class="n">Image</code> <code class="n">daffyDuckImage</code> <code class="o">=</code> <code class="n">ImageIO</code><code class="o">.</code><code class="na">read</code><code class="o">(</code> <code class="n">daffyURL</code> <code class="o">);</code></pre><p>We’ll discuss image loading with AWT and the ImageIO framework in
more detail in <a class="xref" href="ch21.html" title="Chapter 21. Working with Images and Other Media">Chapter 21</a>.</p><p>Once we have an <code class="literal">Image</code> object,
we can draw it into a graphics context with the <a id="I_indexterm20_id813411" class="indexterm"/><code class="literal">drawImage()</code> method of
the <code class="literal">Graphics</code> class. The simplest form
of the <code class="literal">drawImage()</code> method takes four
parameters: the <code class="literal">Image</code> object, the
<code class="literal">x</code>, <code class="literal">y</code> coordinates at which to draw it, and a
reference to a special <span class="emphasis"><em>image observer</em></span> object. We’ll
show an example involving <code class="literal">drawImage()</code>
soon, but first let’s say a word about image observers.<a id="I_indexterm20_id813460" class="indexterm"/><a id="I_indexterm20_id813467" class="indexterm"/><a id="I_indexterm20_id813474" class="indexterm"/></p></div><div class="sect2" title="Image Observers"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-7.2"/>Image Observers</h2></div></div></div><p><a id="idx11089" class="indexterm"/> <a id="idx11100" class="indexterm"/>Images are processed asynchronously, which means that Java
performs image operations, such as loading and scaling in the background
(allowing the user code to continue). In a typical client application,
this might not be important; images may be small for things like
buttons, and are probably bundled with the application for almost
instant retrieval. However, Java was designed to work with image data
over the Web as well as locally, and you will see this expressed in the
APIs for working with image data.</p><p>For example, the <a id="I_indexterm20_id813522" class="indexterm"/><code class="literal">getImage()</code> method
always returns immediately, even if the image data has to be retrieved
over the network from Mars and isn’t available yet. In fact, if it’s a
new image, Java won’t even begin to fetch the data until we try to
display or manipulate it. The advantage of this technique is that Java
can do the work of a powerful, multithreaded image processing
environment for us. However, it also introduces several problems. If
Java is loading an image for us, how do we know when it’s completely
loaded? What if we want to work with the image as it arrives? What if we
need to know properties of the image (like its dimensions) before we can
start working with it? What if there’s an error in loading the
image?</p><p>These issues are handled by <span class="emphasis"><em>image observers</em></span>,
objects that implement the <a id="I_indexterm20_id813546" class="indexterm"/><code class="literal">ImageObserver</code>
interface. All operations that draw or examine <code class="literal">Image</code> objects are asynchronous and take an
image observer object as a parameter. The <code class="literal">ImageObserver</code> monitors the image operation’s
status and can make that information available to the rest of the
application. When image data is loaded from its source by the graphics
system, your image observer is notified of its progress, including when
new pixels are available, when a complete frame of the image is ready,
and if there is an error during loading. The image observer also
receives attribute information about the image, such as its dimensions
and properties, as soon as they are known.</p><p>The <code class="literal">drawImage()</code> method, like
other image operations, takes a reference to an <code class="literal">ImageObserver</code> object as a parameter. <code class="literal">drawImage()</code> returns a <code class="literal">boolean</code> value specifying whether or not the
image was painted in its entirety. If the image data has not yet been
loaded or is only partially available, <a id="I_indexterm20_id813600" class="indexterm"/><code class="literal">drawImage()</code> paints
whatever fraction of the image it can and returns. In the background,
the graphics system starts (or continues) loading the image data. The
image observer object is registered as interested in information about
the image. The observer is then called repeatedly as more pixel
information is available and again when the entire image is complete.
The image observer can do whatever it wants with this information. Most
often the information is used to call <a id="I_indexterm20_id813615" class="indexterm"/><code class="literal">repaint()</code> to prompt the
application to draw the image again with the updated data. In this way,
an application or applet can draw the image as it arrives for a
progressive loading effect. Alternatively, it could wait until the
entire image is loaded before displaying it.</p><p>Image observers are covered in <a class="xref" href="ch21.html" title="Chapter 21. Working with Images and Other Media">Chapter 21</a>. For now, let’s avoid the issue by using
a prefabricated image observer. The <code class="literal">Component</code> class implements the <code class="literal">ImageObserver</code> interface and provides some
simple repainting behavior, which means every component can serve as its
own default image observer. We can simply pass a reference to whatever
component is doing the painting as the image observer parameter of a
<code class="literal">drawImage()</code> call:</p><a id="I_20_tt1162"/><pre class="programlisting"> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">paint</code><code class="o">(</code> <code class="n">Graphics</code> <code class="n">g</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">g</code><code class="o">.</code><code class="na">drawImage</code><code class="o">(</code> <code class="n">monaImage</code><code class="o">,</code> <code class="n">x</code><code class="o">,</code> <code class="n">y</code><code class="o">,</code> <code class="k">this</code> <code class="o">);</code>
<code class="o">...</code></pre><p>Our component serves as the image observer and calls <code class="literal">repaint()</code> for us to redraw the image as
necessary. If the image arrives slowly, our component is notified
repeatedly as new chunks become available. As a result, the image
appears gradually as it’s loaded.<sup>[<a id="learnjava3-CHP-20-FN-1" href="#ftn.learnjava3-CHP-20-FN-1" class="footnote">44</a>]</sup></p><div class="sect3" title="Preloading images"><div class="titlepage"><div><div><h3 class="title"><a id="learnjava3-CHP-20-SECT-7.2.1"/>Preloading images</h3></div></div></div><p><a id="I_indexterm20_id813728" class="indexterm"/> <a id="I_indexterm20_id813739" class="indexterm"/> <a id="idx11106" class="indexterm"/>We’ll discuss image loading in more detail in the next
chapter when we look at the <code class="literal">MediaTracker</code> utility, which
monitors the load progress of one or more images. However, we’ll skip
ahead a bit here and show you the easy shortcut for loading a single
image and making sure it’s complete and ready to draw. You can use the
<a id="I_indexterm20_id813773" class="indexterm"/><code class="literal">javax.swing.ImageIcon</code>
class to do the dirty work for you:</p><a id="I_20_tt1163"/><pre class="programlisting"> <code class="n">ImageIcon</code> <code class="n">icon</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ImageIcon</code><code class="o">(</code><code class="s">"myimage.jpg"</code><code class="o">);</code>
<code class="n">Image</code> <code class="n">image</code> <code class="o">=</code> <code class="n">icon</code><code class="o">.</code><code class="na">getImage</code><code class="o">();</code></pre><p>Images loaded by the <code class="literal">ImageIO
read()</code> methods are returned fully loaded. <code class="literal">ImageIO</code> provides its own API for monitoring
image loading progress. That API follows a more standard event
source/listener pattern, but we won’t get into it here.<a id="I_indexterm20_id813810" class="indexterm"/><a id="I_indexterm20_id813817" class="indexterm"/></p></div></div><div class="sect2" title="Scaling and Size"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-20-SECT-7.3"/>Scaling and Size</h2></div></div></div><p><a id="idx11091" class="indexterm"/> <a id="idx11103" class="indexterm"/> <a id="idx11109" class="indexterm"/>Another version of <a id="I_indexterm20_id813869" class="indexterm"/><code class="literal">drawImage()</code> renders a
scaled version of the image:</p><a id="I_20_tt1164"/><pre class="programlisting"> <code class="n">g</code><code class="o">.</code><code class="na">drawImage</code><code class="o">(</code> <code class="n">monaImage</code><code class="o">,</code> <code class="n">x</code><code class="o">,</code> <code class="n">y</code><code class="o">,</code> <code class="n">x2</code><code class="o">,</code> <code class="n">y2</code><code class="o">,</code> <code class="k">this</code> <code class="o">);</code></pre><p>This draws the entire image within the rectangle formed by the
points <code class="literal">x</code>, <code class="literal">y</code> and <code class="literal">x2</code>,
<code class="literal">y2</code>, scaling as necessary. <code class="literal">drawImage()</code> behaves the same as before; the
image is processed by the component as it arrives, and the image
observer is notified as more pixel data and the completed image are
available. Several other overloaded versions of <code class="literal">drawImage()</code> provide more complex options: you
can scale, crop, and perform some simple transpositions.</p><p>Normally, however, for performance you want to make a scaled copy
of an image (as opposed to simply painting one at draw time); you can
use <a id="I_indexterm20_id813930" class="indexterm"/><code class="literal">getScaledInstance()</code> for
this purpose. Here’s how:</p><a id="I_20_tt1165"/><pre class="programlisting"> <code class="n">Image</code> <code class="n">scaledDaffy</code> <code class="o">=</code>
<code class="n">daffyImage</code><code class="o">.</code><code class="na">getScaledInstance</code><code class="o">(</code> <code class="mi">100</code><code class="o">,</code> <code class="mi">200</code><code class="o">,</code> <code class="n">Image</code><code class="o">.</code><code class="na">SCALE_AREA_AVERAGING</code> <code class="o">);</code></pre><p>This method scales the original image to the given size—in this
case, 100 by 200 pixels. It returns a new <code class="literal">Image</code> that you can draw like any other image.
<a id="I_indexterm20_id813961" class="indexterm"/><code class="literal">SCALE_AREA_AVERAGING</code> is
a constant that tells <code class="literal">getScaledImage()</code> what scaling algorithm to
use. The algorithm used here tries to do a decent job of scaling at the
expense of time. Some alternatives that take less time are <a id="I_indexterm20_id813980" class="indexterm"/><code class="literal">SCALE_REPLICATE</code>, which
scales by replicating scan lines and columns (which is fast, but
probably not pretty). You can also specify either <a id="I_indexterm20_id813992" class="indexterm"/><code class="literal">SCALE_FAST</code> or
<a id="I_indexterm20_id814002" class="indexterm"/><code class="literal">SCALE_SMOOTH</code> and let
the implementation choose an appropriate algorithm that optimizes for
time or quality. If you don’t have specific requirements, you should use
<a id="I_indexterm20_id814016" class="indexterm"/><code class="literal">SCALE_DEFAULT</code>, which
ideally would be set by a preference in the user’s environment.</p><p>If you are going to draw the image more than once (which you
almost always will), creating a scaled copy of the image can improve
performance dramatically. Otherwise, repeated calls to <code class="literal">drawImage()</code> with scaling requirements cause
the image to be scaled every time, which wastes processing time.</p><p>The <code class="literal">Image getHeight()</code> and
<code class="literal">getWidth()</code> methods retrieve the
dimensions of an image. Because this information may not be available
until the image data is completely loaded, both methods also take an
<code class="literal">ImageObserver</code> object as a parameter.
If the dimensions aren’t yet available, they return values of <code class="literal">-1</code> and notify the observer when the actual
value is known. We’ll see how to deal with these and other problems a
bit later. For now, we’ll continue to use our <code class="literal">Component</code> as the image observer and move on to
some general painting techniques.<a id="I_indexterm20_id814074" class="indexterm"/><a id="I_indexterm20_id814081" class="indexterm"/><a id="I_indexterm20_id814088" class="indexterm"/></p></div><div class="footnotes"><br/><hr/><div class="footnote"><p><sup>[<a id="ftn.learnjava3-CHP-20-FN-1" href="#learnjava3-CHP-20-FN-1" class="para">44</a>] </sup>The <code class="literal">awt.image.incrementaldraw</code> and <code class="literal">awt.image.redrawrate</code> system properties
control this behavior. <code class="literal">redrawrate</code>
limits how often <code class="literal">repaint()</code> is
called; the default value is every 100 milliseconds. <code class="literal">incrementaldraw</code>’s default value, <code class="literal">true</code>, enables this behavior. Setting it to
<code class="literal">false</code> delays drawing until the
entire image has arrived.</p></div></div></div></body></html>