UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

272 lines (263 loc) 37.7 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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">&amp;</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>