Image Zooming
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.transitions.Effect;
import org.jdesktop.animation.transitions.EffectsManager;
import org.jdesktop.animation.transitions.EffectsManager.TransitionType;
import org.jdesktop.animation.transitions.ScreenTransition;
import org.jdesktop.animation.transitions.TransitionTarget;
import org.jdesktop.animation.transitions.effects.CompositeEffect;
import org.jdesktop.animation.transitions.effects.Move;
import org.jdesktop.animation.transitions.effects.Scale;
//import org.jdesktop.tools.io.FileTreeWalk;
//import org.jdesktop.tools.io.FileTreeWalker;
//import org.jdesktop.tools.io.UnixGlobFileFilter;
import java.io.FileFilter;
import java.io.File;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
/*
* ImageBrowser.java
*
* Created on May 3, 2007, 3:11 PM
*
* Copyright (c) 2007, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the TimingFramework project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* This demo of the AnimatedTransitions library uses a layout manager
* to assist in setting up the next screen that the application
* transitions to.
*
* The slider in the window controls the picture thumbnail size. The
* standard FlowLayout manager organizes the pictures according to
* the thumbnail sizes. The transition animates the change from
* one thumbnail size to the next.
*
* @author Chet
*/
public class ImageBrowser extends JComponent
implements TransitionTarget, ChangeListener {
private static final int SLIDER_INCREMENT = 50;
int numPictures = 40;
JLabel label[];
Animator animator = new Animator(500);
ScreenTransition transition = new ScreenTransition(this, this, animator);
Dimension newSize = new Dimension();
List<ImageHolder> images = new ArrayList<ImageHolder>();
static int currentSize = 50;
GradientPaint bgGradient = null;
int prevHeight = 0;
static JSlider slider = new JSlider(1, 400 / SLIDER_INCREMENT,
1 + currentSize / SLIDER_INCREMENT);
static int numImages = 0;
/** Creates a new instance of ImageBrowser */
public ImageBrowser() {
setOpaque(true);
animator.setAcceleration(.1f);
animator.setDeceleration(.4f);
setLayout(new FlowLayout());
loadImages();
label = new JLabel[images.size()];
// For each image:
// - set the icon at the current thumbnail size
// - create/set a custom effect that will move/scale the
// images. Note that the main reason for the custom effect
// is that scaling effects typically redraw the actual component
// instead of using image tricks. In this case, image tricks are
// just fine. So the custom effect is purely an optimization here.
for (int i = 0; i < images.size(); ++i) {
label[i] = new JLabel();
label[i].setIcon(new ImageIcon(images.get(i).getImage(currentSize)));
add(label[i]);
Effect move = new Move();
Effect scale = new Scale();
CompositeEffect comp = new CompositeEffect(move);
comp.addEffect(scale);
comp.setRenderComponent(false);
EffectsManager.setEffect(label[i], comp, TransitionType.CHANGING);
}
}
/**
* Paints a gradient in the background of this component
*/
@Override
protected void paintComponent(Graphics g) {
if (getHeight() != prevHeight) {
prevHeight = getHeight();
bgGradient = new GradientPaint(0, 0,
new Color(0xEBF4FA), 0, prevHeight, new Color(0xBBD9EE));
}
((Graphics2D)g).setPaint(bgGradient);
g.fillRect(0, 0, getWidth(), prevHeight);
}
/**
* Loads all images found in the directory "images" (which therefore must
* be found in the folder in which this app runs).
*/
private void loadImages() {
//try {
//File imagesDir = new File("images");
//FileTreeWalker walker = new FileTreeWalker(imagesDir,
// new UnixGlobFileFilter("*.jpg"));
//walker.walk(new FileTreeWalk() {
// public void walk(File path) {
//numImages++;
try {
BufferedImage image = ImageIO.read(ImageBrowser.class.getResource("shanghai.jpg"));
images.add(new ImageHolder(image));
} catch (Exception e) {
System.out.println("Problem loading images: " + e);
}
//}
//});
//} catch (Exception e) {
// System.out.println("Problem loading images: " + e);
//}
}
/**
* TransitionTarget implementation: The setup for the next screen entails
* merely assigning a new icon to each JLabel with the new thumbnail
* size
*/
public void setupNextScreen() {
for (int i = 0; i < images.size(); ++i) {
label[i].setIcon(new ImageIcon(images.get(i).getImage(currentSize)));
}
// revalidation is necessary for the LayoutManager to do its job
revalidate();
}
/**
* This method handles changes in slider state, which can come from either
* mouse manipulation of the slider or right/left keyboard events. This
* event changes the current thumbnail size and starts the transition.
* We will then receive a callback to setupNextScreen() where we set up
* the GUI according to this new thumbnail size.
*/
public void stateChanged(ChangeEvent ce) {
currentSize = slider.getValue() * 25;
if (!transition.getAnimator().isRunning()) {
transition.start();
}
}
private static void createAndShowGUI() {
JFrame f = new JFrame("Image Browser");
f.setLayout(new BorderLayout());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(500, 400);
ImageBrowser component = new ImageBrowser();
f.add(component, BorderLayout.CENTER);
f.add(slider, BorderLayout.SOUTH);
slider.setBackground(new Color(0xBBD9EE));
slider.addChangeListener(component);
f.setVisible(true);
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
} catch (InstantiationException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();
} catch (UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Runnable doCreateAndShowGUI = new Runnable() {
public void run() {
createAndShowGUI();
}
};
SwingUtilities.invokeLater(doCreateAndShowGUI);
}
}
/**
* This is a utility class that holds our images at various scaled
* sizes. The images are pre-scaled down by halves, using the progressive
* bilinear technique. Thumbnails from these images are requested
* from this class, which are created by down-scaling from the next-largest
* pre-scaled size available.
*/
class ImageHolder {
private List<BufferedImage> scaledImages = new ArrayList<BufferedImage>();
private static final int MIN_SIZE = 50;
/**
* Given any image, this constructor creates and stores down-scaled
* versions of this image down to some MIN_SIZE
*/
ImageHolder(BufferedImage originalImage) {
int imageW = originalImage.getWidth();
int imageH = originalImage.getHeight();
scaledImages.add(originalImage);
BufferedImage prevImage = originalImage;
while (imageW > MIN_SIZE && imageH > MIN_SIZE) {
imageW = imageW >> 1;
imageH = imageH >> 1;
BufferedImage scaledImage = new BufferedImage(imageW, imageH,
prevImage.getType());
Graphics2D g2d = scaledImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(prevImage, 0, 0, imageW, imageH, null);
g2d.dispose();
scaledImages.add(scaledImage);
}
}
/**
* This method returns an image with the specified width. It finds
* the pre-scaled size with the closest/larger width and scales
* down from it, to provide a fast and high-quality scaed version
* at the requested size.
*/
BufferedImage getImage(int width) {
for (BufferedImage scaledImage : scaledImages) {
int scaledW = scaledImage.getWidth();
// This is the one to scale from if:
// - the requested size is larger than this size
// - the requested size is between this size and
// the next size down
// - this is the smallest (last) size
if (scaledW < width || ((scaledW >> 1) < width) ||
(scaledW >> 1) < MIN_SIZE) {
if (scaledW != width) {
// Create new version scaled to this width
// Set the width at this width, scale the
// height proportional to the image width
float scaleFactor = (float)width / scaledW;
int scaledH = (int)(scaledImage.getHeight() *
scaleFactor + .5f);
BufferedImage image = new BufferedImage(width,
scaledH, scaledImage.getType());
Graphics2D g2d = image.createGraphics();
g2d.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(scaledImage, 0, 0,
width, scaledH, null);
g2d.dispose();
scaledImage = image;
}
return scaledImage;
}
}
// shouldn't get here
return null;
}
}
/**
* Copyright (c) 2006, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the Harvester project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class UnixGlobFileFilter implements FileFilter {
private Pattern pattern;
public UnixGlobFileFilter(String filter) {
pattern = Pattern.compile(globToRegex(filter));
}
public boolean accept(File file) {
String path = file.getName();
Matcher matcher = pattern.matcher(path);
return matcher.matches();
}
private String globToRegex(String glob) {
char c = '\0';
boolean escape = false;
boolean enclosed = false;
StringBuffer buffer = new StringBuffer(glob.length());
for (int i = 0; i < glob.length(); i++) {
c = glob.charAt(i);
if (escape) {
buffer.append('\\');
buffer.append(c);
escape = false;
continue;
}
switch (c) {
case '*':
buffer.append('.').append('*');
break;
case '?':
buffer.append('.');
break;
case '\\':
escape = true;
break;
case '.':
buffer.append('\\').append('.');
break;
case '{':
buffer.append('(');
enclosed = true;
break;
case '}':
buffer.append(')');
enclosed = false;
break;
case ',':
if (enclosed)
buffer.append('|');
else
buffer.append(',');
break;
default:
buffer.append(c);
}
}
return buffer.toString();
}
}
/**
* Copyright (c) 2006, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the Harvester project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class FileTreeWalker {
private File path;
private static final FileFilter directoryFilter = new FileFilter() {
public boolean accept(File pathname) {
return pathname.isDirectory();
}
};
private FileFilter filter;
public FileTreeWalker(File path) throws IOException {
this(path, new FileFilter() {
public boolean accept(File pathname) {
return pathname.isFile();
}
});
}
public FileTreeWalker(File path, FileFilter filter) throws IOException {
if (path == null || !path.exists() || path.isFile()) {
throw new IOException("Path " + path + " is not a valid directory.");
}
this.path = path;
this.filter = filter;
}
public void walk(FileTreeWalk walk) {
walkDirectory(walk, path);
}
private void walkDirectory(FileTreeWalk walk, File dir) {
File[] files = dir.listFiles(filter);
for (File file : files) {
walk.walk(file);
}
File[] dirs = dir.listFiles(directoryFilter);
for (File subDir : dirs) {
walkDirectory(walk, subDir);
}
}
}
/**
* Copyright (c) 2006, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of the Harvester project nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
interface FileTreeWalk {
public void walk(File path);
}
Filthy-Rich-Clients-ImageZooming.zip( 228 k)Related examples in the same category