You are on page 1of 11

Core Java Technologies Tech Tips

Tips, Techniques, and Sample Code


Welcome to the Core Java Technologies Tech Tips for
June 1, 2005. Here you'll get tips on using core Java
technologies and APIs, such as those in Java 2 Platform,
Standard Edition (J2SE).
This issue covers:
* Introduction to Java Advanced Imaging
* Calendar Utilities in JDesktop Network Components
These tips were developed using the Java 2 Platform Standard
Edition Development Kit 5.0 (JDK 5.0). You can download JDK 5.0
at http://java.sun.com/j2se/1.5.0/download.jsp.
This issue of the Core Java Technologies Tech Tips is written by
Daniel H. Steinberg, Director of Java Offerings for Dim Sum
Thinking, Inc, and editor-in-chief for java.net (http://java.net).
You can view this issue of the Tech Tips on the Web at
http://java.sun.com/developer/JDCTechTips/2005/tt0601.html.
See the Subscribe/Unsubscribe note at the end of this newsletter
to subscribe to Tech Tips that focus on technologies and products
in other Java platforms.
For more Java technology content, visit these sites:
java.sun.com - The Java technology source for developers. Get the
latest Java platform releases, tutorials, newsletters and more.
java.net - A web forum where enthusiasts of Java technology can
collaborate and build solutions together.
java.com - The ultimate marketplace promoting Java technology,
applications and services.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - INTRODUCTION TO JAVA ADVANCED IMAGING
The Java Advanced Imaging (JAI) API
(http://java.sun.com/products/java-media/jai/index.jsp) was
added to the Java platform to give Java developers high
performance image processing capabilities. The API provides
a rich set of capabilities, and you might at first feel a bit
overwhelmed. This tip should help you get started with three
basic activities using the API. You can then easily extend these
to perform more complex actions. In this tip you will load an
image from your hard drive, you will apply an image
transformation, and then save the transformed image to your hard
drive in a different format. You will need to have a JPEG image
available that you have renamed test.jpg. If you don't have an
image available, you can download one from
http://today.java.net/pub/a/today/2003/12/12/pics.html. The
images on that page were used in previous tips.

If the API is not already included in your Java platform, you


can download it form the JAI download page
(http://java.sun.com/products/java-media/jai/downloads/download-1_1_2_01.html).
The 1.1.3 alpha has also been released.
In this tip you will access much of the JAI functionality using
the following methods:
JAI.create(String opName, ParameterBlock args)
JAI.create(String opName, ParameterBlock args,
RenderingHints hints);
The ParameterBlock is an object designed to hold all of the
sources and parameters passed to the method referenced by opName.
A ParameterBlock consists of a Vector of sources and a Vector of
parameters. The two most useful methods in ParameterBlock are
addSource() and add(). You use addSource() to add an image to
the end of the list of sources. You use add() to add a wrapper
for a primitive or an object of type Object to the end of the
list of parameters. The remaining methods in ParameterBlock
allow you to access, manipulate, and remove elements from the
parameters or sources collections.
For example, to load an image named test.jpg, you could do the
following:
ParameterBlock pb = new ParameterBlock();
pb.add("test.jpg);
image = JAI.create("fileload", pb);
This "FileLoad" operation uses the codecs supplied JAI. You can
instead use the "ImageRead" operation which is included in the
separate JAI Image I/O Tools package. ImageRead is not covered
in this tip as it requires installing an additional package.
Also note that if test.jpg is not in the local directory, you
will have to adjust this path accordingly.
In this code snippet, image is of type PlanarImage. This is the
base class for two-dimensional images in JAI, and can be thought
of as a collection of pixels. The JAI.create() method returns an
object of type RenderedOp. RenderedOp extends PlanarImage, and
includes the information on the operation just performed on
the images. If you chain a sequence of operations together, you
have a record of these operations in the RenderedOp nodes.
A RenderedOp is a node in a directed acylic graph of operations.
How do you know what operations are available to you and what
parameters must be included in the corresponding ParameterBlock?
Look at the classes in the package javax.media.jai.operator.
(You can view a list of the classes at
http://java.sun.com/products/java-media/jai/forDevelopers/
jai-apidocs/javax/media/jai/operator/package-summary.html).
Notice all of the classes with names that end with Descriptor.
These are OperationDescriptor implementations. For example,
you should see a class named FileLoadDescriptor. In the JavaDoc
for FileLoadDescriptor, you will find the GlobalName listed as
fileload, which is what was passed into the JAI.create() method.
You will also find a list of the parameters expected and their

default values.
In general, these implementations of
javax.media.jai.OperationDescriptor have names of the form
<opName>Descriptor. The corresponding operation name that is
passed in as the first parameter for JAI.create() is <opName>.
There are more than one hundred possible operations. In the
remainder of this tip, you will apply a convolution to a jpeg
image, and save the transformed image as a tiff file.
The February 10, 2004 tip "Styling Digital Images with
ConvolveOp"
(http://java.sun.com/developer/JDCTechTips/2004/tt0210.html#1)
showed how to blur or sharpen an image using a convolution.
If you followed that tip, you created a 3-by-3 kernel for
a convolution. The convoluton was based on a normalized linear
combination of the pixel itself, the four pixels with which it
shares an edge, and the four pixels with which it shares
a corner. You will do the same thing here, but you'll use the
corresponding JAI class javax.media.jai.KernelJAI, as follows:
import javax.media.jai.KernelJAI;
public class My3x3JAIKernels {
private static final float[] IDENTITY = {0, 0, 0,
0, 1, 0,
0, 0, 0};
private static final float[] EDGE =

{0, 1, 0,
1, 0, 1,
0, 1, 0};

private static final float[] CORNER =

{1, 0, 1,
0, 0, 0,
1, 0, 1};

public static KernelJAI getkernel(int corner,


int edge,
int identity) {
float[] kernel = new float[9];
int sum = corner * 4 + edge * 4 + identity;
if (sum == 0) sum = 1; // to avoid dividing by zero
for (int i = 0; i < 9; i++) {
kernel[i] = (corner * CORNER[i]
+ edge * EDGE[i]
+ identity * IDENTITY[i]) / sum;
}
return new KernelJAI(3, 3, kernel);
}
}
You can now create the KernelJAI object for any set of three
values representing the coefficients of the CORNER, EDGE, and
IDENTITY arrays like this:
My3x3JAIKernels.getkernel(corner, edge, identity));
The returned KernelJAI object can then be passed to the
following method which performs the convolution:

private void convolveImage(KernelJAI kernel) {


ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(kernel);
image = JAI.create("convolve", pb, null);
}
Notice that you had to add the PlanarImage to the list of
sources for the ParameterBlock, and add the KernelJAI object to
the list of parameters. To write out the transformed image as
a tiff, you need to use the "filestore" operation. You also need
to pass in the convolved image as a source, and information
about the name and format for saving it.
As with the "FileLoad" operation, if you download the separate
JAI Image I/O Tools package you should replace the "FileStore"
operation with "ImageWrite".
private void writeImageAsTiff(){
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add("target.tiff");
pb.add("tiff");
pb.add(null);
pb.add(true);
image = JAI.create("filestore", pb, null);
}
For completeness, here is a program, JAIConvolve, that
initially displays the untransformed image and then replaces it
with the transformed image.
import
import
import
import
import
import
import
import

javax.swing.JFrame;
javax.swing.JPanel;
javax.media.jai.PlanarImage;
javax.media.jai.JAI;
javax.media.jai.KernelJAI;
java.awt.image.BufferedImage;
java.awt.image.renderable.ParameterBlock;
java.awt.Graphics;

public class JAIConvolve extends JPanel {


private BufferedImage buffImage;
private PlanarImage image;
JAIConvolve(int corner, int edge, int identity) {
createBufferedImages();
setUpJFrame();
// you can introduce a delay here to view the initial
// image before the convolution is applied
convolveImage(My3x3JAIKernels.getkernel(corner,
edge,
identity));
writeImageAsTiff();
}

private void createBufferedImages() {


ParameterBlock pb = new ParameterBlock();
pb.add("test.jpg");
image = JAI.create("fileload", pb);
drawImage();
}
private void setUpJFrame() {
JFrame myFrame = new JFrame("3 x 3 Convolution");
myFrame.setSize(buffImage.getWidth(),
buffImage.getHeight());
myFrame.add(this);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
myFrame.setVisible(true);
}
private void convolveImage(KernelJAI kernel) {
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add(kernel);
image = JAI.create("convolve", pb, null);
drawImage();
}
private void writeImageAsTiff(){
ParameterBlock pb = new ParameterBlock();
pb.addSource(image);
pb.add("target.tiff");
pb.add("tiff");
pb.add(null);
pb.add(true);
image = JAI.create("filestore", pb, null);
}
private void drawImage() {
buffImage
= image.getAsBufferedImage();
Graphics g = buffImage.createGraphics();
g.drawImage(buffImage, 0, 0, null);
g.dispose();
repaint();
}
public void paintComponent(Graphics g) {
g.drawImage(buffImage, 0, 0, this);
}
public static void main(String[] args) {
if (args.length != 3) {
System.out.println("Usage: java Convolve" +
" corner edge identity");
System.out.println("where corner, edge, " +
"and identity are ints");
System.exit(0);
}
int corner = Integer.parseInt(args[0]);
int edge = Integer.parseInt(args[1]);
int identity = Integer.parseInt(args[2]);
new JAIConvolve(corner, edge, identity);
}

}
Compile and run JAIConvolve using values that show off the
different effects. For example, to blur the image use:
java JAIConvolve 1 0 0
To view an "etching" of the image pass in the parameters -1 -1 8.
Your local directory should also now contain the file target.tiff
which is a tiff you can share with others that captures your
convolution.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CALENDAR UTILITIES IN JDESKTOP NETWORK COMPONENTS
The April 5, 2005 tip "Introduction to Tables with JDesktop
Network Components (JDNC)"
(http://java.sun.com/developer/JDCTechTips/2005/tt0405.html#2)
showed how to use JDNC to read tab-separated data from a file
and display it in a table. In this tip, you will use the Java
APIs for JDNC to create simple calendar widgets. You can use
these widgets to pick dates and to display events in a month
view. There are many rich offerings in JDNC, this tip gives you
a quick look at how the APIs make it easier to perform common
tasks.
To run the examples in this tip, download the latest JDNC
release from the jdnc download page
(https://jdnc.dev.java.net/servlets/ProjectDocumentList). The
latest version is currently 0.7 and requires J2SE 5.0. Download
and expand the file jdnc-0_7-bin.zip. Create a directory for
the examples in this tip, and copy into it the three jar files
from jdnc-0_7/lib (jdnc-0_7-all, jdnc-runner, and jlfgr-1_0).
You will also need to add to your classpath the three jar files
you just copied.
Let's start with a very simple thing you can do with JDNC, that
is add a component to be used for picking dates. You can do that
with the following single line of code:
frame.addComponent(new JXDatePicker());
The method addComponent() should be a hint that the variable
frame, which refers to the top level container, is not a JFrame.
In fact, you are using an org.jdesktop.swing.JXFrame, which
extends a JFrame by adding some functionality. The following
example program, DatePicker, creates a JXFrame object and adds
a newly created JXDatePicker object to it:
import org.jdesktop.swing.JXDatePicker;
import org.jdesktop.swing.JXFrame;
public class DatePicker {
public static void main(String[] args) {
JXFrame frame = new JXFrame("Date");
frame.addComponent(new JXDatePicker());
frame.setResizable(false);
frame.setVisible(true);
}

}
Compile and run DatePicker. You will see a small frame containing
today's date.
The text in this component is editable. You can
also press the button on the right side of the frame and a menu
containing the current month appears. Today's date is selected
and is framed. Click on a different day. The picker disappears
and the newly selected date is in the frame. Click on the button
again and the month view again appears. This time the selected
date has a grey background but the today's date is framed with
the square. You can use the arrows to move forward or backwards a
month at a time.
The month view that is visible when you click on the button in
the date picker is also available as a stand alone component in
the org.jdesktop.swing.calendar package. You can use the
JXMonthView class to display any calendar month and to allow the
user to select a range of days. The no argument constructor of
JMXMonthView is used to instantiate a JXMonthView that displays
the current month. The current date is framed and no date is
selected.
You can customize the look of the calendar by changing the
colors. This includes the color that appears behind the name of
the month, the background of the body of the calendar, the color
of the frame around today's date, and the color that appears for
selected days. Other customizations allow you to specify the
first day of the week as well as the character used to represent
each day of the week.
Also, through the setSelectionMode() method, you to specify
a mode that configures what the user can select. A mode of
NO_SELECTION means that the user cannot select any days in the
calendar. The mode default is SINGLE_SELECTION, it allows the
user to select one value at a time. If SINGLE_SELECTION is
chosen, only one date will appear to be selected, even if a user
programatically selects a range of days. MULTIPLE_SELECTION
allows a user to select a range of consecutive days by clicking
on one day and dragging to others. WEEK_SELECTION restricts this
choice by changing selections longer than seven days to exactly
a week from the day clicked.
The following example program, MonthView, creates a new
JXMonthView. The program then sets the color for selected days
to red and the frame for today's date to green. The program
allows multiple days to be selected.
import org.jdesktop.swing.JXFrame;
import org.jdesktop.swing.calendar.JXMonthView;
import java.awt.Color;
public class MonthView extends JXFrame {
public MonthView(){
setResizable(false);

JXMonthView monthView = new JXMonthView();


monthView.setTodayBackground(Color.GREEN);
monthView.setSelectedBackground(Color.RED);
monthView.setSelectionMode(
JXMonthView.MULTIPLE_SELECTION);
addComponent(monthView);
}
public static void main(String[] args) {
new MonthView().setVisible(true);
}
}
Compile and run MonthView. Click on any day and drag your
mouse to select a range of dates. You should see those selected
days highlighted in red.
You can further customize the month view in many ways. First,
you can create a view to include a specified date. For example,
the following creates a month that includes July 15, 2005:
todaysDate = (new GregorianCalendar(2005,
6, 15)).getTimeInMillis();
monthView = new JXMonthView(todaysDate);
Although this looks unusual, remember that months are zero based
so that January is 0 which means that month 6 is July and not
June. Next, you can set any day to be the first day of the week.
Here is how you would specify a calendar where each week begins
on Monday:
monthView.setFirstDayOfWeek(Calendar.MONDAY);
To further exercise the JXMonthView class, you will need to use
two other classes in the org.jdesktop.swing.calendar package:
DateSpan and DateUtils. To select a range of dates, use the
setSelectedDateSpan() method in JXMonthView and pass in a
DateSpan object. This requires you to specify a beginning date
and an end date. You can do this by explicitly selecting the
days using the GregorianCalendar class as before. You can also
use some of the convenience methods in the DateUtils class to
select the date before or after, the date a week before or
after, and the first day of the month or the last day of the
month. Here's how you can select multiple dates using DateSpan
and DateUtils:
long startDate = DateUtils.previousWeek(todaysDate);
long endDate = DateUtils.previousDay(todaysDate);
monthView.setSelectedBackground(Color.LIGHT_GRAY);
monthView.setSelectionMode(JXMonthView.MULTIPLE_SELECTION);
monthView.setSelectedDateSpan(new DateSpan(startDate,
endDate));
In addition to selecting dates you can flag special days. For
example, you might want to highlight holidays, or pay days, or
weekends. The effect of using:
monthView.setFlaggedDates(flaggedDates);

is that the days passed in an array of longs in ascending order


are highlighted in bold.
Here is a program example, RangeofDates, that uses these additional
features:
import
import
import
import

org.jdesktop.swing.JXFrame;
org.jdesktop.swing.calendar.JXMonthView;
org.jdesktop.swing.calendar.DateSpan;
org.jdesktop.swing.calendar.DateUtils;

import java.awt.Color;
import java.util.GregorianCalendar;
import java.util.Calendar;
public class RangeOfDates extends JXFrame {
private long todaysDate;
private JXMonthView monthView;
RangeOfDates() {
setResizable(false);
setUpMonthView();
markDateSpan();
flagDates();
addComponent(monthView);
}
private void setUpMonthView() {
todaysDate = (new GregorianCalendar(2005,
6, 15)).getTimeInMillis();
monthView = new JXMonthView(todaysDate);
monthView.setFirstDayOfWeek(Calendar.MONDAY);
}
private void markDateSpan() {
long startDate = DateUtils.previousWeek(todaysDate);
long endDate = DateUtils.previousDay(todaysDate);
monthView.setSelectedBackground(Color.LIGHT_GRAY);
monthView.setSelectionMode(
JXMonthView.MULTIPLE_SELECTION);
monthView.setSelectedDateSpan(new DateSpan(startDate,
endDate));
}
private void flagDates() {
long[] flaggedDates = {
DateUtils.getStartOfMonth(todaysDate),
todaysDate,
DateUtils.getEndOfMonth(todaysDate)
};
monthView.setFlaggedDates(flaggedDates);
}
public static void main(String[] args) {
new RangeOfDates().setVisible(true);
}
}

Compile and run RangeOfDates. You will see a calendar view of


July, 2005, a week highlighted, and three days flagged. There is
nothing groundbreaking about this API. It does, however, keep
you from having to reimplement the same code every time you need
a calendar widget.
For more information about JDNC, see the JDNC project page
(https://jdnc.dev.java.net/).
. . . . . . . . . . . . . . . . . . . . . . .
PRIVACY STATEMENT:
Sun respects your online time and privacy (http://sun.com/privacy).
You have received this based on your e-mail preferences. If you
would prefer not to receive this information, please follow the
steps at the bottom of this message to unsubscribe.
Please read our Terms of Use and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://developers.sun.com/dispatcher.jsp?uid=6910008
* FEEDBACK
Comments? Please enter your feedback on the Tech Tips at:
http://developers.sun.com/contact/feedback.jsp?category=sdn
* SUBSCRIBE/UNSUBSCRIBE
Subscribe to other Java developer Tech Tips:
- Enterprise Java Technologies Tech Tips. Get tips on using
enterprise Java technologies and APIs, such as those in the
Java 2 Platform, Enterprise Edition (J2EE).
- Wireless Developer Tech Tips. Get tips on using wireless
Java technologies and APIs, such as those in the Java 2
Platform, Micro Edition (J2ME).
To subscribe to these and other SDN publications:
- Go to the Sun Developer Network - Subscriptions page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
choose the newsletters you want to subscribe to and click
"Submit".
- To unsubscribe, go to the Subscriptions page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
uncheck the appropriate checkbox, and click "Submit".
- To use our one-click unsubscribe facility, see the link at
the end of this email:
- ARCHIVES
You'll find the Core Java Technologies Tech Tips archives at:
http://java.sun.com/developer/TechTips/index.html
- COPYRIGHT
Copyright 2005 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, California 95054 USA.

This document is protected by copyright. For more information, see:


http://java.sun.com/jdc/copyright.html
Core Java Technologies Tech Tips
June 1, 2005
Trademark Information: http://www.sun.com/suntrademarks/
Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks
or registered trademarks of Sun Microsystems, Inc. in the
United States and other countries.

You might also like