Cómo Utilizar un Filtro de Imagen

El siguiente applet utiliza un filtro para rotar una imagen. El filtro es uno personalizado llamado RotateFilter que podrás ver explicado en la página siguiente. Todo lo que necesitas saber sobre el filtro para utilizarlo es que su constructor toma un sólo argumento double: el ángulo de rotación en radianes. El applet convierte el número que introduce el usuario de grados a radianes, para que el applet pueda construir un RotateFilter.

Abajo tienes el código fuente que utiliza el filtro. (Aquí tienes el programa completo.)

public class ImageRotator extends Applet {
    . . .
    RotatorCanvas rotator;
    double radiansPerDegree = Math.PI / 180;

    public void init() {
        //Carga la imagen.
        Image image = getImage(getCodeBase(), "../images/rocketship.gif");

        ...//Crea el componente que utiliza el filtro de imagen:
        rotator = new RotatorCanvas(image);
        . . .
        add(rotator);
        . . .
    }

    public boolean action(Event evt, Object arg) {
        int degrees;

        ...//obtiene el número de grados que se tiene que rotar la imagen.

        //Lo convierte a Radianes.
        rotator.rotateImage((double)degrees * radiansPerDegree);

        return true;
    }
}

class RotatorCanvas extends Canvas {
    Image sourceImage;
    Image resultImage;

    public RotatorCanvas(Image image) {
        sourceImage = image;
        resultImage = sourceImage;
    }

    public void rotateImage(double angle) {
        ImageFilter filter = new RotateFilter(angle);
        ImageProducer producer = new FilteredImageSource(
                                        sourceImage.getSource(),
                                        filter);
        resultImage = createImage(producer);
        repaint();
    }

    public void paint(Graphics g) {
        Dimension d = size();
        int x = (d.width - resultImage.getWidth(this)) / 2;
        int y = (d.height - resultImage.getHeight(this)) / 2;

        g.drawImage(resultImage, x, y, this); 
    }
}

Cómo trabaja el Código

Para utilizar un filtro de imagen, un programa debe seguir los siguientes pasos:
  1. Obtener un objeto Image (normalmente se hace con el método getImage()).
  2. Utilizando el método getSource(), obtiene la fuente de los datos (un ImageProducer) para el objeto Image.
  3. Crea un ejemplar del filtro de imagen, inicializando el filtro si es necesario.
  4. Crea un objeto FilteredImageSource, pasando al constructor la fuente de la imagen y el objeto del filtro.
  5. Con el método createImage() del componente, crea un nuevo objeto Image que tiene el FilteredImageSource como su productor de imagen.

Esto podría sonar complejo, pero realmente es sencillo de implementar. Lo realmente complejo está detrás de la escena, como explicaremos un poco más tarde. Primero explicaremos el código del applet que utiliza el filtro de imagen.

En el applet de ejemplo, el método rotateImage() de RotatorCanvas realiza la mayoría de las tareas asociadas con el uso del filtro de imagen. La única excepción es el primer paso, obtener el objeto Image original, que es realizado por el método init() del applet. Este objeto Image es pasado a RotatoCanvas, que se refiere a él como sourceImage.

El método rotateImage() ejemplariza el filtro de imagen llamando al constructor del filtro. El único argumento del constructor es el ángulo, en radianes, que se va a rotar la imagen.

ImageFilter filter = new RotateFilter(angle);
Luego, el método rotateImage() crea un ejemplar de FilteredImageSource. El primer argumento del constructor de FilteredImageSource es la fuente de la imagen, obtenida con el método getSource(). El segundo argumento es el objeto filtro.
ImageProducer producer = new FilteredImageSource(
                                sourceImage.getSource(),
                                filter);
Finalmente, el código crea una segunda Imagen, resultImage, llamando al método createImage() de la clase Component. El único argumento de createImage() es el objeto FilteredImageSource creado en el paso anterior.
resultImage = createImage(producer);

Qué sucede detrás de la escena

Esta sección explica cómo trabaja el filtrado de la imagen, detrás de la escena. Si no te interesan estos detalles de la implementación, puedes saltar a Donde Encontrar Filtros de Imagen.

Lo primer que necesitas saber es que el AWT utiliza ImageConsumer detrás de la escena, en respuesta a una petición a drawImage(). Por eso el Componente que muestra la imagen no es el consumidor de imagen -- alguno objeto peofundo del AWT es el consumidor de imagen.

La llamada anterior a createImage() selecciona una Imagen (resultImage) que espera obtener los datos desde su productor, el ejemplar de FilteredImageSource. Aquí tienes lo que parecería el path de los datos de la imagen, desde la perspectiva de resultImage():

La línea punteada indica que el consumidor de imagen realmente nunca obtiene los datos del FilteredImageSource. En su lugar, cuando el consumidor pide datos de la imagen (en respuesta a g.drawImage(resultImage,...)), el FilteredImageSource realiza algún escamoteo y luego lo disocia de alguna manera. Aquí tienes la magia realizada por FilteredImageSource:

  • Crea un nuevo objeto del filtro de imagen invocando al método getFilterInstance() en el objeto filtro que se le ha pasado al constructor de FilteredImageSource. Por defecto, getFilterInstance() clona el objeto filtro.
  • Conecta el nuevo filtro de imagen al consumidor de imagen.
  • Conecta la fuente de los datos de la imagen, que se ha pasado al constructor de FilteredImageSource, al filtro de imagen.

Aquí tienes el resultado:

Dónde Encontrar Filtros de Imagen

Entonces, ¿donde puedes encontrar filtros de imagen existentes? El paquete java.awt.image incluye un filtro listo para utilizar, CropImageFilter, que produce una imagen que consite en un región rectangular de la imagen original. También puede encontrar varios filtros de imagen utilizados por applets en la website se sun. Todas estas páginas incluyen enlaces al código fuente de los applets que utilizan un filtro de imagen:
  • La página Generación Dinámica de Etiquetas de Color contiene dos applets que modifican el color de una imagen. El primer applet, AlphaBulet, define y utiliza un AlphaColorFilter; el segundo HueBullet, define y utiliza HueFilter.
  • La página Realimentación en directo de Imagemap demuestra un applet que mapea una imagen. Utiliza muchos filtros para porporcionan realimentación visual cuando el cursor se mueve sobre ciertas áreas o cuando el usuario pulsa un área especial.
  • La página Prueba de Imagen realiza una variedad de procesos de imágenes. Además de permitir al usuario escalar o mover la imagen, define y utiliza tres filtros. El AlphaFilter hace la imagen transparente, el RedBlueSwapFilter cambia los colores de la iamgn y el RotateFilter rota la imagen, como has podido ver en esta sección.


Ozito