| You are receiving this e-mail because you elected to receive e-mail from Sun Microsystems, Inc. To update your communications preferences, please see the link at the bottom of this message. We respect your privacy and post our privacy policy prominently on our Web site http://sun.com/privacy/ |
![]() |
||||||
|
||||||
| In this Issue | ||
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. 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 latest Java platform releases, tutorials, and newsletters. java.net - A web forum where enthusiasts of Java technology can collaborate and build solutions together. java.com - Hot games, cool apps -- Experience the power of Java technology. |
||
| INTRODUCTION TO JAVA ADVANCED IMAGING | ||
The Java Advanced Imaging (JAI) API 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 here. The images on that page were used in previous tips. For example, you can download the following image: ![]() If the API is not already included in your Java platform, you can download it form the JAI download page. 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). 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" 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 javax.swing.JFrame;
import javax.swing.JPanel;
import javax.media.jai.PlanarImage;
import javax.media.jai.JAI;
import javax.media.jai.KernelJAI;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;
import 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.![]() Back to Top |
||
| CALENDAR UTILITIES IN JDESKTOP NETWORK COMPONENTS | ||
|
The April 5, 2005 tip "Introduction to Tables with JDesktop Network Components (JDNC)" 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. 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 org.jdesktop.swing.JXFrame;
import org.jdesktop.swing.calendar.JXMonthView;
import org.jdesktop.swing.calendar.DateSpan;
import 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. Back to Top |
||
|
Comments? Send your feedback on the Tech Tips: http://developers.sun.com/contact/feedback.jsp?category=sdn
Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
IMPORTANT: Please read our Terms of Use, Privacy, and Licensing policies: http://www.sun.com/share/text/termsofuse.html http://www.sun.com/privacy/ http://developer.java.sun.com/berkeley_license.html © 2005 Sun Microsystems, Inc. All Rights Reserved. For information on Sun's trademarks see: http://sun.com/suntrademarks Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Sun Microsystems, Inc. 10 Network Circle, MPK10-209 Menlo Park, CA 94025 US As used on the web site, the terms "Java Virtual Machine" and "JVM" mean a virtual machine for the Java platform. |