Return-Path: <env_170147211578454271@hermes.sun.com>
Received: from pacific-carrier-annex.mit.edu by po10.mit.edu (8.9.2/4.7) id TAA20881; Tue, 18 Jun 2002 19:08:34 -0400 (EDT)
Received: from hermes.sun.com (hermes.sun.com [64.124.140.169])
	by pacific-carrier-annex.mit.edu (8.9.2/8.9.2) with SMTP id TAA14815
	for <alexp@mit.edu>; Tue, 18 Jun 2002 19:08:33 -0400 (EDT)
Date: Tue, 18 Jun 2002 12:57:03 GMT-08:00
From: "JDC Tech Tips" <body_170147211578454271@hermes.sun.com>
To: alexp@mit.edu
Message-Id: <170147211578454271@hermes.sun.com>
Subject: JDC Tech Tips, June 18, 2002 (Reading From Output Streams, Blending Images)
Mime-Version: 1.0
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Mailer: SunMail 1.0

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>
Technical Tips
</TITLE>
</HEAD>

<body bgcolor="#ffffff">
<a name="top"></a>
<table border="0" cellpadding="0" cellspacing="0" width="640">
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>

<tr>
<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>

<td>
<table border="0" cellpadding="0" cellspacing="0" width="640">
<tr>
<td colspan="2">
<img src="http://developer.java.sun.com/images/jdc_techtips_header.gif" width="640" alt="" border="0"></td>
</tr>

<tr>
<td colspan="2" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>

<!-- ================== -->
<!-- Start Main Content -->
<!-- ================== -->

<tr bgcolor="#59588d">
<td height="20">&nbsp;&nbsp;&nbsp;<a href="http://developer.java.sun.com/developer/TechTips/txtarchive/2002/June02_GlenM.txt?s=06&w=23" style="text-decoration:none;"><font face="Verdana" size="2" color="ffffff">View this issue as simple text</font></a></td>
<td align="right" height="20"><font face="Verdana" size="2" color="ffffff"><b>June 18, 2002</b></font>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>
</tr>
<tr>
<td colspan="2" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>

<tr><td colspan="2">

<table border="0" cellpadding="10" cellspacing="0" width="640">
<tr><td>

<FORM METHOD="GET" ACTION="http://search.java.sun.com/search/java/?s=06&w=23">
<table BORDER="0" CELLPADDING="0" CELLSPACING="0" WIDTH="100%">
<tr>
<td>
        
<table BORDER="0" CELLPADDING="0" CELLSPACING="0">
<TR> 
<td  align="left" VALIGN="middle"><img src="http://developer.java.sun.com/images/issue.gif" border="0" alt=""></td>
              
<td VALIGN="middle" align="right" WIDTH="100%">
<FONT SIZE="2">
<INPUT TYPE="text" SIZE="15" MAXLENGTH="128" NAME=qt></FONT></td>
            
<td VALIGN="middle" WIDTH="55" align="right">
<INPUT TYPE="image" SRC="http://developer.java.sun.com/images/search.button.gif" ALT="Search" value="search" BORDER="0" WIDTH="55"></td>
</tr>
</table>
</td></tr>
</table>
</FORM>

<p>
<a href="#1"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt=""><font face="Verdana" size="2" color="#666699">Reading from Output Streams</font></a>
<br>    
<a href="#2"><img src="http://developer.java.sun.com/images/anchor.gif" border="0" alt=""><font face="Verdana" size="2" color="#666699">Blending Images</font></a>
</p>

<p>
<font face="Verdana" size="2" color="#000000">These tips were developed using java<font size="-2"><sup>TM</sup></font> 2 SDK, Standard Edition, v 1.4.</font>
</p>

<p>
<font face="Verdana" size="2" color="#000000">This issue of the JDC Tech Tips is written by John Zukowski, 
president of <a href="http://www.jzventures.com">JZ Ventures, Inc</a>.</font>
</p>

<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="1"></a>
<p>
<font face="Verdana" size="2" color="#000000"><b>Reading from Output Streams</b></font>
</p>

<p>
<font face="Verdana" size="2" color="#000000">
I/O stands for input and output. It represents how programs 
interact with the outside world. You read input and you write
output. In the Java<sup><font size="-2">TM</font></sup> platform, I/O relies on a streams-based model. This model allows you to read from files, network 
connections, or consoles in the same way. You don't have to 
change your code based on the type of input device. Similarly, 
for output you don't have to change your code for each type of 
output device.
</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
The streams-based model works well when you want to read from 
an input stream or write to an output stream. However, there are 
added considerations when you need to get data that was written 
to an output stream, or put data into an input stream to be read. 
This tip examines some of these considerations.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
Input streams are for reading. A program opens an input stream 
for reading information from a source. Output streams are for 
writing. To write to a destination, a program opens an output 
stream to that destination, and then writes to that output stream.
</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
The <code>java.io</code> package contains a variety of stream classes for
reading from and writing to a stream. These classes are broadly 
divided into two categories: character streams and byte streams. 
Character stream classes are for reading and writing character 
data. Byte stream classes are for reading and writing binary 
data (that is, bytes). <code>Reader</code> and <code>Writer</code> are abstract
superclasses for character streams. <code>InputStream</code> and <code>OutStream</code> are abstract superclasses for byte streams. Subclasses of
these superclasses implement streams for specific sources and
destinations.
</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
A question that is sometimes asked is how do you read what was 
just written to a stream? For example, suppose you write to an 
output stream. To do this, you pass to some library method an 
<code>OutputStream</code> or <code>Writer</code>. How do you then read what you just wrote from the <code>OutputStream</code> or <code>Writer</code>?
</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
One way to read what you wrote is to pass to the library method 
one of the file-related output streams: <code>FileOutputStream</code> or 
<code>FileWriter</code>. This allows you to reread what you wrote to the file 
system. Here's an example:
</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  import java.io.*;

  public class FileRead {
    public static void main(String args[]) 
        throws IOException {
      // Get temp output file
      File file = File.createTempFile(
        "zuk", ".tmp");
      // Remove when program ends
      file.deleteOnExit();
      // Create output stream for file
      Writer writer = new FileWriter(file);
      // Send data to output
      save(writer);
      // Close output
      writer.close();
      // Open output as input
      Reader reader = new FileReader(file);
      BufferedReader bufferedReader = 
        new BufferedReader(reader);
      // Read input
      String line;
      while ((line = bufferedReader.readLine()) 
          != null) {
        System.out.println(line);
      }
      bufferedReader.close();
    }
    private static void save(Writer generic) 
        throws IOException {
      PrintWriter out = new PrintWriter(generic);
      out.println("Line One");
      out.println("Line Two");
    }
  } 
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
The <code>FileRead</code> program creates a file-related output stream (a
<code>FileWriter</code>), writes two lines of output to the stream, opens the
output as an input stream, and then reads from the input
stream. The program should display the reread lines:
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  Line One
  Line Two
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
This approach is especially appropriate if the output is larger 
than available memory. That's because you will have to save the 
output to an external source anyway.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
In cases where the intermediate information is relatively small, 
you can use memory-based stream classes. Memory-based stream
classes read from and write to memory (as opposed to streams
such as <code>FileWriter</code> which are used to read from an external 
source). You can have the library send intermediate information 
to the appropriate memory-based stream class: for output, that 
would be either <code>ByteArrayOutputStream</code> or <code>StringWriter</code>. Then, to 
read the in-memory information, you can convert it to a
memory-based input stream: <code>ByteArrayInputStream</code> or <code>StringReader</code>.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
The output streams, <code>ByteArrayOutputStream</code> and <code>StringWriter</code>, rely 
on an internal byte array and <code>StringBuffer</code> to store the 
intermediate information. At input time, the <code>ByteArrayInputStream</code> 
and <code>StringReader</code> work with a byte array and <code>String</code> for input. 
That means that when you need to change from output to input 
mode, you get the current contents of the output destination to 
create an input source.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
In the case of the byte-based streams, the <code>ByteArrayOutputStream</code>
and <code>ByteArrayInputStream</code> work together. When you finish writing, 
you get the bytes with the <code>toByteArray()</code> method. Passing the
bytes to the <code>ByteArrayInputStream</code> provides the input stream:</font>
</p>


<font face="Verdana" size="2" color="#000000">
<pre>
  // Create output stream
  ByteArrayOutputStream outputStream = 
    new ByteArrayOutputStream(initialSize);
  // Write to stream
  ...
  // When done, get bytes
  byte bytes[] = outputStream.toByteArray();
  // Create intput stream
  ByteArrayInputStream inputStream = 
    new ByteArrayInputStream(bytes);
  // Read from stream
  ... 
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
There are some things to consider when you use 
<code>ByteArrayOutputStream</code>. First, it helps if you can estimate the
size of the output. If you don't provide an initial size, the 
byte array starts at 32 bytes and increases by a factor of two 
each time the internal buffer fills up (the growth is even faster 
if you write an array instead of a character). If you know you're 
going to have at least 2000 characters, start at that size and 
avoid the resizings at 64, 128, 256, 512, and 1024, just to get 
to 2048 characters. Another consideration is that the 
<code>toByteArray()</code> method doesn't return a reference to the internal 
byte array. Instead, it returns a copy. This can be both a good 
or bad thing. While copying does prevent the buffer from changing, 
(or you changing the buffer), it does mean that there are two sets 
of data, requiring twice as much memory.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
For character-based streams, there are <code>StringWriter</code> and 
<code>StringReader</code>. <code>StringWriter</code> uses an internal <code>StringBuffer</code> for 
managing the characters read. The code to use for 
character-based streams is similar to the code for byte-array 
streams:</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  // Create output stream
  StringWriter writer = 
    new StringWriter(initialSize);
  // Write to stream
  ...
  // When done, get characters
  String string = writer.toString();
  // Create intput stream
  StringReader reader = 
    new StringReader(string);
  // Read from stream
  ... 
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
<code>StringWriter</code> uses a character array for the internal storage. 
The character array is in a <code>StringBuffer</code>. As the array fills up, 
it increases in size with the same doubling effect as described 
previously for <code>ByteArrayOutputStream</code>. If you don't provide an 
initial size, the <code>StringBuffer</code> array starts at only an initial 
size of 16. As always, try to size the array to a more realistic 
initial size. Note that it's possible to get the contents of the 
<code>StringBuffer</code> used by the <code>StringWriter</code> without allocating more memory. For more information about this, see the documentation of the <a href="http://java.sun.com/j2se/1.4/docs/api/java/lang/StringBuffer.html#toString()?s=06&w=25"><code>toString</code> method of <code>StringBuffer</code></a>.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
Using the <code>StringWriter</code>-<code>StringReader</code> pair, you can now change the earlier example to keep all accesses in memory:</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  import java.io.*;

  public class MemRead {
    public static void main(String args[]) 
        throws IOException {
      // Create memory output stream 
      StringWriter writer = 
        new StringWriter(128);
      // Send data to output
      save(writer);
      // Close output
      writer.close();
      // Open output as input
      Reader reader = 
        new StringReader(writer.toString());
      BufferedReader bufferedReader = 
        new BufferedReader(reader);
      // Read input
      String line;
      while ((line = bufferedReader.readLine()) 
          != null) {
        System.out.println(line);
      }
      bufferedReader.close();
    }
    private static void save(Writer generic) 
        throws IOException {
      PrintWriter out = new PrintWriter(generic);
      out.println("Line One");
      out.println("Line Two");
    }
  } 
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
There's at least one other way to read from an output stream. 
This approach uses filters. Both the byte and character-based 
streaming classes provide for the installation of filters into 
the I/O streams. While keeping the basic reading and writing 
operations the same, filters enhance streams by adding 
capabilities. The <code>BufferedReader</code> class used in the previous
examples is an example of a filter. It maintains input from 
the source in an internal buffer and feeds the characters to the 
reader as requested. Instead of having to go to the input source 
for each request, the <code>BufferedReader</code> fetches input in bulk, 
usually for quicker performance. Because the <code>MemRead</code> program uses
an in-memory buffer, there is no real performance difference. For 
the <code>FileRead</code> program, there is a performance difference, albeit 
minimal for input this small.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
Filters typically fit into the processing sequence as follows:
you pass in the original source or destination to a constructor, 
then the filter performs its processing before (or after) passing 
the bytes or characters to the original source or destination. 
Filters subclass either an existing class or one of the filtering 
stream. The filtering stream classes depend on the type of data 
to be filtered: <code>FilterInputStream</code>, <code>FilterOutputStream</code>, <code>FilterReader</code>, or <code>FilterWriter</code>.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
You use filters in a program in the same way as shown earlier for 
<code>BufferedReader</code> earlier, that is:</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  SourceStream source = new SourceStream(...);
  AFilterStream filter = new AFilterStream(source);
  // use filter
  ...
  // close filter, not source
  filter.close(); 
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
Here's a program that uses a filter to count characters, numbers,
and white space. When the filter is closed, it writes the counts 
to the stream sent to the constructor:</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  import java.io.*;

  public class CountWriter 
      extends FilterWriter {

    PrintStream out;
    int chars, nums, whites;

    public CountWriter(Writer destination, 
        PrintStream out) {
      super(destination);
      this.out = out;
    }

  public void write(int c) 
      throws IOException {
    super.write(c);
    check((char)c);
  }

  public void write(char cbuf[], int off, 
      int len) throws IOException {
    super.write(cbuf, off, len);
    for (int i=off; i&lt;len; i++) {
      check(cbuf[i]);
    }
  }

  public void write(String str, int off, 
      int len) throws IOException {
    super.write(str, off, len);
    for (int i=off; i&lt;len; i++) {
      check(str.charAt(i));
    }
  }

  private void check(char ch) {
    if (Character.isLetter(ch)) {
      chars++;
    } else if (Character.isDigit(ch)) {
      nums++;
    } else if (Character.isWhitespace(ch)) {
      whites++;
    }
  }

  public void close() {
    out.println("Chars:      " + chars);
    out.println("Nums:       " + nums);
    out.println("Whitespace: " + whites);
  }
}
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
Let's update the earlier <code>MemRead</code> program to use the filter.
Notice that you don't need to reread the data to produce the 
necessary output:</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  import java.io.*;

  public class MemRead2 {
    public static void main(String args[]) 
        throws IOException {
      // Create memory output stream 
      StringWriter writer = 
        new StringWriter(128);
      CountWriter counter = 
        new CountWriter(writer, System.err);
      // Send data to output
      save(counter);
      // Close output
      counter.close();
    }
    private static void save(Writer generic) 
        throws IOException {
      PrintWriter out = new PrintWriter(generic);
      out.println("Line One");
      out.println("Line Two");
    }
  } 
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
When you run the program, you should see the following output:
</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  Chars:      14
  Nums:       0
  Whitespace: 4 
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
That's really all there is to reading from output streams. You can
either take the brute force approach of reading the completely
written output, or intercept the output as it is being written to
perform your own read operation.
</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
The New I/O libraries of Java 1.4 provide additional mechanisms 
to create read-write buffers. See the article "<a href="http://java.sun.com/jdc/technicalArticles/releases/nio/?s=06&w=25">New I/0 
Functionality for Java 2 Standard Edition 1.4</a>" for
information on working with the newer buffering capabilities.
</font>
</p>


<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<div align="right">
<a href="#top"><font face="Verdana" size="2" color="#666699">back to top</font><img src="http://developer.java.sun.com/images/back_to_top.gif" border="0" alt=""></a>
</div>
</td></tr>

<tr><td bgcolor="#ffffff" height="2"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td></tr>

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<a name="2"></a>
<p>
<font face="Verdana" size="3"><b>Blending Images</b></font>
</p>

<p>
<font face="Verdana" size="2" color="#000000">
The Java 2D<sup><font size="-2">TM</font></sup> API provides support for the blending of multiple 
drawn images through what are known as Porter-Duff rules. 
Originally described by a SIGGRAPH paper from 1984, <a href="http://www.keithp.com/~keithp/porterduff/">Compositing 
Digital Images</a>, by Thomas Porter and Tom Duff, the rules describe 
how to combine the contents of multiple images when one image is 
drawn on top of the other.</font>
</p>

<p>
<font face="Verdana" size="2" color="#000000">
There are twelve such rules. These include rules such as &quot;draw 
only the source image&quot; and &quot;draw the part of the destination 
image that doesn't overlap the source.&quot; At first glance, some of 
these rules might seem complex. However they aren't as complex as 
they seem. If you see a picture, things get much clearer.</font>
</p>

<p>
<font face="Verdana" size="2" color="#000000">
Within the Java 2D API, the blending rules are supported by the 
<code>AlphaComposite</code> class. The class provides twelve constants, one 
for each rule. To change the setting, you pass the specific 
constant to the <code>setComposite</code> method of the <code>Graphics2D</code> class. Then, when an image is drawn, the rule associated with the 
constant is used to describe how the new image is blended with 
the existing content. The Java 2D API supports <code>AlphaComposite</code>
objects with transparency percentages. If you want to slowly blend 
one image into another, you can alter the percentages such that 
more of the new image can appear or disappear based on the 
blending rule used.</font>
</p>

<p>
<font face="Verdana" size="2" color="#000000">
Here are the twelve constants and their associated rules:
</font>
</p>

<table border="0" cellpadding="8">
<tr>
<td><font face="Verdana" size="2" color="#000000">CLEAR</font></td><td>Draw nothing. Creates empty output.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">DST</font></td><td>Draw only the destination image.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">SRC</font></td><td>Draw only the source image.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">DST_ATOP</font></td><td>Draw the source image. Where the two images overlap,
           draw the destination image.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">SRC_ATOP</font></td><td>Draw the destination image. Where the two images 
           overlap, draw the source image.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">DST_IN</font></td><td>Draw the part of the destination image that overlaps 
           the source.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">SRC_IN</font></td><td>Draw the part of the source image that overlaps the 
           destination.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">DST_OUT</font></td><td>Draw the part of the destination image that doesn't 
           overlap the source.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">SRC_OUT</font></td><td>Draw the part of the source image that doesn't overlap 
           the destination.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">DST_OVER</font></td><td>Draw the destination image over the source image.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">SRC_OVER</font></td><td>Draw the source image over the destination image.</td>
</tr>
<tr>
<td><font face="Verdana" size="2" color="#000000">XOR</font></td><td>Draw the part of the destination and source images that 
           don't overlap.</td>
</tr>
</table>


<p>
<font face="Verdana" size="2" color="#000000">
To help you visualize the twelve rules, this tip uses a program
that blends images. The program comes from the book Mastering 
Java 2, J2SE 1.4 by John Zukowski, published by <a href="http://www.sybex.com/">Sybex</a>. 
The program produces a screen using all 
twelve rules. In the program, each rule is used with three 
different percentages for transparency settings of the source and
destination images. The source image is a green triangle on the 
left. The destination image is a magenta triangle on the right. 
The two triangles overlap in the middle.</font>
</p>


<p>
<font face="Verdana" size="2" color="#000000">
In the screen for the program are two sets of drawings. The first 
set on top uses the composite settings of <code>CLEAR</code>, <code>DST</code>, <code>DST_ATOP</code>, 
<code>DST_IN</code>, <code>DST_OUT</code>, and <code>DST_OVER</code>. The bottom set uses <code>SRC</code>, <code>SRC_ATOP</code>, 
<code>SRC_IN</code>, <code>SRC_OUT</code>, <code>SRC_OVER</code>, and <code>XOR</code>.
</p>


<p>
<font face="Verdana" size="2" color="#000000">
The program is only meant to show the different rules. How to 
actually blend images will be explained shortly.
</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  import java.awt.*;
  import java.awt.geom.*;
  import java.awt.image.*;
  import javax.swing.*;
  
  public class CompositeIt extends JFrame {
    int rules[] = {
      AlphaComposite.CLEAR,    
      AlphaComposite.DST, 
      AlphaComposite.DST_ATOP, 
      AlphaComposite.DST_IN, 
      AlphaComposite.DST_OUT,  
      AlphaComposite.DST_OVER, 
      AlphaComposite.SRC,      
      AlphaComposite.SRC_ATOP, 
      AlphaComposite.SRC_IN,   
      AlphaComposite.SRC_OUT, 
      AlphaComposite.SRC_OVER, 
      AlphaComposite.XOR};
    float percents[] = {.33f, .67f, 1.0f};
    BufferedImage source, dest;
    GeneralPath sourcePath, destPath;
  
    public CompositeIt() {
      sourcePath = new GeneralPath();  
      sourcePath.moveTo(0,   0);   
      sourcePath.lineTo(50, 0);
      sourcePath.lineTo(50, 25);   
      sourcePath.closePath();
      source = new BufferedImage(80, 30, 
        BufferedImage.TYPE_INT_ARGB);
      destPath = new GeneralPath();
      destPath.moveTo(25,  0);    
      destPath.lineTo(75, 0);
      destPath.lineTo(25, 25);    
      destPath.closePath();
      dest = new BufferedImage(80, 30, 
        BufferedImage.TYPE_INT_ARGB);
    }
  
    public void paint(Graphics g) {
      Graphics2D g2d = (Graphics2D)g;
      Graphics2D sourceG = 
        source.createGraphics();
      Graphics2D destG = 
        dest.createGraphics();
      AffineTransform at = 
        new AffineTransform();
      Composite originalComposite = 
        g2d.getComposite();
      for(int i=0; i&lt;3; i++) {
        for(int j=0, n=rules.length; j&lt;n; 
            j++) {
          at = AffineTransform.
            getTranslateInstance(j*80+10, 
            i*30+30);
          if (j &gt;= rules.length/2) {
            at.translate(-rules.length/2*80, 
              120);
          }
          g2d.setTransform(at);
          g.drawRect(0, 0, 80, 30);
          destG.setComposite(
            AlphaComposite.Clear);
          destG.fillRect(0, 0, 80, 30);
          destG.setComposite(
            AlphaComposite.getInstance(
              AlphaComposite.XOR, percents[i]));
          destG.setPaint(Color.MAGENTA);
          destG.fill(destPath);
          sourceG.setComposite(
            AlphaComposite.Clear);
          sourceG.fillRect(0, 0, 80, 30);
          sourceG.setComposite(
            AlphaComposite.getInstance(
              AlphaComposite.XOR, percents[i]));
          sourceG.setPaint(Color.GREEN);
          sourceG.fill(sourcePath);
          destG.setComposite(
            AlphaComposite.getInstance(rules[j]));
          destG.drawImage(source, 0, 0, null);
          g2d.drawImage(dest, 0, 0, this);
        }
      }
    }
  
    public static void main(String args[]) {
      JFrame f = new CompositeIt();
      f.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      f.setTitle("CompositeIt");
      f.setSize(525, 275);
      f.show();
    }
  }
</pre>
</font>

<p>
<font face="Verdana" size="2" color="#000000">
Here's the blended image the program displays:
</p>

<img src="http://developer.java.sun.com/images/tt0618_compositeit.gif" width="525" height="275" alt="CompositeIt">

<p><font face="Verdana" size="2" color="#000000">
You can combine the images in memory, as opposed to using the
current Graphics context for the screen. Using a <code>BufferedImage</code>
object for double buffering, you draw the one image to the 
buffer. Then you draw the second image on the first using the 
desired rule. Finally, you draw the combined image to the screen. 
Here's the approach:</font>
</p>

<font face="Verdana" size="2" color="#000000">
<pre>
  // Create in-memory image buffer
  BufferedImage dest = new BufferedImage(
  width, height,
  BufferedImage.TYPE_INT_ARGB);

  // Get the Graphics Context
  Graphics2D destG = dest.createGraphics();

  // Draw first image on it
  destG.drawImage(image1, 0, 0, this);
 
  // Combine them
  destG.setComposite(mode);
  destG.drawImage(source, 0, 0, this);

  // Draw image on screen
  g2d.drawImage(dest, 0, 0, this);
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
There is more to these capabilities though. The example didn't show how to blend images. More specifically, you haven't seen how to have one image fade, such that a second image is progressively favored. With properly sized images, you can watch as a baby picture morphs into an adult, or a puppy into a full grown dog.</font></p>

<p><font face="Verdana" size="2" color="#000000">
To have images fade, it becomes necessary to draw the source and
destination images with varying transparency percentages. The
<code>AlphaComposite</code> class provides a <code>getInstance</code> method that allows you to provide a Porter-Duff rule, and to specify a transparency
percentage for a drawing operation. By having that drawing 
operation be the initial drawing of the image, you effectively 
make the image transparent to varying degrees. Then, when the two 
images are drawn, one on top of the other, you can get a fading 
effect by altering the degree of transparency.</font>
</p>

<p><font face="Verdana" size="2" color="#000000">
The following program demonstrates this capability by fading the
image of a stage coach:</font>
</p>

<img src="http://developer.java.sun.com/images/tt0618_oldstage.gif" width="222" height="168" alt="stage coach">

<p><font face="Verdana" size="2" color="#000000">
into that of a saloon:</font>
</p>

<img src="http://developer.java.sun.com/images/tt0618_saloon.gif" width="198" height="135" alt="saloon">

<p><font face="Verdana" size="2" color="#000000">
You can grab the 
images from the <a href="http://www.cowboyclipart.com/graphics/oldwest.asp">Cowboy Clip Art site</a> or you can provide your own images. The saloon image is <code>saloon.gif</code>, the
stagecoach image is <code>oldstage.gif</code>. The program uses a <code>TimerTask</code> 
and <code>Timer</code> to loop through a fixed set of steps between images. 
Feel free to adjust the <code>STEPS</code> setting to alter this counter, or 
the <code>SLEEP_DELAY</code> setting to change the speed of the changes. 
A higher <code>STEPS</code> setting means there are more intermediate steps 
between images. A higher <code>SLEEP_DELAY</code> setting makes the time 
between each step longer.</font>
</p>


<font face="Verdana" size="2" color="#000000">
<pre>
  import java.awt.*;
  import java.awt.image.*;
  import javax.swing.*;
  import java.util.Timer;
  import java.util.TimerTask;
  
  public class Converge extends JFrame {
  
    ImageIcon saloonIcon = 
      new ImageIcon("saloon.gif");
    ImageIcon coachIcon = 
      new ImageIcon("oldstage.gif");
    Image saloon = saloonIcon.getImage();
    Image coach = coachIcon.getImage();
  
    BufferedImage dest;
  
    float sourcePercentage = 1, 
      destinationPercentage = 0;
    private static int STEPS = 100;
    private static float STEP_CHANGE = 
      1.0f/STEPS;
    private static int SLEEP_DELAY = 100;
  
    Insets insets;
  
    public Converge() {
      super("Image Blending");
      setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
      dest = new BufferedImage(200, 200, 
        BufferedImage.TYPE_INT_ARGB);
      setSize(200, 200);
      TimerTask task = new TimerTask() {
        public void run() {
          repaint();
          sourcePercentage -= STEP_CHANGE;
          destinationPercentage += 
            STEP_CHANGE;
          if (sourcePercentage &lt; 0) {
            sourcePercentage = 0;
            destinationPercentage = 1;
            cancel();
          }
        }
      };
      Timer timer = new Timer();
      timer.schedule(task, 0, SLEEP_DELAY);
    }
  
    public void paint(Graphics g) {
      if (insets == null) {
        insets = getInsets();
      }
      g.translate(insets.left, insets.top);
      Graphics2D g2d = (Graphics2D)g;
      Graphics2D destG = dest.createGraphics();

      destG.setComposite(AlphaComposite.getInstance(
        AlphaComposite.SRC, sourcePercentage));
      destG.drawImage(coach, 0, 0, this);
      destG.setComposite(AlphaComposite.getInstance(
        AlphaComposite.XOR, destinationPercentage));
      destG.drawImage(saloon, 0, 0, this);
      g2d.drawImage(dest, 0, 0, this);
    }
   
    public static void main(String args[]) {
      new Converge().show();
    }
  }
</pre>
</font>

<p><font face="Verdana" size="2" color="#000000">
Here's a snapshot of the blended image the 
program displays:
</font>
</p>

<img src="http://developer.java.sun.com/images/tt0618_blend.gif" with="200" height="200" alt="Image Blending">

<p><font face="Verdana" size="2" color="#000000">
The Java 1.4 platform includes a number of graphics improvements
related to the Java 2D API. For a description of these 
improvements see the article "<a href="http://java.sun.com/products/java-media/2D/perf_graphics.html?s=06&w=25">Graphics Performance Improvements in the Java 2 SDK, version 1.4</a>".
Also see the presentation "<a href="http://servlet.java.sun.com/javaone/sf2002/conf/sessions/display-2248.en.jsp?s=06&w=25">Translucency, Alpha Compositing and 
Animation: Taking Advantage of Java 2D Technology in Your Rich 
Client Application</a>".
</font>
</p>


<table width="100%" border="0" cellspacing="0" cellpadding="0" align="center">
<tr>
<td>
<div align="right">
<a href="#top"><font face="Verdana" size="2" color="#666699">back to top</font><img src="http://developer.java.sun.com/images/back_to_top.gif" border="0" alt=""></a>
</div>
</td></tr>

<tr><td bgcolor="#ffffff" height="2"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td></tr>

<!-- Grey Horizontal Line Begins Here -->

<tr>
<td bgcolor="#cccccc" height="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" ALT="Pixel" border="0"></td>
</tr>
</table> 

<!-- Grey Horizontal Line ends Here -->

<p>
<font face="Verdana" color="#999999" size="2">IMPORTANT: Please read our Terms of Use, Privacy, and Licensing
policies:</font><br>
<a href="http://www.sun.com/share/text/termsofuse.html?s=06&w=25"><font face="Verdana" size="2" color="#666699">http://www.sun.com/share/text/termsofuse.html</font></a><br>
<a href="http://www.sun.com/privacy/?s=06&w=25"><font face="Verdana" size="2" color="#666699">http://www.sun.com/privacy/</font></a><br>
<a href="http://developer.java.sun.com/berkeley_license.html?s=06&w=25"><font face="Verdana" size="2" color="#666699">http://developer.java.sun.com/berkeley_license.html</font></a>
</p>

<P>
<font face="Verdana" color="#999999" size="2">Comments? Send your feedback on the Java<font size="-2"><sup>TM</sup></font> Developer Technical Tips to: <a href="mailto:jdc-webmaster@sun.com"><font face="Verdana" size="2" color="#666699">jdc-webmaster@sun.com</font></a></font>
</P>

<P>
<font face="Verdana" color="#999999" size="2">Go to the <a href="http://developer.java.sun.com/subscription/?s=06&w=23"><font face="Verdana" size="2" color="#666699">subscriptions page</font></a> to subscribe or unsubscribe to this newsletter.</font>
</P>

<p>
<font face="Verdana" color="#999999" size="2">ARCHIVES: You'll find the Java Developer Connection Technical Tips archives at:</font><br>
<a href="http://developer.java.sun.com/developer/JDCTechTips/?s=06&w=23"><font face="Verdana" size="2" color="#666699">http://developer.java.sun.com/developer/JDCTechTips/</font></a>
</p>

<P>
<font face="Verdana" color="#999999" size="2">Copyright 2002 <a href="http://www.sun.com?s=06&w=23"><font face="Verdana" size="2" color="#666699">Sun Microsystems, Inc.</font></a> All rights reserved. 901 San Antonio Road, Palo Alto, California 94303 USA.</font>
</P>


<P>
<font face="Verdana" color="#999999" size="2">Sun, Sun Microsystems, Java, Java Developer Connection, and Java 2D are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.</font>
</P>

<!-- ================ -->
<!-- End Main Content -->
<!-- ================ -->

<center>
<a href="http://www.sun.com?s=06&w=23"><img src="http://developer.java.sun.com/images/lgsun.gif" border="0" alt="Sun Microsystems, Inc."></a>
</center>

</td>
</tr>
</table>

</td></tr>
</table>
</td>

<td bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
<tr>
<td colspan="3" bgcolor="#cccccc" width="1"><img src="http://developer.java.sun.com/images/pixel.gif" width="1" height="1" border="0" alt=""></td>
</tr>
</table>

<table bgcolor = "#efefef"><tr><td><a href="http://bulkmail.sun.com/servlet/PreferenceServlet?action=change&pref_name=content-type&pref_value=text&id=170147211578454271">Please send me newsletters in text.</a><br><a href="http://bulkmail.sun.com/unsubscribe?170147211578454271">Please unsubscribe me from this newsletter.</a><img src="http://bulkmail2.sun.com/OTServlet?id=170147211578454271" width=1 height=1></td></tr></table></body>
</html>		

