/*
* Copyright 2004 - 2008 Christian Sprajc. All rights reserved.
*
* This file is part of PowerFolder.
*
* PowerFolder is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* PowerFolder is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PowerFolder. If not, see <http://www.gnu.org/licenses/>.
*
* $Id: ImageSupport.java 5457 2008-10-17 14:25:41Z harry $
*/
package de.dal33t.powerfolder.ui.util;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageInputStream;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Class with some convenience methods for image handeling.
*
* @author <A HREF="mailto:schaatser@powerfolder.com">Jan van Oosterom</A>
* @version $Revision: 1.13 $
*/
public class ImageSupport {
private static final Logger log = Logger.getLogger(ImageSupport.class.getName());
// Use a set to filter duplicates
private static final Set<String> supportedReadFileTypes = new HashSet<String>();
private static final Set<String> supportedWriteFileTypes = new HashSet<String>();
private static BufferedImage lastImage;
private static int lastWidth;
private static int lastHeight;
private static Image lastResizedImage;
private static int lastScalingType;
static {
Iterator<ImageReaderSpi> it = IIORegistry.getDefaultInstance()
.getServiceProviders(ImageReaderSpi.class, true);
while (it.hasNext()) {
ImageReaderSpi spi = it.next();
supportedReadFileTypes.addAll(Arrays.asList(spi.getFileSuffixes()));
}
supportedReadFileTypes.remove(""); // Seems to get added for some
// reason...
Iterator<ImageWriterSpi> writers = IIORegistry.getDefaultInstance().getServiceProviders(ImageWriterSpi.class, true);
while (writers.hasNext()) {
ImageWriterSpi spi = writers.next();
supportedWriteFileTypes.addAll(Arrays.asList(spi.getFileSuffixes()));
}
}
/**
* is there a image reader available for a file with this extension?
*
* @param filename
* the file to determen if there is a imageReader for.
* @return true if there is a ImageReader for this type of file.
*/
public static boolean isReadSupportedImage(String filename) {
int index = filename.lastIndexOf('.');
if (index > 0) {
String fileSuffix = filename
.substring(index + 1, filename.length()).toLowerCase();
if (supportedReadFileTypes.contains(fileSuffix)) {
return true;
}
}
return false;
}
/** @param extension the extension to determen if there is an image writer for */
public static boolean isWriteSupportedImage(String extension) {
return supportedWriteFileTypes.contains(extension);
}
/**
* Get the resolution for an image, note: isReadSupportedImage must be true
* for this file and file must exists.
*
* @param file
* @return A Dimension holding the width and height of this image
*/
public static Dimension getResolution(File file) {
if (!isReadSupportedImage(file.getName())) {
throw new IllegalStateException("unsuported image format: " + file);
}
if (!file.exists()) {
throw new IllegalStateException("File must exists: " + file);
}
try {
int index = file.getName().lastIndexOf('.');
if (index > 0) {
String fileSuffix = file.getName().substring(index + 1,
file.getName().length());
ImageReader reader = getReader(fileSuffix);
ImageInputStream iis = ImageIO.createImageInputStream(file);
reader.setInput(iis, true);
int imageIndex = 0;
int width = reader.getWidth(imageIndex);
int height = reader.getHeight(imageIndex);
iis.close();
reader.dispose();
return new Dimension(width, height);
}
} catch (Exception e) {
log.log(Level.FINER, "Unable to read image: " + file.getAbsolutePath(), e);
}
return null;
}
public static BufferedImage getImage(File file) {
if (!isReadSupportedImage(file.getName())) {
throw new IllegalStateException("unsuported image format: " + file);
}
if (!file.exists()) {
throw new IllegalStateException("File must exists: " + file);
}
try {
int index = file.getName().lastIndexOf('.');
if (index > 0) {
String fileSuffix = file.getName().substring(index + 1,
file.getName().length());
ImageReader reader = getReader(fileSuffix);
ImageInputStream iis = ImageIO.createImageInputStream(file);
reader.setInput(iis, true);
int imageIndex = 0;
BufferedImage image = reader.read(imageIndex, null);
iis.close();
reader.dispose();
return image;
}
} catch (Exception e) {
log.log(Level.FINER, "Unable to read image: " + file.getAbsolutePath(), e);
}
return null;
}
private static ImageReader getReader(String fileSuffix) {
Iterator<ImageReader> readers = ImageIO
.getImageReadersByFormatName(fileSuffix);
return readers.next();
}
public static void clearCache() {
if (lastImage != null) {
lastImage.flush();
lastImage = null;
}
if (lastResizedImage != null) {
lastResizedImage.flush();
lastResizedImage = null;
}
lastWidth = -1;
lastHeight = -1;
lastScalingType = -1;
}
/**
* Constrains an Image (or BufferedImage) to a specific width and heigth; if
* the source image is smaller than width X height then its size is
* increased to fit
*/
public static Image constrain(BufferedImage src, int width, int height,
int scalingType)
{
if (src == lastImage && width == lastWidth && height == lastHeight
&& scalingType == lastScalingType)
{
return lastResizedImage;
}
clearCache();
lastWidth = width;
lastHeight = height;
lastImage = src;
lastScalingType = scalingType;
try {
// Get the source Image dimensions
int srcWidth = src.getWidth(null);
int srcHeight = src.getHeight(null);
// Compute the width to height ratios of both the source and the
// constrained window
double srcRatio = (double) srcWidth / (double) srcHeight;
double windowRatio = (double) width / (double) height;
// These variables will hold the destination dimensions
int destWidth = width;
int destHeight = height;
if (windowRatio < srcRatio) {
// Bind the height image to the height of the window
destHeight = (int) ((double) width / (double) srcWidth * srcHeight);
} else {
// Bind the width of the image to the width of the window
destWidth = (int) ((double) height / (double) srcHeight * srcWidth);
}
if (scalingType == Image.SCALE_FAST) {
// seams faster this way than "Image.getScaledInstance"
// Create a new BufferedImage and paint our source image to it
BufferedImage destImage = new BufferedImage(destWidth,
destHeight, BufferedImage.TYPE_USHORT_565_RGB);
Graphics g = destImage.getGraphics();
g.drawImage(src, 0, 0, destWidth, destHeight, null);
g.dispose();
lastResizedImage = destImage;
return destImage;
}
Image destImage = src.getScaledInstance(destWidth, destHeight,
scalingType);
lastResizedImage = destImage;
return destImage;
} catch (Exception e) {
log.log(Level.SEVERE, "Exception", e);
}
return null;
}
}