import java.awt.image.BufferedImage

advertisement
Displaying an Image
In the first example, we simply display an image on the panel.
DisplayImage.java
package com.zetcode;
import
import
import
import
java.awt.Dimension;
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class DisplayImage extends JPanel {
Image castle;
Dimension size;
public DisplayImage() {
size = new Dimension();
castle = new
ImageIcon(this.getClass().getResource("redrock.png")).getImage();
size.width = castle.getWidth(null);
size.height = castle.getHeight(null);
setPreferredSize(size);
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(castle, 0, 0, null);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Red Rock");
frame.add(new DisplayImage());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Grayscale image
In computing, a grayscale digital image is an image in which the value of each pixel is a
single sample, that is, it carries the full (and only) information about its intensity.
Images of this sort are composed exclusively of shades of neutral gray, varying from
black at the weakest intensity to white at the strongest. (wikipedia)
In the next example, we will create a grayscale image with Java 2D tools.
GrayImage.java
package com.zetcode;
import
import
import
import
import
java.awt.Dimension;
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.Image;
java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GrayImage extends JPanel {
Image castle;
BufferedImage bufferedImage;
Dimension size;
public GrayImage() {
size = new Dimension();
castle = new ImageIcon("slanec.jpg").getImage();
size = new Dimension();
size.width = castle.getWidth(null);
size.height = castle.getHeight(null);
setPreferredSize(size);
bufferedImage =
new BufferedImage(size.width, size.height,
BufferedImage.TYPE_BYTE_GRAY);
Graphics g = bufferedImage.getGraphics();
g.drawImage(castle, 0, 0, null);
g.dispose();
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(bufferedImage, null, 0, 0);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Grayscale");
frame.add(new GrayImage());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Flipped image
Next we are going to flip an image. We are going to filter the image. There is
a filter() method, which is transforming images.
ImageFlip.java
package com.zetcode;
import
import
import
import
import
import
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.Image;
java.awt.geom.AffineTransform;
java.awt.image.AffineTransformOp;
java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class ImageFlip extends JPanel {
Image castle;
BufferedImage bufferedImage;
public ImageFlip() {
castle = new ImageIcon("slanec.jpg").getImage();
bufferedImage = new BufferedImage(castle.getWidth(null),
castle.getHeight(null), BufferedImage.TYPE_INT_RGB);
}
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
Graphics gb = bufferedImage.getGraphics();
gb.drawImage(castle, 0, 0, null);
gb.dispose();
AffineTransform tx = AffineTransform.getScaleInstance(-1, 1);
tx.translate(-castle.getWidth(null), 0);
AffineTransformOp op = new AffineTransformOp(tx,
AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
bufferedImage = op.filter(bufferedImage, null);
g2d.drawImage(castle, 10, 10, null);
g2d.drawImage(bufferedImage, null, 290, 10);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Flip image");
frame.add(new ImageFlip());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(570, 230);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Blurred image
The next code example will blur our image. Blur means an unfocused image. To blur an
image, we use the convolution operation. It is a mathematical operations. It is also used
in edge detection or noise elimination. Blur operations can be used in various graphical
effects. For example creating speed illusion, showing an unfocused vision of a human
being etc.
The blur filter operation replaces each pixel in image with an average of the pixel and its
neighbours.
BlurredImage.java
package com.zetcode;
import
import
import
import
import
import
import
java.awt.Dimension;
java.awt.Graphics;
java.awt.Graphics2D;
java.awt.image.BufferedImage;
java.awt.image.BufferedImageOp;
java.awt.image.ConvolveOp;
java.awt.image.Kernel;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class BlurredImage extends JPanel {
BufferedImage castle;
BufferedImage filteredImage;
Dimension size;
public BlurredImage() {
try {
castle =
ImageIO.read(this.getClass().getResource("redrock.png"));
} catch (IOException e) {
System.out.println("cannot read image");
}
filteredImage = new BufferedImage(castle.getWidth(null),
castle.getHeight(null),
BufferedImage.TYPE_BYTE_GRAY);
size = new Dimension();
size.width = castle.getWidth(null);
size.height = castle.getHeight(null);
setPreferredSize(size);
Graphics g = filteredImage.getGraphics();
g.drawImage(castle, 455, 255, null);
float[] blurKernel = {
1/9f, 1/9f, 1/9f,
1/9f, 1/9f, 1/9f,
1/9f, 1/9f, 1/9f
};
BufferedImageOp blur = new ConvolveOp(new Kernel(3, 3, blurKernel));
castle = blur.filter(castle, new BufferedImage(castle.getWidth(),
castle.getHeight(),castle.getType()));
g.dispose();
}
@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(castle, null, 3, 3);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Blurred Image");
frame.add(new BlurredImage());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Reflection
In the next example we show a reflected image. This beautiful effect makes an illusion as
if the image was reflected in water.
Reflection.java
package com.zetcode;
import
import
import
import
import
java.awt.*;
java.awt.image.*;
java.io.*;
javax.imageio.*;
javax.swing.*;
public class Reflection extends JComponent {
private BufferedImage image;
public Reflection() {
try {
image = ImageIO.read(new File("slanec.jpg"));
} catch (Exception e) {
e.printStackTrace();
}
}
public void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D)g;
int width = getWidth();
int height = getHeight();
int imageWidth = image.getWidth();
int imageHeight = image.getHeight();
int gap = 20;
float opacity = 0.4f;
float fadeHeight = 0.3f;
g2d.setPaint(new GradientPaint(0, 0, Color.black, 0, height,
Color.darkGray));
g2d.fillRect(0, 0, width, height);
g2d.translate((width - imageWidth) / 2, height / 2 - imageHeight);
g2d.drawRenderedImage(image, null);
g2d.translate(0, 2 * imageHeight + gap);
g2d.scale(1, -1);
BufferedImage reflection =
new BufferedImage(imageWidth, imageHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D rg = reflection.createGraphics();
rg.drawRenderedImage(image, null);
rg.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN));
rg.setPaint(new GradientPaint(0, imageHeight * fadeHeight,
new Color(0.0f, 0.0f, 0.0f, 0.0f), 0,
imageHeight,
new Color(0.0f, 0.0f, 0.0f, opacity)));
rg.fillRect(0, 0, imageWidth, imageHeight);
rg.dispose();
g2d.drawRenderedImage(reflection, null);
}
public Dimension getPreferredSize() {
return new Dimension(320, 390);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Reflection");
Reflection r = new Reflection();
frame.add(new Reflection());
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
package com.example.vacphotos;
02.
03.import javax.swing.Icon;
04.import javax.swing.ImageIcon;
05.import photoalbumapp.Photo;
06.
07.public class VacPhotos implements Photo {
08.
09.ImageIcon icon1
= newImageIcon(getClass().getResource("/com/example/vacphotos/demo1.png"))
;
10.ImageIcon icon2
= newImageIcon(getClass().getResource("/com/example/vacphotos/demo2.png"))
;
11.
12.public VacPhotos() {
13.}
14.
15.@Override
16.public Icon[] getPhoto() {
17.Icon[] icons = new Icon[]{icon1, icon2};
18.return icons;
19.}
20.
21.@Override
22.public String[] getDescription() {
23.String[] descs = new String[]{"pic 1", "pic2"};
24.return descs;
25.}
26.
27.}
01.package photoalbumapp;
02.
03.import java.util.Collection;
04.import org.openide.util.Lookup;
05.import org.openide.util.Lookup.Result;
06.import org.openide.util.Lookup.Template;
07.
08.public class PhotoService {
09.
10.private static PhotoService service;
11.private Lookup photoLookup;
12.private Collection photos;
13.private Template photoTemplate;
14.private Result photoResults;
15.
16.private PhotoService() {
17.photoLookup = Lookup.getDefault();
18.photoTemplate = new Template(Photo.class);
19.photoResults = photoLookup.lookup(photoTemplate);
20.photos = photoResults.allInstances();
21.}
22.
23.public static synchronized PhotoService getInstance() {
24.if (service == null) {
25.service = new PhotoService();
26.}
27.return service;
28.}
29.
30.public Collection getDefinitions() {
31.return photos;
32.}
33.
34.}
Setting Up Your Own Photo Album
To implement a photo album project, I have established a very simple directory structure. You may
ultimately use something different, but if you want to use the included source with minimal changes,
follow this structure:
1. All photo album folders will reside in some main "root" directory.
2. Every album folder must contain two sub folders, called "images" and "thumbnails" (more on this
later).
3. Album folders can be nested.
For example:




Post a comment
Email Article
Print Article
Share Articles
C:photos: is my main root folder
C:photosSomeAlbum: photo album folder
C:photosSomeAlbumimages
C:photosSomeAlbumthumbnails
Helper Objects
I will start with helper classes before moving on to the main algorithms. To filter out only specific file types
to work with, I implemented classes using the standard java.io FileFilter interface, located in
the filters package. The DirFilter filters out only directory file types and only those that I'm interested in.
Here is the code implementing the accept method from the java.io FileFilter interface.
public boolean accept(File file) {
return file.isDirectory() && !excludeDir(file.getName());
}
private boolean excludeDir(String dirname) {
for (int i = 0; i < exclude.length; i++) {
if (exclude[i].equals(dirname)) {
return true;
}
}
return false;
}
Similarly, the ImageFilesOnly filters out only image file types from the list of all files in a folder—in this
case, only JPG files.
static String[] accepted = {"jpg", "JPG"};
public boolean accept(File file) {
if (file.isFile()) {
String fn = file.getName();
return (file.isFile() && (fn.endsWith(accepted[0]) ||
fn.endsWith(accepted[1])));
}
return false;
}
I apply the filters when I create the file objects representing a file system folders or files. For instance,
File dir = new File("C:\photos");
File[] pics = dir.listFiles(new ImageFilesOnly());
will create a list of JPG files located in the "photos" folder.
The ImageUtils from the util package contains APIs pertaining to the logical Image object, which
represents one picture. I did not create a separate picture representation object in the beans package
because all of the image properties required for the back-end engine are calculated in real time, and the
image is represented simply by java.io.File. The APIs for the Image are:
 getImageCameraManufacturer(File img)
 getImageExifCameraModel(File img)
 getImageExifCreationDate(File img)
 getImageExifMetaData(File img, int meta)
As you may have guessed, all of these APIs use the metadata extractor library developed by Drew
Noakes (see reference), and the names are self explanatory. One API of particular interest is
thegetImageExifCreationDate. It uses the FileTimes utility and has some logic in addition to the metadata
extractor calls. Different manufacturers may call the field in the metadata of the file representing date the
picture was taken differently, and in rare cases may not store that field at all. Therefore, I try different tags
to locate the creation date of the picture. Otherwise, if image does not have this field, I get the time the file
was created.
Here is the source code for this method. See the complete source for the other methods:
public static String getImageExifCreationDate(File img) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
try {
Metadata metadata = JpegMetadataReader.readMetadata(img);
Directory exifDirectory =
metadata.getDirectory(ExifDirectory.class);
String dt = exifDirectory.getString(ExifDirectory.TAG_DATETIME);
String dt_org =
exifDirectory.getString(ExifDirectory.TAG_DATETIME_ORIGINAL);
String dt_dt =
exifDirectory.getString(ExifDirectory.TAG_DATETIME_DIGITIZED);
if (dt_org != null && !dt_org.startsWith("0000")) {
return dt_org;
} else if (dt != null && !dt.startsWith("0000")) {
return dt;
} else if (dt_dt != null && !dt_dt.startsWith("0000")) {
return dt_dt;
} else {
// not correct call . java has no API to get the file
// create date of a file
// return sdf.format(new Date(img.lastModified()));
return sdf.format(new Date(FileTimes.getFileCreated(
img.getPath())));
}
} catch (JpegProcessingException ex) {
logger.error(ex, ex);
return null;
}
}
The AlbumUtil class in the same util package that pertains to the Album object, which is a higher
obstructed object than the single image and is represented by the folder on the file system. AlbumUtil is
much more complex than the ImageUtil and has a lot of logic that constitutes a big part of the main backend engine. For example, the getFolderDate method does a selective sampling of the file creation dates
of the first, middle, and last picture in the folder using the getImageExifCreationDate method, which then
returns the latest date. The getAlbumDate method uses the getFolderDate method to recursively
calculate one master date for the whole Album, including subfolders and excluding folders designated by
the EXCLUDE_DIR parameter.
Here is the source for the getAlbumDate method:
public static String getAlbumDate(File dir) {
String[] dates = null;
ArrayList aDates = new ArrayList();
File[] innerAlbums =
dir.listFiles(new DirFilter(new String[] {TNAILS_DIR}));
if (innerAlbums != null && innerAlbums.length > 0) {
String currentDirDate = getFolderDate(dir);
if (currentDirDate != null) {
// if there are pictures in
// the current dir
aDates.add(currentDirDate);
}
for (int i = 0; i < innerAlbums.length; i++) {
// recursive call to continue traversing the dir tree
String date = getAlbumDate(innerAlbums[i]);
if (date != null) {
aDates.add(date);
}
}
dates = (String[]) aDates.toArray(new String[aDates.size()]);
Arrays.sort(dates, Collections.reverseOrder());
}
else {
// there are no child dir - return date for this dir
return getFolderDate(dir);
}
return dates[0];
}
Because I do not read the creation date for every file in every subfolder, but instead use selective
sampling, very little I/O is generated and the calculation engine is extremely fast. The selective sampling
works even if pictures are not in alphabetical order. For example, over 800 Mb of pictures can be
analyzed in 953 MS on a standard hard drive (7200 RMP), with RAID optimized I/O; with 10000 RPM
hard drives, this time can be decreased even further.
Now, look at how the engine works.
The GetResourceFiles object (called from the main method) is passed a location of the root folder.
It then calls a getRootView method that recursively traverses the folders and pushes them on the Stack.
For every folder that is pushed on the stack, a random thumbnail image is calculated every time the
engine is called (see the pushAlbum method). This is the property that can be accessed on the front end
to display a different picture for an album on every refresh.
In addition, if the folder has subfolders, they are all analyzed, sorted by their calculated date, and also
pushed on the Stack. The output indentation you see is created by the relative position of the object in the
stack. Therefore, child folders are correctly indented from the parent folders (see the indent method) But,
for the Web representation, the indent method would need to be changed to account for the HTML or
other output.
public void getRootView(File dir) {
if (dir.exists() && dir.isDirectory()) {
Album a = new Album(dir);
pushAlbum(a);
// one level down only
Album[] innerAlbums = a.getInnerAlbums();
if (innerAlbums != null && innerAlbums.length > 0) {
// sort in the order of newest first here
// before expecting them
SortedMap sortedInnerAlbums =
AlbumUtils.sortAlbums(innerAlbums);
Collection sAlbums = sortedInnerAlbums.values();
innerAlbums =
(Album[]) sAlbums.toArray(new Album[sAlbums.size()]);
sortedAlbums.putAll(sortedInnerAlbums);
for (int i = 0; i < innerAlbums.length; i++) {
// recursive call to continue traversing the dir tree
getRootView(innerAlbums[i].getDir());
}
}
popAlbum();
}
}
private String indent(String tag) {
StringBuffer res = new StringBuffer();
int indent = stack.size() - 1;
for (int i = 0; i < indent; i++) {
res.append("t");
}
res.append(tag);
return res.toString();
}
Download