epubjs
Version:
Render ePub documents in the browser, across many devices
272 lines (263 loc) • 37.7 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Loading 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="Loading Images"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-21-SECT-1"/>Loading Images</h1></div></div></div><p>One of the challenges in building software for networked
applications is that data is not always instantly available. Since some of
Java’s roots are in Internet applications such as web browsers, its image
handling APIs were designed specifically to accommodate the fact that
images might take some time to load over a slow network, providing for
detailed information about image-loading progress. While many client
applications do not require handling of image data in this way, it’s still
useful to understand this mechanism if for no other reason than it appears
in the most basic image-related APIs. The Swing toolkit adds its own layer
of image handling over this with components such as <code class="literal">ImageIcon</code>, which encapsulates an image source
for you. After reading this chapter, you’ll have an understanding of how
the layers fit together.</p><div class="sect2" title="ImageObserver"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-21-SECT-1.1"/>ImageObserver</h2></div></div></div><p><a id="idx11119" class="indexterm"/> <a id="idx11123" class="indexterm"/> <a id="idx11135" class="indexterm"/>In the previous chapter, we mentioned that all operations
on image data (e.g., loading, drawing, scaling) allow you to specify an
“image observer” object as a participant. An image observer implements
the <code class="literal">ImageObserver</code> interface, allowing
it to receive notification as information about the image becomes
available. The image observer is essentially a callback that is notified
progressively as the image is loaded. For a static image, such as a GIF
or JPEG data file, the observer is notified as chunks of image data
arrive and also when the entire image is complete. For a video source or
animation (e.g., GIF89), the image observer is notified at the end of
each frame as the continuous stream of pixel data is generated.</p><p>The image observer can do whatever it wants with this information.
For example, in the last chapter we used the image observer built into
the base <code class="literal">Component</code> class. Although
you probably didn’t see it happen in our examples, the <code class="literal">Component</code> image observer invoked <code class="literal">repaint()</code> for us each time a new section of
the image became available so that the picture, if it had taken a long
time to load, would have displayed progressively. A different kind of
image observer might have waited for the entire image before telling the
application to display it; yet another use for an observer might be to
update a loading meter showing how far the image loading had
progressed.</p><p>To be an image observer, implement the <a id="I_indexterm21_id815559" class="indexterm"/><code class="literal">imageUpdate()</code> method,
which is defined by the <code class="literal">java.awt.image.ImageObserver</code> interface:</p><a id="I_21_tt1176"/><pre class="programlisting"> <code class="kd">public</code> <code class="kt">boolean</code> <code class="nf">imageUpdate</code><code class="o">(</code><code class="n">Image</code> <code class="n">image</code><code class="o">,</code> <code class="kt">int</code> <code class="n">flags</code><code class="o">,</code> <code class="kt">int</code> <code class="n">x</code><code class="o">,</code> <code class="kt">int</code> <code class="n">y</code><code class="o">,</code>
<code class="kt">int</code> <code class="n">width</code><code class="o">,</code> <code class="kt">int</code> <code class="n">height</code><code class="o">)</code></pre><p><code class="literal">imageUpdate()</code> is called by the
graphics system, as needed, to pass the observer information about the
construction of its view of the image. The <code class="literal">image</code> parameter holds a reference to the
<code class="literal">Image</code> object in question. <code class="literal">flags</code> is an integer whose bits specify what
information about the image is now available. The flag values are
defined as <code class="literal">static</code> variables in the
<code class="literal">ImageObserver</code> interface, as
illustrated in this example:</p><a id="I_21_tt1177"/><pre class="programlisting"> <code class="c1">//file: ObserveImageLoad.java</code>
<code class="kn">import</code> <code class="nn">java.awt.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">java.awt.image.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">ObserveImageLoad</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code> <code class="n">String</code> <code class="o">[]</code> <code class="n">args</code><code class="o">)</code>
<code class="o">{</code>
<code class="n">ImageObserver</code> <code class="n">myObserver</code> <code class="o">=</code> <code class="k">new</code> <code class="n">ImageObserver</code><code class="o">()</code> <code class="o">{</code>
<code class="kd">public</code> <code class="kt">boolean</code> <code class="nf">imageUpdate</code><code class="o">(</code>
<code class="n">Image</code> <code class="n">image</code><code class="o">,</code> <code class="kt">int</code> <code class="n">flags</code><code class="o">,</code> <code class="kt">int</code> <code class="n">x</code><code class="o">,</code> <code class="kt">int</code> <code class="n">y</code><code class="o">,</code> <code class="kt">int</code> <code class="n">width</code><code class="o">,</code> <code class="kt">int</code> <code class="n">height</code><code class="o">)</code>
<code class="o">{</code>
<code class="k">if</code> <code class="o">(</code> <code class="o">(</code><code class="n">flags</code> <code class="o">&</code> <code class="n">HEIGHT</code><code class="o">)</code> <code class="o">!=</code><code class="mi">0</code> <code class="o">)</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Image height = "</code> <code class="o">+</code> <code class="n">height</code> <code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="o">(</code><code class="n">flags</code> <code class="o">&</code> <code class="n">WIDTH</code> <code class="o">)</code> <code class="o">!=</code><code class="mi">0</code> <code class="o">)</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Image width = "</code> <code class="o">+</code> <code class="n">width</code> <code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="o">(</code><code class="n">flags</code> <code class="o">&</code> <code class="n">FRAMEBITS</code><code class="o">)</code> <code class="o">!=</code> <code class="mi">0</code> <code class="o">)</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Another frame finished."</code><code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="o">(</code><code class="n">flags</code> <code class="o">&</code> <code class="n">SOMEBITS</code><code class="o">)</code> <code class="o">!=</code> <code class="mi">0</code> <code class="o">)</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Image section :"</code>
<code class="o">+</code> <code class="k">new</code> <code class="n">Rectangle</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">width</code><code class="o">,</code> <code class="n">height</code> <code class="o">)</code> <code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="o">(</code><code class="n">flags</code> <code class="o">&</code> <code class="n">ALLBITS</code><code class="o">)</code> <code class="o">!=</code> <code class="mi">0</code> <code class="o">)</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Image finished!"</code><code class="o">);</code>
<code class="k">if</code> <code class="o">(</code> <code class="o">(</code><code class="n">flags</code> <code class="o">&</code> <code class="n">ABORT</code><code class="o">)</code> <code class="o">!=</code> <code class="mi">0</code> <code class="o">)</code>
<code class="n">System</code><code class="o">.</code><code class="na">out</code><code class="o">.</code><code class="na">println</code><code class="o">(</code><code class="s">"Image load aborted..."</code><code class="o">);</code>
<code class="k">return</code> <code class="kc">true</code><code class="o">;</code>
<code class="o">}</code>
<code class="o">};</code>
<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="n">Image</code> <code class="n">img</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">args</code><code class="o">[</code><code class="mi">0</code><code class="o">]</code> <code class="o">);</code>
<code class="n">toolkit</code><code class="o">.</code><code class="na">prepareImage</code><code class="o">(</code> <code class="n">img</code><code class="o">,</code> <code class="o">-</code><code class="mi">1</code><code class="o">,</code> <code class="o">-</code><code class="mi">1</code><code class="o">,</code> <code class="n">myObserver</code> <code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>Run the example, supplying an image file as the command-line
argument and observe the output. You’ll see a number of incremental
messages about loading the image.</p><p>The <code class="literal">flags</code> integer determines
which of the other parameters—<code class="literal">x</code>,
<code class="literal">y</code>, <code class="literal">width</code>, and <code class="literal">height</code>—hold valid data and what that data
means. To test whether a particular flag in the <code class="literal">flags</code> integer is set, we have to resort to
some binary shenanigans—using the <code class="literal">&</code> (<code class="literal">AND</code>)
operator). The <code class="literal">width</code> and <code class="literal">height</code> parameters play a dual role. If
<code class="literal">SOMEBITS</code> is set, they represent the
size of the chunk of the image that has just been delivered. If <code class="literal">HEIGHT</code> or <code class="literal">WIDTH</code> is set, however, they represent the
overall image dimensions. Finally, <a id="I_indexterm21_id815726" class="indexterm"/><code class="literal">imageUpdate()</code> returns a
<code class="literal">boolean</code> value indicating whether or
not it’s interested in future updates.</p><p>In this example, after requesting the <code class="literal">Image</code> object with <a id="I_indexterm21_id815752" class="indexterm"/><code class="literal">getImage()</code>, we
kick-start the loading process with the Toolkit’s <a id="I_indexterm21_id815764" class="indexterm"/><code class="literal">prepareImage()</code> method,
which takes our image observer as an argument. Using an Image API method
such as <a id="I_indexterm21_id815775" class="indexterm"/><code class="literal">drawImage()</code>, <a id="I_indexterm21_id815786" class="indexterm"/><code class="literal">scaleImage()</code>, or asking
for image dimensions with <a id="I_indexterm21_id815797" class="indexterm"/><code class="literal">getWidth()</code> or
<a id="I_indexterm21_id815808" class="indexterm"/><code class="literal">getHeight()</code> will also
suffice to start the operation. Remember that although the <code class="literal">getImage()</code> method created the image object, it
doesn’t begin loading the data until one of the image operations
requires it.</p><p>The example shows the lowest-level general mechanism for starting
and monitoring the process of loading image data. You should be able to
see how we could implement all sorts of sophisticated image loading and
tracking schemes with this. The two most important strategies (to draw
an image progressively, as it’s constructed, or to wait until it’s
complete and draw it in its entirety) are handled for us. We have
already seen that the <code class="literal">Component</code> class
implements the first scheme. Another class, <code class="literal">java.awt.Media</code><code class="literal">Tracker</code>, is a general utility that tracks
the loading of a number of images or other media types for us. We’ll
look at it in the next section.<a id="I_indexterm21_id815857" class="indexterm"/><a id="I_indexterm21_id815864" class="indexterm"/><a id="I_indexterm21_id815871" class="indexterm"/></p></div><div class="sect2" title="MediaTracker"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-21-SECT-1.2"/>MediaTracker</h2></div></div></div><p><a id="idx11124" class="indexterm"/> <a id="idx11136" class="indexterm"/> <a id="idx11137" class="indexterm"/> <code class="literal">java.awt.MediaTracker</code>
is a utility class that simplifies life if we have to wait for one or
more images to be loaded completely before they’re displayed. A <code class="literal">MediaTracker</code> monitors the loading of an image
or a group of images and lets us check on them periodically or wait
until they are finished. <code class="literal">MediaTracker</code>
implements the <code class="literal">ImageObserver</code>
interface that we just discussed, allowing it to receive image
updates.</p><p>The following code snippet illustrates how to use a <code class="literal">MediaTracker</code> to wait while an image is
prepared:</p><a id="I_21_tt1178"/><pre class="programlisting"> <code class="c1">//file: StatusImage.java</code>
<code class="kn">import</code> <code class="nn">java.awt.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.swing.*</code><code class="o">;</code>
<code class="kd">public</code> <code class="kd">class</code> <code class="nc">StatusImage</code> <code class="kd">extends</code> <code class="n">JComponent</code>
<code class="o">{</code>
<code class="kt">boolean</code> <code class="n">loaded</code> <code class="o">=</code> <code class="kc">false</code><code class="o">;</code>
<code class="n">String</code> <code class="n">message</code> <code class="o">=</code> <code class="s">"Loading..."</code><code class="o">;</code>
<code class="n">Image</code> <code class="n">image</code><code class="o">;</code>
<code class="kd">public</code> <code class="nf">StatusImage</code><code class="o">(</code> <code class="n">Image</code> <code class="n">image</code> <code class="o">)</code> <code class="o">{</code> <code class="k">this</code><code class="o">.</code><code class="na">image</code> <code class="o">=</code> <code class="n">image</code><code class="o">;</code> <code class="o">}</code>
<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="k">if</code> <code class="o">(</code><code class="n">loaded</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">image</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="k">this</code><code class="o">);</code>
<code class="k">else</code> <code class="o">{</code>
<code class="n">g</code><code class="o">.</code><code class="na">drawRect</code><code class="o">(</code><code class="mi">0</code><code class="o">,</code> <code class="mi">0</code><code class="o">,</code> <code class="n">getSize</code><code class="o">().</code><code class="na">width</code> <code class="o">-</code> <code class="mi">1</code><code class="o">,</code> <code class="n">getSize</code><code class="o">().</code><code class="na">height</code> <code class="o">-</code> <code class="mi">1</code><code class="o">);</code>
<code class="n">g</code><code class="o">.</code><code class="na">drawString</code><code class="o">(</code><code class="n">message</code><code class="o">,</code> <code class="mi">20</code><code class="o">,</code> <code class="mi">20</code><code class="o">);</code>
<code class="o">}</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">loaded</code><code class="o">()</code> <code class="o">{</code>
<code class="n">loaded</code> <code class="o">=</code> <code class="kc">true</code><code class="o">;</code>
<code class="n">repaint</code><code class="o">();</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kt">void</code> <code class="nf">setMessage</code><code class="o">(</code> <code class="n">String</code> <code class="n">msg</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">message</code> <code class="o">=</code> <code class="n">msg</code><code class="o">;</code>
<code class="n">repaint</code><code class="o">();</code>
<code class="o">}</code>
<code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code> <code class="n">String</code> <code class="o">[]</code> <code class="n">args</code> <code class="o">)</code> <code class="o">{</code>
<code class="n">JFrame</code> <code class="n">frame</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JFrame</code><code class="o">(</code><code class="s">"TrackImage"</code><code class="o">);</code>
<code class="n">Image</code> <code class="n">image</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="na">getImage</code><code class="o">(</code> <code class="n">args</code><code class="o">[</code><code class="mi">0</code><code class="o">]</code> <code class="o">);</code>
<code class="n">StatusImage</code> <code class="n">statusImage</code> <code class="o">=</code> <code class="k">new</code> <code class="n">StatusImage</code><code class="o">(</code> <code class="n">image</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">add</code><code class="o">(</code> <code class="n">statusImage</code> <code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setSize</code><code class="o">(</code><code class="mi">300</code><code class="o">,</code><code class="mi">300</code><code class="o">);</code>
<code class="n">frame</code><code class="o">.</code><code class="na">setVisible</code><code class="o">(</code><code class="kc">true</code><code class="o">);</code>
<code class="n">MediaTracker</code> <code class="n">tracker</code> <code class="o">=</code> <code class="k">new</code> <code class="n">MediaTracker</code><code class="o">(</code> <code class="n">statusImage</code> <code class="o">);</code>
<code class="kt">int</code> <code class="n">MAIN_IMAGE</code> <code class="o">=</code> <code class="mi">0</code><code class="o">;</code>
<code class="n">tracker</code><code class="o">.</code><code class="na">addImage</code><code class="o">(</code> <code class="n">image</code><code class="o">,</code> <code class="n">MAIN_IMAGE</code> <code class="o">);</code>
<code class="k">try</code> <code class="o">{</code>
<code class="n">tracker</code><code class="o">.</code><code class="na">waitForID</code><code class="o">(</code> <code class="n">MAIN_IMAGE</code> <code class="o">);</code> <code class="o">}</code>
<code class="k">catch</code> <code class="o">(</code><code class="n">InterruptedException</code> <code class="n">e</code><code class="o">)</code> <code class="o">{}</code>
<code class="k">if</code> <code class="o">(</code> <code class="n">tracker</code><code class="o">.</code><code class="na">isErrorID</code><code class="o">(</code> <code class="n">MAIN_IMAGE</code> <code class="o">)</code> <code class="o">)</code>
<code class="n">statusImage</code><code class="o">.</code><code class="na">setMessage</code><code class="o">(</code> <code class="s">"Error"</code> <code class="o">);</code>
<code class="k">else</code>
<code class="n">statusImage</code><code class="o">.</code><code class="na">loaded</code><code class="o">();</code>
<code class="o">}</code>
<code class="o">}</code></pre><p>In this example, we created a trivial component called <code class="literal">StatusImage</code> that accepts an image and draws a
text status message until it is told that the image is loaded. It then
displays the image. The only interesting part here is that we use a
<code class="literal">MediaTracker</code> to load the image data
for us, simplifying our logic.</p><p>First, we create a <code class="literal">MediaTracker</code>
to manage the image. The <code class="literal">MediaTracker</code>
constructor takes a <code class="literal">Component</code> as an
argument; this is supposed to be the component onto which the image is
later drawn. This argument is somewhat of a holdover from earlier Java
days with AWT. If you don’t have the component reference handy, you can
simply substitute a generic component reference like so:</p><a id="I_21_tt1179"/><pre class="programlisting"> <code class="n">Component</code> <code class="n">comp</code> <code class="o">=</code> <code class="k">new</code> <code class="n">Component</code><code class="o">();</code></pre><p>After creating the <code class="literal">MediaTracker</code>, we assign it images to manage.
Each image is associated with an integer that identifier we can use
later for checking on its status or to wait for its completion. Multiple
images can be associated with the same identifier, letting us manage
them as a group. The value of the identifier is also meant to prioritize
loading when waiting on multiple sets of images; lower IDs have higher
priority. In this case, we want to manage only a single image, so we
created one identifier called <a id="I_indexterm21_id816039" class="indexterm"/><code class="literal">MAIN_IMAGE</code> and passed
it as the ID for our image in the call to <code class="literal">addImage()</code>.</p><p>Next, we call the <code class="literal">MediaTracker
waitforID()</code> routine, which blocks on the image, waiting for it
to finish loading. If successful, we tell our example component to use
the image and repaint. Another <code class="literal">MediaTracker</code> method, <a id="I_indexterm21_id816070" class="indexterm"/><code class="literal">waitForAll()</code>, waits for
all images to complete, not just a single ID. It’s possible to be
interrupted here by an <code class="literal">Interrupted</code><code class="literal">Exception</code>. We should also test for errors
during image preparation with <a id="I_indexterm21_id816095" class="indexterm"/><code class="literal">isErrorID()</code>. In our
example, we change the status message if we find one.</p><p>The <code class="literal">MediaTracker checkID()</code> and
<a id="I_indexterm21_id816114" class="indexterm"/><code class="literal">checkAll()</code> methods may
be used to poll periodically the status of images loading, returning
<code class="literal">true</code> or <code class="literal">false</code> to indicate whether loading is finished.
The <code class="literal">checkAll()</code> method does this for
the union of all images being loaded. Additionally, the <a id="I_indexterm21_id816142" class="indexterm"/><code class="literal">statusID()</code> and
<a id="I_indexterm21_id816153" class="indexterm"/><code class="literal">statusAll()</code> methods
return a constant indicating the status or final condition of an image
load. The value is one of the <code class="literal">MediaTracker</code> constant values: <a id="I_indexterm21_id816170" class="indexterm"/><code class="literal">LOADING</code>, <a id="I_indexterm21_id816181" class="indexterm"/><code class="literal">ABORTED</code>, <a id="I_indexterm21_id816192" class="indexterm"/><code class="literal">ERROR</code>, or <a id="I_indexterm21_id816202" class="indexterm"/><code class="literal">COMPLETE</code>. For <code class="literal">statusAll()</code>, the value is the bitwise OR value
of all of the various statuses.</p><p>This may seem like a lot of work to go through just to put up a
status message while loading a single image. <code class="literal">MediaTracker</code> is more valuable when you are
working with many raw images that have to be available before you can
begin parts of an application. It saves implementing a custom <code class="literal">ImageObserver</code> for every application. For
general Swing application work, you can use yet another simplification
by employing the <code class="literal">ImageIcon</code> component
to use a <code class="literal">MediaTracker</code>. This is
covered next.<a id="I_indexterm21_id816246" class="indexterm"/><a id="I_indexterm21_id816254" class="indexterm"/><a id="I_indexterm21_id816261" class="indexterm"/></p></div><div class="sect2" title="ImageIcon"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-21-SECT-1.3"/>ImageIcon</h2></div></div></div><p><a id="I_indexterm21_id816274" class="indexterm"/> <a id="I_indexterm21_id816285" class="indexterm"/>In <a class="xref" href="ch17.html" title="Chapter 17. Using Swing Components">Chapter 17</a>, we discussed
Swing components that can work with images using the <code class="literal">Icon</code> interface. In particular, the <a id="I_indexterm21_id816306" class="indexterm"/><code class="literal">ImageIcon</code> class accepts
an image filename or URL and can render it into a component. Internally,
<code class="literal">ImageIcon</code> uses a <code class="literal">MediaTracker</code> to fully load the image in the
call to its constructor. It can also provide the <code class="literal">Image</code> reference back. So, a shortcut to what
we did in the last few sections—getting an image loaded fully before
using it—would be:</p><a id="I_21_tt1180"/><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>This quirky approach saves a few lines of typing, but uses an icon
in an odd way and is not very clear. <code class="literal">ImageIcon</code> also gives you direct access to the
<code class="literal">MediaTracker</code> it’s using through the
<a id="I_indexterm21_id816360" class="indexterm"/><code class="literal">getMediaTracker()</code>
method or tells you the <code class="literal">MediaTracker</code>
load status through the <a id="I_indexterm21_id816377" class="indexterm"/><code class="literal">getImageLoadStatus()</code>
method. This returns one of the <code class="literal">MediaTracker</code> constants: <code class="literal">ABORTED</code>, <code class="literal">ERROR</code>, or <code class="literal">COMPLETE</code>.</p></div><div class="sect2" title="ImageIO"><div class="titlepage"><div><div><h2 class="title"><a id="learnjava3-CHP-21-SECT-1.4"/>ImageIO</h2></div></div></div><p><a id="idx11118" class="indexterm"/> <a id="idx11122" class="indexterm"/> <a id="idx11134" class="indexterm"/>As we mentioned in the introduction to <a class="xref" href="ch01.html" title="Chapter 1. A Modern Language">Chapter 1</a>, the <a id="I_indexterm21_id816460" class="indexterm"/><code class="literal">javax.imageio</code> package
is a standard extension that deals with reading and writing many image
formats. It is a part of the larger Java Advanced Imaging (JAI) API.
This API supports advanced manipulation and display of images. While the
AWT has a relatively fixed set of functionality, JAI is an extensible
framework that accepts plug-ins for new image formats and features. The
<code class="literal">imageio</code> portion of JAI is bundled
with Java 1.4 and later, so we can take advantage of it on all current
Java releases. <code class="literal">ImageIO</code> effectively
supercedes the APIs we’ve talked about here with new ones for loading
and monitoring image data, and although we won’t cover it in detail, we
will discuss it briefly here for several reasons. First, it is fairly
easy to use. Second, <code class="literal">ImageIO</code> natively
works with <code class="literal">BufferedImage</code>s and not
just plain AWT <code class="literal">Image</code>s. As we’ll
discuss throughout the rest of this chapter, buffered images can expose
their pixel data for you to read or manipulate. Finally, using <code class="literal">ImageIO</code> allows you both to load and save
<code class="literal">BufferedImage</code>s to files. The core AWT
has no tools for encoding image data for saving to files.</p><p>Previously, we showed how easy it is to load an image with the
static <code class="literal">read()</code> methods of the <code class="literal">ImageIO</code> class, which accept either a <code class="literal">File</code>, <code class="literal">URL</code>,
or <code class="literal">InputStream</code>:</p><a id="I_21_tt1181"/><pre class="programlisting"> <code class="n">File</code> <code class="n">file</code> <code class="o">=</code> <code class="k">new</code> <code class="n">File</code><code class="o">(</code><code class="s">"/Users/pat/images/boojum.gif"</code><code class="o">);</code>
<code class="n">BufferedImage</code> <code class="n">bi</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">file</code> <code class="o">);</code></pre><p>In this example, we revealed that the type returned is actually a
<code class="literal">BufferedImage</code>, which is a subtype of
<code class="literal">Image</code>. The <code class="literal">ImageIO.read()</code> method, like the AWT <code class="literal">getImage()</code> method, automatically detects the
image type and decodes it properly. Because <code class="literal">ImageIO</code> is extensible, it’s useful to be able
to list the types of images it can decode. You get this information with
the <code class="literal">ImageIO.getReaderFormatNames()</code>
method, which returns an array of strings corresponding roughly to file
extensions for the image types it understands. (<code class="literal">ImageIO</code> does not rely on file extensions to
detect image types; rather, it looks at the content of the file.)</p><p>Images loaded by the <code class="literal">ImageIO.read()</code> methods are fully loaded before
they are returned, so the method blocks until they are done. If you want
more fine-grained information on the progress of image loading, you can
use the <a id="I_indexterm21_id816616" class="indexterm"/><code class="literal">IIOReadProgressListener</code>
interface of the <code class="literal">javax.imageio.event</code>
package, which roughly corresponds to the AWT <code class="literal">ImageObserver</code>. To use it, you must delve a
little deeper into the ImageIO API by first looking up an appropriate
<a id="I_indexterm21_id816639" class="indexterm"/><code class="literal">ImageReader</code> object with
which to register the listener:</p><a id="I_21_tt1182"/><pre class="programlisting"> <code class="kn">import</code> <code class="nn">javax.imageio.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.imageio.stream.*</code><code class="o">;</code>
<code class="kn">import</code> <code class="nn">javax.imageio.event.*</code><code class="o">;</code>
<code class="err"> </code>
<code class="n">File</code> <code class="n">file</code> <code class="o">=</code> <code class="k">new</code> <code class="n">File</code><code class="o">(</code><code class="s">"image.jpg"</code><code class="o">);</code>
<code class="n">ImageInputStream</code> <code class="n">iis</code> <code class="o">=</code> <code class="n">ImageIO</code><code class="o">.</code><code class="na">createImageInputStream</code><code class="o">(</code> <code class="n">file</code> <code class="o">);</code>
<code class="err"> </code>
<code class="n">Iterator</code> <code class="n">readers</code> <code class="o">=</code> <code class="n">ImageIO</code><code class="o">.</code><code class="na">getImageReaders</code><code class="o">(</code> <code class="n">iis</code> <code class="o">);</code>
<code class="n">ImageReader</code> <code class="n">reader</code> <code class="o">=</code> <code class="o">(</code><code class="n">ImageReader</code><code class="o">)</code><code class="n">readers</code><code class="o">.</code><code class="na">next</code><code class="o">();</code> <code class="c1">// choose first one</code>
<code class="err"> </code>
<code class="n">reader</code><code class="o">.</code><code class="na">addIIOReadProgressListener</code><code class="o">(</code> <code class="n">readProgressListener</code> <code class="o">);</code>
<code class="n">reader</code><code class="o">.</code><code class="na">setInput</code><code class="o">(</code> <code class="n">iis</code><code class="o">,</code> <code class="kc">true</code> <code class="o">);</code>
<code class="n">BufferedImage</code> <code class="n">bi</code> <code class="o">=</code> <code class="n">reader</code><code class="o">.</code><code class="na">read</code><code class="o">(</code> <code class="mi">0</code><code class="cm">/*index*/</code> <code class="o">);</code></pre><p>This code is fairly straightforward. The <code class="literal">ReadProgressListener</code> is used like any of the
AWT or Swing event interfaces we’ve seen before. You can refer to the
Javadoc for the exact methods you must implement.</p><p>Finally, in addition to the progress listener, two other listener
APIs, <a id="I_indexterm21_id816679" class="indexterm"/><code class="literal">IIOReadUpdateListener</code>
and <a id="I_indexterm21_id816690" class="indexterm"/><code class="literal">IIOReadWarningListener</code>,
offer information on pixel changes (e.g., for progressive loading) and
loading errors. There are also, of course, “write” versions of all of
these tools that handle the flip side, saving image data. We’ll return
to that topic later in this chapter.<a id="I_indexterm21_id816706" class="indexterm"/><a id="I_indexterm21_id816713" class="indexterm"/><a id="I_indexterm21_id816720" class="indexterm"/></p></div></div></body></html>