package com.im.imjutil.media.image;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.Collection;
import java.util.Properties;
import com.im.imjutil.exception.ImageEditingException;
import com.im.imjutil.exception.ValidationException;
import com.im.imjutil.media.image.Image.Anchor;
import com.im.imjutil.media.image.Image.Color;
import com.im.imjutil.media.image.Image.Format;
import com.im.imjutil.validation.Convert;
import com.im.imjutil.validation.Validator;
/**
* Classe estatica de fachada responsavel por editar imagens {@link Image},
* aplicando transformacoes {@link Transform} nas mesmas. Esta aplica
* transformacoes geometricas (redimencionar, rotacionar, virar, recortar),
* de cores (preto e branco, escala de cinza, sepia, RGB, IHS) e
* de ajustes (automatico, brilho, contraste, nitidez, turvez, niveis).
* Esta possui funcoes para abrir, salvar, criar e editar uma ou varias
* imagens vindas de um arquivo {@link File} ou de um stream {@link InputStream},
* em diversos formatos (GIF, JPG, PNG, TIFF, BMP).
*
*
* @author Felipe Zappala
*/
public final class ImageEditor {
/**
* Proibido a instanciacao
*/
private ImageEditor() {
super();
}
/** Arquivo de propriedades com as classes de transformacoes disponiveis */
private static Properties transforms;
static {
transforms = new Properties();
}
/**
* Registra novas ou subistitui as transformacoes cadastradas no editor.
*/
public static void register(String name, Class<? extends Transform> clazz) {
if (Validator.isValid(name, clazz)) {
transforms.put(name, clazz.getName());
}
}
/**
* Instancia uma transformacao pelo nome registrada no arquivo
* de propriedades de transformacoes disponiveis.
*/
public static Transform transform(String name)
throws ImageEditingException {
try {
if (transforms.isEmpty()) {
transforms.load(ImageEditor.class
.getResourceAsStream("transforms.properties"));
}
if (!Validator.isValid(name)) {
throw new ValidationException(Convert.toString(
"Nome de transformacao invalido [", name, "]"
));
}
String className = transforms.getProperty(name.trim());
if (!Validator.isValid(className)) {
throw new ValidationException(Convert.toString(
"Transformacao nao encontrada com o nome [", name, "]"
));
}
Class<?> clazz = Class.forName(className);
Constructor<?> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
return (Transform) constructor.newInstance();
} catch (Exception e) {
throw new ImageEditingException(Convert.toString(
e.getClass().getSimpleName(), ": ", e.getMessage()), e);
}
}
/**
* Aplica uma transformacao a uma imagem.
*/
public static Image apply(Transform transform, Image image, Object... params)
throws ImageEditingException {
return transform.apply(image, params);
}
/**
* Aplica varias transformaces a uma imagem.
*/
public static Image apply(Collection<Transform> transforms, Image image)
throws ImageEditingException {
Image result = image;
for (Transform transform : transforms) {
result = transform.apply(result);
}
return result;
}
/**
* Cria uma imagem a partir de uma {@link RenderedImage}.
*/
public static Image create(RenderedImage image)
throws ImageEditingException {
return transform("create").apply(null, "source", image);
}
/**
* Cria uma {@link RenderedImage} a partir de uma imagem.
*/
public static RenderedImage create(Image image)
throws ImageEditingException {
return image.getSource();
}
/**
* Abre uma imagem de uma URL.
*/
public static Image open(URL url)
throws ImageEditingException {
return transform("open").apply(null, "url", url);
}
/**
* Abre uma imagem de um arquivo.
*/
public static Image open(File file)
throws ImageEditingException {
return transform("open").apply(null, "file", file);
}
/**
* Abre uma imagem de um stream.
*/
public static Image open(InputStream stream)
throws ImageEditingException {
return transform("open").apply(null, "stream", stream);
}
/**
* Abre uma imagem de um byte[].
*/
public static Image open(byte[] bytes)
throws ImageEditingException {
return transform("open").apply(null, "bytes", bytes);
}
/**
* Grava uma imagem em um arquivo.
*/
public static Image save(Image image, File file)
throws ImageEditingException {
return transform("save").apply(image, "file", file);
}
/**
* Grava uma imagem em um stream.
*/
public static Image save(Image image, OutputStream stream)
throws ImageEditingException {
return transform("save").apply(image, "stream", stream);
}
/**
* Recorta uma imagem.
*/
public static Image crop(Image image, float x, float y,
float width, float height) throws ImageEditingException {
return transform("crop").apply(image, x, y, width, height);
}
/**
* Vira uma imagem na horizontal.
*/
public static Image horizontalFlip(Image image)
throws ImageEditingException {
return transform("flip").apply(image, "horizontal");
}
/**
* Vira uma imagem na vertical.
*/
public static Image verticalFlip(Image image)
throws ImageEditingException {
return transform("flip").apply(image, "vertical");
}
/**
* Redimenciona uma imagem.
*/
public static Image resize(Image image, int width, int height)
throws ImageEditingException {
return transform("resize").apply(image, width, height);
}
/**
* Escalona uma imagem.
*/
public static Image scale(Image image, float factor)
throws ImageEditingException {
return transform("scale").apply(image, factor);
}
/**
* Converte o formato de uma imagem.
*/
public static Image convert(Image image, Format format, Color color)
throws ImageEditingException {
return transform("convert").apply(image, "both", format, color);
}
/**
* Converte o formato de uma imagem.
*/
public static Image convert(Image image, Format format)
throws ImageEditingException {
return transform("convert").apply(image, "format", format);
}
/**
* Converte o modo de cor de uma imagem.
*/
public static Image convert(Image image, Color color)
throws ImageEditingException {
return transform("convert").apply(image, "color", color);
}
/**
* Rotaciona uma imagem.
*/
public static Image rotate(Image image, int degrees)
throws ImageEditingException {
return transform("rotate").apply(image, degrees);
}
/**
* Ajusta automaticamente uma imagem.
*/
public static Image adjust(Image image)
throws ImageEditingException {
return transform("adjust").apply(image);
}
/**
* Concatena varias imagem em uma unica.
*/
public static Image concat(Collection<Image> images)
throws ImageEditingException {
return transform("concat").apply(null, images);
}
/**
* Compoe varias imagens em uma tela personalizavel.
*/
public static Image compose(Collection<Image> images, int width, int height,
float opacity, Color color, Format format, Anchor anchor)
throws ImageEditingException {
return transform("compose").apply(null, images,
width, height, opacity, color, format, anchor);
}
/**
* Retorna um array com os dados do histograma no formato:
* {@code int[bands][bins=256]}.
*/
public static int[][] histogram(Image image)
throws ImageEditingException {
Image dummyImage = transform("histogram").apply(image, 256);
return dummyImage.getProperty("histogram");
}
}