Beruflich Dokumente
Kultur Dokumente
INTRODUCCION:
El API de java avanzado de imagen lleva a cabo un juego de imagen del centro que
procesa capacidades incluyendo imagen azulada, regiones de interés, hilando y la
ejecución diferido. JAI también ofrece un juego de imagen del centro que procesa a
operadores que incluyen a muchos puntos en común, área y operadores del dominio de
la frecuencia.
JAI encapsula los datos de la estructura de la imagen y las invocaciones del método
remoto dentro de los datos de la imagen re-utilizables, permitiendo un archivo de la
imagen, un objeto de imagen de red o los datos del real-tiempo que vierten para ser
procesados idénticamente. JAI sigue una carrera de tiempo de la biblioteca modelo de
java, mientras proporciona la independencia de la plataforma con el paradigma "escriba
una vez, ejecute en cualquier parte." El imaging del cliente-servidor se apoya por vía de
la plataforma de Java que está conectando a una red de computadoras y tecnologías de
ejecución remotas. La ejecución remota es basada en Java RMI (método remoto de
invocación). Esto permite que el código de Java en un cliente invoque las llamadas del
método en objetos que residen en otra computadora sin tener que mover aquéllos
objetos al cliente.
JAI sigue un modelo objeto dónde las imágenes y operadores de imagen son definidas
como objetos subclasificados fuera de un padre común. Un objeto del operador es el
instanciado con uno o más fuentes de la imagen y otros parámetros. Este objeto del
operador puede volverse una fuente de la imagen entonces para el próximo objeto del
operador. Las conexiones entre los objetos definen el flujo de datos procesados. Pueden
definirse los gráficos del editable resultantes de imagen que procesa los
funcionamientos e instanciado como necesitado. JAI también proporciona un armazón
extensible que permite agregar las soluciones personalizadas al central API.
Interfaces:
Las clases que implementa el interfaz ImageProducer sirven como fuentes de pixels.
Los métodos de estas clases pueden generar los pixels a partir de la pantalla, o puede
interpretar cualquier otra fuente de datos, como un fichero GIF. No importa cómo
genere los datos, el principal propósito de un productor de imágenes es proporcionar
pixels a una clase ImageConsumer.
La clase ColorModel
Un modelo de color es necesario porque hay muchos métodos que reciben un array de
bytes y convierten esos bytes en pixeles para su presentación en pantalla, es decir,
convierten los bytes de datos en pixels visuales sobre la pantalla. Por ejemplo, con un
modelo de color directo simple, cada grupo de cuatro bytes se podría interpretar como la
representación de un valor del color de un pixel individual. En un modelo de color
indexado simple, cada byte en el array se podría interpretar como un índice a una tabla
de enteros de 32 bits donde cada uno de esos enteres representa el valor del color
adscrito al pixel.
La clase IndexColorModel:
La clase DirectColorModel:
La clase FilteredImageSource
Esta clase es una implementación del interfaz ImageProducer que toma una imagen y
un objeto de tipo ImageFilter para generar una nueva imagen que es una versión
filtrada de la imagen original. Las operaciones de filtrado pueden realizar una gran
variedad de operaciones, como son el desplazamiento y sustitución de colores, la
rotación de imágenes, etc.
La clase ImageFilter
Hay varias subclases que extienden esta clase base para permitir la manipulación de la
imagen, como son RGBImageFilter, CropImageFilter, ReplicateScaleFilter y
AreaAveragingScaleFilter.
La clase MemoryImageSource
Esta clase es una implementación del interfaz ImageProducer que utiliza un array de
datos para generar los valores de los pixels de una imagen. Dispone de varios
constructores que son:
La clase PixelGrabber
Esta es una clase de utilidad para convertir una imagen en un array de valores que
corresponden a sus pixels. Implementa el interfaz ImageConsumer, que puede ser
acoplado a un objeto Image o ImageProducer para realizar cualquier manipulación de
esa imagen.
Métodos de Clipping
Clipping es el proceso por el que se define la zona del contexto gráfico en la que se van
a realizar las modificaciones de los subsiguientes procesos de dibujo. Cualquier pixel
que se encuentre fuera del área de clipping permanecerá inmune a toda modificación.
Los métodos que están involucrados son varios, unos que permiten fijar el rectángulo de
clipping y otros que permiten obtener la zona de clipping actual.
La clase Color
Esta clase es simple, encapsula los colores utilizando el formato RGB. En este formato,
los colores se definen por sus componentes Rojo, Verde y Azul, representado cada uno
de ellos por un número entero en el rango 0-255. En el caso del API Java2D, el espacio
de color que se usa es el sRGB, un estándar del consorcio W3.
Hay otro modelo de color llamado HSB (matiz, saturación y brillo). La clase Color
proporciona métodos de conveniencia para poder realizar la conversión entre un modelo
y otro sin dificultad.
La clase Color proporciona variables estáticas finales que permiten el uso de cualquiera
de los treinta colores, simplemente especificando su nombre. Para usar estas variables
sólo es necesario referencias el color por su nombre de variable, por ejemplo
objeto.setBackground( Color.red );
Los valores predefinidos para los colores en esta clase son los que se muestran en la
siguiente lista, todos ellos en el espacio sRGB:
• black, negro
• blue, azul
• cyan, azul celeste
• darkGray, gris oscuro
• gray, gris
• green, verde
• lightGray, gris claro
• magenta, violeta
• orange, naranja
• pink, rosa
• red, rojo
• white, blanco
• yellow, amarillo
Los constructores de esta clase son tres, dos de los cuales permiten instanciar un nuevo
objeto de tipo Color indicando las cantidades de rojo, verde y azul que entran en su
composición mediante valores enteros en el rango 0 a 255:
Color( int,int,int )
El otro de los constructores que permite especificar la contribución de rojo, verde y azul
al color final, admite valore flotantes en el rango 0.0 a 1.0:
Color( float,float,float )
Color( int )
Métodos que devuelven un entero representando el valor RGB para un determinado
objeto Color.
getRed(), devuelve el componente rojo del color como un entero en el rango 0 a 255.
getGreen(), devuelve la cantidad de verde que entra en la composición del objeto Color,
en el rango 0 a 255.
getBlue(), devuelve el componente azul del color con un entero en el rango 0 a 255.
getRGB(), devuelve un entero representando el color RGB, utilizando los bits para
indicar la cantidad de cada uno de los componentes rojo, verde y azul que entran en su
composición. Los bits 24 a 31 del entero que devuelve el método son 0xff, los bits 16 a
23 son el valor rojo, los bits 8 a 15 son el valor verde y los bits 0 a 7 indican el valor del
color azul. Siempre en el rango 0 a 255.
Los siguiente métodos devuelven un objeto de tipo Color, de forma que se pueden
utilizar para crear objetos de este tipo.
Los métodos que se indican a continuación, también devuelven un objeto de tipo Color,
pero están especializados para trabajar con el sistema a través de la clase Properties.
getColor( String ), busca un color entre las propiedades del sistema. El objeto String se
utiliza como el valor clave en el esquema clave/valor utilizado para describir las
propiedades en Java. El valor es entonces utilizado para devolver un objeto Color.
getColor( String,Color ), busca un color entre las propiedades del sistema. El segundo
parámetro es el que se devuelve en el caso de que falle la búsqueda de la clave indicada
en el objeto String.
getColor( String,int ), busca un color entre las propiedades del sistema. El segundo
parámetro es utilizado para instanciar y devolver un objeto Color en el caso de que falle
la búsqueda de la clave indicada en el objeto String.
Los siguientes métodos se utilizan para realizar la conversión entre el modelo de color
RGB y el modelo HSB.
Y ya, los métodos que quedan son métodos de utilidad general, sin ninguna aplicación
específica en lo que al Color respecta.
El método drawImage():
Este método es el que se utiliza para presentar una imagen en pantalla; aunque hay
métodos de otras clases que son utilizados para la manipulación de imágenes en Java, lo
primero que se necesita es saber cómo se visualiza una imagen, y eso es lo que hace este
método drawImage() de la clase Graphics.
drawImage( Image,int,int,int,int,int,int,int,int,Color,ImageObserver ).
drawImage( Image,int,int,int,int,int,int,int,int,ImageObserver ).
Ejemplo llamada a metodo:
int x,
int y,
int width,
int height,
ImageObserver observer )
En esta versión del método, la imagen se pintará dentro del rectángulo que se para en
los parámetros y se escalará si es necesario. El método retorna inmediatamente, incluso
aunque la imagen no se haya terminado de escalar o convertir al formato que admita el
dispositivo de salida. Si esta conversión no se ha completado, drawImage() devuelve
false, y como hay parte de imagen que no está procesada, el proceso que pinta la imagen
notifica al observador a través de su método imageUpdate() y esa imagen continúa
pintándose por trozos.
De los parámetros que se pasan al método drawImage(), todos resultan obvios, excepto
quizá, el último de ellos, observer, que se refiere al objeto que debe ser notificado
cuando la imagen esté disponible. Cuando se realiza una llamada a drawImage(), se
lanza una tarea que carga la imagen solicitada. Hay un observador que monitoriza el
proceso de carga; la tarea que está cargando la imagen notifica a ese observador cada
vez que llegan nuevos datos. Para este parámetro se puede utilizar perfectamente this
como observador en la llamada a drawImage(); es más, se puede decir que cualquier
componente puede servir como observador para imágenes que se pintan sobre él. Quizá
sea este el momento de entrar un poco más en detalle en la clase ImageObserver, e
incluso antes en la clase Image, porque son los dos parámetros diferentes del típico
entero que aparecen en la llamada a drawImage().
La clase Image:
La clase Image, como cualquier otra, está formada por una serie de constantes o
variables, constructores y métodos. Uno de estos métodos es getScaledInstance(), que
devuelve una versión escalada de una imagen. Uno de los parámetros de este método es
un valor entero que especifica el algoritmo a utilizar para la realización del escalado. Se
puede utilizar cualquiera de ellos, la tabla siguiente muestra su nombre y una pequeña
descripción, si el lector necesita más detalles, debe recurrir como siempre se
recomienda, a la documentación del JDK.
Aunque la clase Image dispone de un constructor, es una clase abstracta, por lo que no
se puede instanciar ningún objeto llamando directamente a este constructor. Se puede
conseguir un objeto Image indirectamente por la invocación del método getImage() de
las clases Applet o Toolkit. El método getImage() utiliza un hilo de ejecución, o tarea,
separado para cargar la imagen. El resultado práctico de la invocación a getImage(), es
la asociación entre una referencia de tipo Image y un fichero localizado en algún lugar
que contiene la imagen que interesa. Otra forma de obtener un objeto Image es invocar
al método createImage(), de las clases Component y Toolkit. La lista siguiente
muestra una pequeña descripción de los métodos de la clase Image:
getGraphics(), crea un contexto gráfico para pintar una imagen en segundo plano
El interfaz ImageProducer:
Se trata de un interfaz para objeto que pueden producir imágenes para la clase Image.
Cada imagen contiene un ImageProducer que se utiliza en la reconstrucción de esa
imagen cuando es necesario; por ejemplo, cuando se escala la imagen, o cuando se
cambia la imagen de tamaño
La clase MediaTracker:
Esta es una clase de utilidad general diseñada para controlar el estado de los objetos de
tipo media, que en teoría pueden ser tanto clips de sonido como cualquier otro objeto
media, como es el caso de una imagen.
MediaTracker( Component ):
addImage( Image,int ), incorpora una nueva imagen a la lista de imágenes que está
siendo controlada por el objeto MediaTracker.
El objeto MediaTracker se puede utilizar para hacer que la tarea, o hilo de ejecución,
se bloquee hasta que una o más imágenes de su lista haya completado su carga. Esto se
consigue con los siguientes métodos.
waitForAll( long ), inicia la carga de todas la imágenes, devolviendo true si todas las
imágenes se han cargado y false en cualquier otro caso.
waitForID( int ), inicia la carga de las imágenes que corresponden al identificador que
se pasa; devuelve void.
Por supuesto, es posible utilizar métodos que no bloquean la tarea que carga las
imágenes para comprobar el estado de una o más imágenes de la lista. Esto permite
continuar haciendo el trabajo mientras las imágenes siguen cargándose. Estos métodos
devuelven true o false para indicar si la carga es completa. La versión con el parámetro
booleano comenzará la carga de cualquier imagen que no se esté cargando, en caso de
que ese parámetro booleano sea true. La otra versión no iniciará la carga de ninguna
imagen. Esta interpretación también es válida para el parámetro booleano de otros
métodos de la clase que disponen de él.
checkAll() y checkAll( boolean ), comprueban si todas las imágenes que están siendo
controladas por el objeto MediaTracker han finalizado la carga.
El hecho de que los métodos anteriores indiquen que la carga de las imágenes ha sido
completa, no garantiza que esa carga esté libre de errores. Los siguiente métodos se
utilizan para determinar si se ha producido algún problema durante la carga de las
imágenes.
getErrorsAny(), devuelve una lista de todas las imágenes (o cualquier media) en los que
se ha producido un error en la carga.
Los dos siguientes métodos devuelven un valor entero formado por la operación OR
entre los valores de estado de todas las imágenes que se requieren; en el primero de
todas las que controla el objeto MediaTracker, y en el segundo de las que
corresponden al identificador que se especifica.
statusAll( boolean )
statusID( int,boolean )
Imágenes
Sistema de Coordenadas
Construir un área geométrica (CAG) es el proceso de crear una nueva forma geométrica
realizando operaciones con las ya existentes. En el API Java 2D un tipo especial de
Shape llamado Area soporta operaciones booleanas. Podemos construir un Area desde
cualquier Shape .
Unión Subtracción
En este ejemplo, los objetos Area construyen una forma de pera partiendo de varias
elipses.
Gráficos en 2 Dimensiones:
Por ejemplo, se podria mostrar gráficos y charts complejos que usan varios estilos de
línea y de relleno para distinguir conjuntos de datos, como se muestra en la siguiente
figura:
Las clases del paquete java.awt.geom definen gráficos primitivos comunes, como
puntos, líneas, curvas, arcos, rectángulos y elipses.
Excepto para Point2D y Dimension2D, cada una de las otras clases geométricas
implementa el interface Shape, que proporciona un conjunto de métodos comunes para
describir e inspeccionar objetos geométricos bi-dimensionales.
Con estas clases se puede crear de forma virtual cualquier forma geométrica y dibujarla
a través de Graphics2D llamando al método draw o al método fill. Por ejemplo, las
formas geométricas del siguiente applet están definidas usando los geométricos básicos
de Java 2D.
Formas Rectangulares
La clase QuadCurve2D nos permite crear segmentos de curvas cuadráticos. Una curva
cuadrática está definida por dos puntos finales y un punto de control.
La clase CubicCurve2D nos permite crear segmentos de curvas cúbicos. Una curva
cúbica está definida por dos puntos finales y dos puntos de control. Las siguientes
figuras muestran ejemplos de curvas cuadráticas y cúbicas.
GeneralPath
La clase GeneralPath permite crear una curva arbitraria especificando una serie de
posiciones a lo largo de los límites de la forma. Estas posiciones pueden ser conectadas
por segmentos de línea, curvas cuadráticas o curvas cúbicas. La siguiente figura puede
ser creada con 3 segmentos de línea y una curva cúbica.
Areas
Renderizado en Java 2D
Para usar las características del API 2D de Java, se forza el objeto Graphics pasado al
método de dibujo de un componente a un objeto Graphics2D.
gp = new GradientPaint(0f,0f,blue,0f,30f,green);
g2.setPaint(gp);
Componer Gráficos:
Source-over (SRC_OVER) Si los pixels del objeto que está siendo renderizado (la
fuente) tienen la misma posición que los pixels
renderizados préviamente (el destino), los pixels de la
fuente se renderizan sobre los pixels del destino.
Source-in (SRC_IN) Si los pixels de la fuente y el destino se solapan, sólo se
renderizarán los pixels que haya en el área solapada.
AlphaComposite ac =
AlphaComposite.getInstance(AlphaComposite.SRC);
ac = AlphaComposite.getInstance(getRule(rule), alpha);
BufferedImage.TYPE_INT_ARGB);
gbi.setComposite(ac);
Mostrar y Manipular Imágenes
Esta lección muestra cómo realizar operaciones de filtrado con BufferedImages y cómo
usar un BufferedImage como un buffer fuera de pantalla.
Filtrado y BufferedImage
Esta sección muestra cómo usar las clases BufferedImageOp para realizar operaciones
de filtrado sobre BufferedImage.
Esta sección nos enseña cómo usar un BufferedImage como un buffer fuera de pantalla
para aumentar el rendimiento de las imágenes.
BufferedImage es la clase clave del API del modo-inmediato. Esta clase maneja una
imagen en memoria y proporciona métodos para almacenar, interpretar y dibujar cada
dato de pixel. Un BufferedImage puede ser renderizado en un contexto Graphics o on
un contexto Graphics2D.
Filtrar un BufferedImage
El API Java 2D define varias operaciones de filtrado para objetos BufferedImage . Cada
operación de proceso de imágenes está incluida en una clase que implementa el
interface BufferedImageOp. La manipulación de imágenes se realiza en el método filter.
La clase BufferedImageOp en el API Java 2D soporta:
• Tranformación afin.
• Escalado.
• Modificación de Aspecto.
• Combinación Linear de Bandas.
• Conversión de color.
• Convolución.
Ejemplo: ImageOps
Para construir y aplicar este tipo de filtrado al BufferedImage, este ejemplo usa un
código similar al del siguiente fragmento.
BufferedImage(iw,ih,BufferedImage.TYPE_INT_RGB);
Kernel kernel = new Kernel(3,3,SHARPEN3x3);
ConvolveOp.EDGE_NO_OP,
null);
cop.filter(srcbimg,dstbimg);
Para permitir que el usuario interactúe con los graficos que se dibujan, se requiere
poder determinar cuando el usuario pulsa sobre uno de ellos. El método hit de
Graphics2D proporciona una forma para determinar fácilmente si ha ocurrido una
pulsación de ratón sobre una Shape particular. De forma alternativa podemos obtener la
posición del click de ratón y llamar a contains sobre la Shape para determinar si el click
ocurrió dentro de los límites de la Shape.
Ejemplo: ShapeMover
Este applet permite al usuario arrastrar la Shape por la ventana del applet. La Shape se
redibuja en cada nueva posición del ratón para proporcionar información al usuario
mientras la arrastra.
Se llama al método contains para determinar si el cursor está dentro de los límites del
rectángulo cuando se pulsa el botón. Si es así, se actualiza la posición del rectángulo.
...
...
repaint();
Al redibujar la Shape en cada posición del ratón es muy lento, porque el rectángulo
relleno es renderizado cada vez que se mueve, Usando el doble buffer podemos eliminar
este problema. Si estamos usando Swing, el dibujo usará doble buffer automáticamente;
si no es así tendremos que cambiar todo el código de renderizado.
Ejemplo: HitTestSample
Esta aplicación ilustra la comprobación de pulsaciones dibujando el cursor por defecto
siempre que el usuario pulse sobre el TextLayout, como se muestra en la siguiente
figura.
Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El
applet aparecerá en una nueva ventana del navegador.
...
origin.y =
+ textLayout.getAscent())/2;
return origin;
...
super.paintComponent(g);
setBackground(Color.white);
graphics2D.translate(origin.getX(), origin.getY());
// Draw textLayout.
textLayout.draw(graphics2D, 0, 0);
graphics2D.setColor(STRONG_CARET_COLOR);
graphics2D.draw(carets[0]);
if (carets[1] != null) {
graphics2D.setColor(WEAK_CARET_COLOR);
graphics2D.draw(carets[1]);
}
}
...
/**
*/
// textLayout's origin.
insertionIndex = currentHit.getInsertionIndex();
hitPane.repaint();
Ejemplo: ClipImage
Este ejemplo anima un path de recortado para revelar diferentes porciones de una
imagen:
...
g2.setClip(ellipse);
g2.clip(rect);
Ejemplo: Starry
Un área de recortado también puede crearse desde una cadena de texto existente. El
siguiente ejemplo crea un TextLayout con la cadena The Starry Night. Luego, obtiene
una línea exterior del TextLayout. El método TextLayout.getOutline devuelve un objeto
Shape y un Rectangle creado a partir de los límites del objeto Shape. Los límites
contienen todos los pixels que layout puede dibujar. El color en el contexto gráfico se
selecciona a azul y se dibuja la figura exterior de la forma, como ilustran la siguiente
imagen y el fragmento de código.
Rectangle r = outline.getBounds();
transform = g2.getTransform();
transform.translate(w/2-(r.width/2), h/2+(r.height/2));
g2.transform(transform);
g2.setColor(Color.blue);
g2.draw(outline);
g2.setClip(outline);
El siguiente applet demuestra cómo podemos dibujar formas geométricas usando los
métodos Graphics2D draw y fill.
Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El
applet aparecerá en una nueva ventana del navegador.
Cada una de las formas dibujadas por el applet está construida de geometrías y está
dibujada a través de Graphics2D. Las variables rectHeight y rectWidth de este ejemplo
definen las dimensiones del espacio en que se dibuja cada forma, en pixels. La variables
x e y cambian para cada forma para que sean dibujadas en formación de parrilla.
// draw Line2D.Double
x + rectWidth, y));
// draw Rectangle2D.Double
g2.setStroke(stroke);
g2.draw(new Rectangle2D.Double(x, y,
rectWidth,
rectHeight));
// draw RoundRectangle2D.Double
g2.setStroke(dashed);
g2.draw(new RoundRectangle2D.Double(x, y,
rectWidth,
rectHeight,
10, 10));
// draw Arc2D.Double
g2.setStroke(wideStroke);
g2.draw(new Arc2D.Double(x, y,
rectWidth,
rectHeight,
90, 135,
Arc2D.OPEN));
// draw Ellipse2D.Double
g2.setStroke(stroke);
g2.draw(new Ellipse2D.Double(x, y,
rectWidth,
rectHeight));
// draw GeneralPath (polygon)
x, x+rectWidth};
y+rectHeight, y};
x1Points.length);
polygon.moveTo(x1Points[0], y1Points[0]);
index++) {
polygon.lineTo(x1Points[index],
y1Points[index]);
};
polygon.closePath();
g2.draw(polygon);
// draw GeneralPath (polyline)
x+rectWidth};
y+rectHeight, y};
GeneralPath(GeneralPath.WIND_EVEN_ODD,
x2Points.length);
index++) {
polyline.lineTo(x2Points[index],
y2Points[index]);
};
g2.draw(polyline);
// fill Rectangle2D.Double (red)
g2.setPaint(red);
g2.fill(new Rectangle2D.Double(x, y,
rectWidth, rectHeight));
// fill RoundRectangle2D.Double
g2.setPaint(redtowhite);
g2.fill(new RoundRectangle2D.Double(x, y,
rectWidth,
rectHeight,
10, 10));
// fill Arc2D
g2.setPaint(red);
rectHeight, 90,
135, Arc2D.OPEN));
// fill Ellipse2D.Double
g2.setPaint(redtowhite);
rectWidth,
rectHeight));
// fill and stroke GeneralPath
x+rectWidth};
y+rectHeight, y};
GeneralPath(GeneralPath.WIND_EVEN_ODD,
x3Points.length);
filledPolygon.moveTo(x3Points[0],
y3Points[0]);
index++) {
filledPolygon.lineTo(x3Points[index],
y3Points[index]);
};
filledPolygon.closePath();
g2.setPaint(red);
g2.fill(filledPolygon);
Observa que este ejemplo usa implementaciones de doble precision de las clases
geométricas. Donde sea posible, las implementaciones de los float y doble precisión de
cada geométrico están proporcionados por clases internas.
Dibujar Curvas
Los applets Cubic y Quad demuestran como crear curvas cúbicas y cuadráticas usando
CubicCurve2D y QuadCurve2D. Estos applets también demuestran como se dibujan las
curvas con respecto al posicionamiento de los puntos de control permitiendonos mover
interactivamente tanto los puntos de control como los puntos finales.
Ejemplo: Quad
El applet Quad demuestra una curva cuadrática, que es un segmento de curva que tiene
dos puntos finales y un único punto de control. El punto de control determina la forma
de la curva controlando tanto el punto de control como los vectores tangenciales de los
puntos finales.
Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El
applet aparecerá en una nueva ventana del navegador.
Primero se crea una nueva curva cuadrática con dos puntos finales y un punto de control
y las posiciones de los puntos se seleccionan con respecto al tamaño de la ventana.
start.setLocation(w/2-50, h/2);
end.setLocation(w/2+50, h/2);
control.setLocation((int)(start.x)+50, (int)(start.y)-50);
Cada vez que el usuario mueva uno de los puntos, la curva se reseteará.
Ejemplo: Cubic
El ejemplo Cubic muestra una curva cúbica, que es un segmento de curva que tiene dos
puntos finales y dos puntos de control. Cada punto de control determina la forma de la
curva mediante el control de uno de los vectores tangenciales de un punto final. En el
ejemplo Cubic, las cruces coloreadas se dibujan donde se encuentran los puntos de
control y los puntos finales. El punto de control azul controla el punto final rojo y el
punto de control verde controla el punto final magenta.
Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El
applet aparecerá en una nueva ventana del navegador.
...
start.setLocation(w/2-50, h/2);
end.setLocation(w/2+50, h/2);
one.setLocation((int)(start.x)+25, (int)(start.y)-25);
two.setLocation((int)(end.x)-25, (int)(end.y)+25);
Como en el ejemplo Quad, la curva es reseteada cada vez que se mueven los puntos.
Ejemplo: Odd_Shape
...
x = w/2 + 50;
y = h/2 - 25;
x2 = x;
y2 = y;
oddShape.moveTo(x, y);
x -= 100;
oddShape.lineTo(x, y);
y += 50;
oddShape.lineTo(x, y);
x += 100;
oddShape.lineTo(x, y);
x += 10;
y -= 10;
x1 = x - 20;
y1 = y - 20;
Estilos de Línea
Los estilos de línea están definidos por el atributo stroke en el contexto Graphics2D.
Para seleccionar el atributo stroke podemos crear un objeto BasicStroke y pasarlo
dentro del método Graphics2D setStroke.
JOIN_BEVEL
JOIN_MITER
JOIN_ROUND
CAP_ROUND
CAP_SQUARE
Patrón de Relleno
Los patrones de rellenos están definidos por el atributo paint en el contexto Graphics2D.
Para seleccionar el atributo paint, se crea un ejemplar de un objeto que implemente el
interface Paint y se pasa dentro del método Graphics2D setPaint.
Para crear un GradientPaint, se especifica una posición inicial y un color y una posición
final y otro color. El gradiente cambia proporcionalmente desde un color al otro a lo
largo de la línea que conecta las dos posiciones.
El patrón para una TexturePaint esta definido por un BufferedImage. Para crear un
TexturePaint, se especifica una imagen que contiene el patrón y un rectángulo que se
usa para replicar y anclar el patrón.
Ejemplo: StrokeAndFill
El applet StrokeAndFill permite al usuario seleccionar un gráfico primitivo, un estilo de
línea, un estilo de dibujo y o bien puntear el exterior del objeto, rellenarlo con el dibujo
seleccionado, o puntear el objeto en blanco y rellenar el dibujo con el dibujo
seleccionado.
Esta es una imagen del GUI del applet. Para ajecutar el applet, pulsa sobre ella. El
applet aparecerá en una nueva ventana del navegador.
Para crear un objeto Shape desde una cadena de texto, primero debemos crear un objeto
TextLayout desde el texto de la cadena.
Las siguientes líneas transforman el TextLayout para que sea centrado en el origen y
luego introduce el objeto Shape resultante de la llamda a getOutline dentro del array
shapes.
AffineTransform textAt = new AffineTransform();
textAt.translate(0,
(float)textTl.getBounds().getHeight());
shapes[2] = textTl.getOutline(textAt);
Podemos elegir un primitivo accediendo al índice apropiado dentro del array shapes.
Shape shape =
shapes[Transform.primitive.getSelectedIndex()];
Nota:
Para rellenar y puntear un gráfico primitivo, necesitamos hacer dos llamadas separadas a
métodos: fill o drawString para rellenar el interior, y draw para dibujar el exterior.
Los tres estilos de línea usados en este ejemplo -- ancho, estrecho y punteado -- son
ejemplares de BasicStroke.
...
g2.setStroke(new BasicStroke(3.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER,
En este ejemplo se usan tres estilos de dibujo -- sólido, gradiente y polka. El dibujo de
color sólido es un ejemplar de Color, el gradiente un ejemplar de GradientPaint, y el
patrón un ejemplar de TexturePaint.
...
Color.lightGray,
break;
BufferedImage.TYPE_INT_RGB);
big.setColor(Color.blue);
big.fillRect(0, 0, 5, 5);
big.setColor(Color.lightGray);
big.fillOval(0, 0, 5, 5);
break;
OPERADORES ARITMETICOS:
Los funcionamientos aritméticos diádicos incluyen suma del por cada banda,
substracción, multiplicación y división entre dos imágenes fuente para producir una
imagen de destino. También es posible tomar el valor absoluto de pixeles en la imagen
de la fuente y guardar los resultados en una imagen de destino. Exponenciacion
también se proporciona.
Las operaciones aritméticas requieren que las imágenes fuente y la imagen del destino
tengan los mismos tipos de datos y número de bandas. El tamaño de las dos imágenes
(altura y anchura), sin embargo, no necesita ser el mismo.
Cuando las operaciones son realizadas, se alinean situaciones del origen para cada
imagen o la sola imagen para las operaciones del monadic. Por ejemplo, para la suma de
la imagen el valor a situación 0,0 en uno la imagen de la fuente se agrega a situación 0,0
de la segunda imagen de la fuente y el resultado se guarda en situación 0,0 de la imagen
del destino. Este procedimiento se repite para cada píxel. Las operaciones aritméticas
para imágenes onmulti-banda son realizadas con respecto a la banda de la imagen
fuente.
Se usan las operaciones aritméticas para realizar una combinación píxel a píxel de dos
imágenes o de una imagen con un valor constante
COMPUESTO:
Por ejemplo,
pb = new ParameterBlock()
pb.addSource(source1);
pb.addSource(source2);
pb.add(alpha1);
pb.add(null);
pb.add(new Boolean(false));
destination = JAI.create("composite", pb, null);
El funcionamiento compuesto combina dos imágenes basadas en sus valores del alfa a
cada píxel. Esto se hace en una base por cada banda, y se espera que las dos imágenes
de la fuente tengan el mismo número de bandas y el mismo tipo de datos. La imagen
del destino tiene los mismos tipos de datos de las dos imágenes de la fuente, pero con
una banda extra que representa el cauce de alfa resultante.
Los valores de píxel de destino pueden verse como una representación fraccional de
cada pixel o como un factor de transparencia. especifica los instrumentos compuestos
el Porter-Duff "encima de" la regla en que el color del rendimiento de un pixel con el
triple de valor/alpha de fuente (A, a) y (B, b) se da por el a*A + (1 - a)*(b*B). El valor
de alfa de rendimiento se da por a + (1 - a)*b. Para el triple de fuentes de
premultiplicado ( a*A, a) y ( b*B, b), el valor de rendimiento de premultiplicado
simplemente es ( a*A) + (1 - a)*(b*B).
Los canales de color de las dos imágenes fuente son provistos vía source1 y source2.
Las dos fuentes deben ser cualquiera los dos pre-multiplicados por el alfa o no. El cauce
del alfa no debe ser incluido en el source1 y source2.
El canal del alfa de las primeras imágenes de la fuente debe proporcionarse vía
parámetro del source1Alpha. Este parámetro no puede ser nulo. El canal del alfa de la
segunda imagen fuente puede proporcionarse vía parámetro del source2Alpha. Este
parámetro puede ser nulo en el caso en que la segunda fuente es considerada
completamente opaca. Las imágenes del alfa deben solo-atarse, y tiene los mismos
tipos de datos así como las dimensiones de sus imágenes fuente correspondientes.
La imagen del destino es la combinación de las dos imágenes de la fuente. Tiene los
canales de color y un canal del alfa adicional (el índice de la banda depende del
parámetro del alphaFirst). Si el valor del alfa también se pre-multiplica a los canales de
color este también depende del valor de alphaPremultiplied (pre-multiplicó si
verdadero).
CONVOLUCION:
dst[x][y] = 0;
for( int i = - xOrigin; i <- xOrigin + weight; i++) {
for ( int j = - yOrigin; j <- yOrigin + hieght ; j++) {
dst[x][y] + = src[x+i][y+j] * kernel[xOrigin+i][yOrigin+j];
}
}
La convolución, deja una banda de pixeles alrededor de los bordes indefinido. Por
ejemplo, para un objeto 3x3 sólo cuatro elementos del objeto y cuatro pixeles de la
fuente contribuyen al pixel de la convolución en las esquinas de la imagen de la fuente.
Pixeles que no permiten aplicar el objeto lleno a la fuente no son incluidos en la imagen
del destino. Un funcionamiento Fronterizo puede usarse para agregar una frontera
apropiada a la imagen de la fuente para evitar encogimiento de los límites de la imagen.
El objeto no puede ser más grande en cualquier dimensión que los datos de la imagen.
Para cada muestra del destino, el objeto se gira 180 grados y su elemento" importante, u
origen, se pone encima del pixel de la fuente que corresponde con el pixel del destino.
Los elementos del grano se multiplican con los pixeles de la fuente bajo ellos, y los
productos resultantes se suman para producir el valor de muestra de destino.
HISTOGRAMA:
Las tareas primarias necesitadas para obtener un histograma son como sigue:
1. cree un objeto del Histograma que especifica el tipo de histograma a ser generado.
Para una imagen de 8 bits, hay 255 posibles valores de intensidad. Así, dada una
imagen de 8 bits que es 128 por 128 con los valores todo el juego para poner a cero el
histograma resultante a una sola banda tendría un solo valor a las 0 con un valor de
16384 con todas las otras cajas que contienen el valor de 0. La suma de todos los
resultados en cada caja debe tener magnitud para el número total de pixeles en la
imagen.
CAPAS:
En JAI, las colecciones contienen imágenes del renderable o colecciones que incluyen
colecciones de imágenes. Pilas de imagen, pirámides o mapas mip, por ejemplo.
LOOKUT TABLE:
El funcionamiento de Lookup toma una imagen dada o renderada imagen y una mesa
del lookup, y realiza el lookup de la mesa general pasando la imagen de la fuente a
través de la mesa.
La imagen fuente puede ser mono o multi-banda de tipos de datos, ushort, short, o int.
El lookuptable puede ser mono o multi-banda y de cualquier JAI soportando los tipos
de los datos. La imagen destino debe tener los mismos tipos de datos como la mesa del
lookup, y su número de bandas es determinado basado en el número de bandas de la
fuente y la mesa. Si la fuente se mono-banda, el destino tiene el mismo número de
bandas como la mesa del lookup; por otra parte, el destino tiene el mismo número de
bandas como la fuente.
RENDEREABLE:
El funcionamiento del Invertido invierte los valores del pixel de una imagen. Para las
imágenes de la fuente con los tipos de datos firmados, el valor de pixel de la imagen
destino se define por el pseudocodigo:
dst[x][y][b] = - src[x][y][b]
Para los tipos de los datos sin firmar, los valores del destino se definen por:
dst[x][y][b] = MAX_VALUE - src[x][y][b]
donde MAX_VALUE es el valor máximo apoyado por el sistema del tipo de los datos
del pixel de la fuente.
La capa del renderable proporciona fuentes de la imagen que pueden reusarse múltiples
veces en los contextos diferentes, como la pantalla despliegue o imprimiendo. Los
operadores del renderable toman los parámetros dar-independientes y pueden
encadenarse juntos (el funcionamiento encadena) a para dirigir-acyclic-graphs(DAGS).
Cualquier clase que lleva a cabo la interfaz de RenderableImage es una fuente del
renderable y debe adaptar a RenderContexts. Las imágenes de Renderable son los
referenciados a través del usuario con los sistemas de la coordenada definidos
RENDERABLE SCALE:
La operación de escala traduce y redimensiona una imagen. Para cada pixel (x, y) del
destino, el valor de la fuente a la posición del subpixel fraccionaria ((x - xTrans)/xScale,
(y - yTrans)/yScale) se construye por medio de un objeto de la Interpolación y escrito
al destino.
Cuando aplica a una escala un factor de escala scale_x, scale_y a una imagen fuente
con la anchura de src_width y altura de src_height, la imagen resultante se define para
tener las dimensiones siguientes:
UMBRAL:
El funcionamiento del Umbral toma uno imagen dada, y traza todos los pixeles de esta
imagen cuyo valor se queda dentro de un rango especificado a una constante
especificada. El rango se especifica por un valor bajo y un valor alto.
El valor de pixel de la imagen del destino byte define con el pseudocodigo siguiente:
WARP:
Para torcerse la imagen, pueden seleccionarse juegos de puntos usando el botón del
ratón izquierdo. Por ejemplo, para el affine apriete el botón del ratón y arrástrelo a una
nueva situación. Una línea de venda de caucho mostrará el camino. Cuando el ratón se
suelta, un par de puntos se mostrará conectado por una línea recta. Repita este dos más
veces. Un mensaje al fondo de la ventana contará el número de juegos seleccionado.
Pueden arrastrarse los puntos a las nuevas situaciones, o los puntos de sumas agregaron
qué quiere de nuevo, tuérzase la imagen.
Java Advanced Imaging proporciona una clase de la transformación, warp que se usa
para la transformación de coordenada nolineal de imagen. El pixel posiciona en la clase
de la Urdimbre se representa usando el fijo-punto coordina, la exactitud del subpixel
productiva pero todavía permitiendo el uso de aritmética del entero. El grado de
precisión es fijo por las funciones de JAI apropiadas en el método del warpRect.
El método importante de esta clase es warpRect que proporciona las situaciones de los
pixeles en el espacio de la fuente que el mapa a una región del rendimiento rectangular
dada. La región del rendimiento que usa las coordenadas del entero normales se
especifica. Se especifican las posiciones de la fuente vueltas por el método en el fijo-
punto, las coordenadas del subpixel.
Polinómico
El polinomio general
La reja
Cuadrático
Cúbico
En perspectiva
Affine
OpImage
ARBOL DE HERENCIA
NOTA: Este árbol es sacado directamente de la página del API, Aunque identifico
algunas de las funciones utilizadas para el procesamiento de imágenes, no comprendo la
gran mayoria de secciones del arbol.
o class java.lang.Object
o class com.sun.media.jai.codec.BMPEncodeParam (implements
com.sun.media.jai.codec.ImageEncodeParam)
o class javax.media.jai.BorderExtender (implements java.io.Serializable)
o class javax.media.jai.BorderExtenderConstant
o class javax.media.jai.BorderExtenderCopy
o class javax.media.jai.BorderExtenderReflect
o class javax.media.jai.BorderExtenderWrap
o class javax.media.jai.BorderExtenderZero
o class javax.media.jai.util.CaselessStringKey (implements java.lang.Cloneable, java.io.Serializable)
o class javax.media.jai.registry.CIFRegistry
o class javax.media.jai.CollectionImage (implements java.util.Collection, javax.media.jai.ImageJAI)
o class javax.media.jai.AttributedImageCollection
o class javax.media.jai.CollectionOp (implements javax.media.jai.OperationNode,
java.beans.PropertyChangeListener)
o class javax.media.jai.ImageSequence
o class javax.media.jai.ImageStack
o class javax.media.jai.RenderedImageList (implements java.util.List,
java.awt.image.RenderedImage, java.io.Serializable)
o class java.awt.image.ColorModel (implements java.awt.Transparency)
o class java.awt.image.ComponentColorModel
o class javax.media.jai.FloatDoubleColorModel
o class java.awt.color.ColorSpace (implements java.io.Serializable)
o class javax.media.jai.ColorSpaceJAI
o class javax.media.jai.IHSColorSpace
o class java.awt.Component (implements java.awt.image.ImageObserver, java.awt.MenuContainer,
java.io.Serializable)
o class java.awt.Canvas (implements javax.accessibility.Accessible)
o class javax.media.jai.CanvasJAI
o class javax.media.jai.widget.ImageCanvas
o class java.awt.Container
o class javax.swing.JComponent (implements java.io.Serializable)
Interface Hierarchy
o interface javax.media.jai.CachedTile
o interface java.lang.Cloneable
o interface com.sun.media.jai.codec.ImageDecodeParam (also extends java.io.Serializable)
APLICACIÓN
Ejemplo de histograma:
import java.io.File;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.FlowLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.image.renderable.ParameterBlock;
import java.awt.image.DataBuffer;
import java.awt.event.*;
import java.awt.Color;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;
import javax.swing.event.*;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.Histogram;
import javax.media.jai.LookupTableJAI;
import javax.media.jai.RenderedOp;
import java.net.URL;
import java.net.MalformedURLException;
try
{
source = JAI.create("url", new URL (filename) );
}
catch ( MalformedURLException e)
{
return;
}
setOpaque(true);
setLayout(new BorderLayout());
setBackground(Color.white);
reset.addActionListener(this);
equal.addActionListener(this);
norm.addActionListener(this);
piece.addActionListener(this);
controlPanel.add(reset);
controlPanel.add(equal);
controlPanel.add(norm);
controlPanel.add(piece);
add(title, BorderLayout.NORTH);
add(panel, BorderLayout.CENTER);
add(controlPanel, BorderLayout.SOUTH);
return local_array;
}