package org.korsakow.services.encoders.image;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import org.korsakow.services.encoders.FileExternalEncoder;
public class JavaImageIOImageEncoder extends FileExternalEncoder implements ImageEncoder
{
public static class JavaImageIOEncoderDescription implements ImageEncoder.ImageEncoderDescription
{
public Class<? extends ImageEncoder> getEncoderClass() {
return JavaImageIOImageEncoder.class;
}
private static final Collection<ImageFormat> inputFormats = Collections.unmodifiableCollection(Arrays.asList(
ImageFormat.JPG, ImageFormat.PNG
));
private static final Collection<ImageFormat> outputFormats = Collections.unmodifiableCollection(Arrays.asList(
ImageFormat.JPG, ImageFormat.PNG
));
public Collection<ImageFormat> getSupportedInputFormats() {
return inputFormats;
}
public Collection<ImageFormat> getSupportedOutputFormats() {
return outputFormats;
}
}
protected Integer width;
protected Integer height;
public void encode(File sourceFile, ImageFormat dstFormat, File destFile) throws ImageEncoderException
{
BufferedImage image;
try {
image = ImageIO.read(sourceFile);
} catch (IOException e) {
throw new ImageEncoderException(e);
}
if (width != null && height != null) {
image = getScaledInstance(image, width, height, RenderingHints.VALUE_INTERPOLATION_BICUBIC, false);
}
try {
if (!ImageIO.getImageWritersByFormatName(getFormatName(dstFormat)).hasNext())
throw new ImageEncoderException("No Image writer for : " + getFormatName(dstFormat));
ImageWriter writer = ImageIO.getImageWritersByFormatName(getFormatName(dstFormat)).next();
ImageWriteParam params = writer.getDefaultWriteParam();
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
params.setCompressionQuality(1);
writer.setOutput(new FileImageOutputStream(destFile));
writer.write(null, new IIOImage(image, null, null), params);
} catch (IOException e) {
throw new ImageEncoderException(e);
}
}
public String getFileExtension(ImageFormat format) throws ImageEncoderException
{
switch (format)
{
case JPG: return "jpg";
case PNG: return "png";
}
throw new ImageEncoderException("unknown format: " + format);
}
public Object getEncoderSpecificOption(Object name) throws UnsupportedOperationException
{
throw new UnsupportedOperationException();
}
public void setEncoderSpecificOption(Object name, Object value) throws UnsupportedOperationException
{
throw new UnsupportedOperationException();
}
public void setSize(Integer width, Integer height) throws UnsupportedOperationException
{
this.width = width;
this.height = height;
}
private static String getFormatName(ImageFormat format) throws ImageEncoderException
{
switch (format)
{
case JPG: return "jpeg";
case PNG: return "png";
}
throw new ImageEncoderException("unknown format: " + format);
}
/**
* http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
*/
public BufferedImage getScaledInstance(
BufferedImage img,
int targetWidth,
int targetHeight,
Object hint,
boolean higherQuality)
{
int type = (img.getTransparency() == Transparency.OPAQUE) ?
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage ret = img;
int w, h;
if (higherQuality) {
// Use multi-step technique: start with original size, then
// scale down in multiple passes with drawImage()
// until the target size is reached
w = img.getWidth();
h = img.getHeight();
} else {
// Use one-step technique: scale directly from original
// size to target size with a single drawImage() call
w = targetWidth;
h = targetHeight;
}
do {
if (higherQuality && w > targetWidth) {
w /= 2;
if (w < targetWidth) {
w = targetWidth;
}
}
if (higherQuality && h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, type);
Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(ret, 0, 0, w, h, null);
g2.dispose();
ret = tmp;
} while (w != targetWidth || h != targetHeight);
return ret;
}
}