lunes, 19 de diciembre de 2011

RenderingHints, renderizados y operaciones de manipulación de imágenes

0 comentarios
Hola otra vez, hoy vamos a profundizar un poco en las claves de la manipulación de imágenes y textos con Graphics2D y de como mejorar la resolución de los objetos u imágenes mostrados.
Para ellos nos serviremos de la clase RenderingHints y le estableceremos los valores apropiados para los resultados que pretendemos obtener.

La clase RenderingHints define y maneja una colección de claves y valores asociados que permite a una aplicación proporcionar entradas a las opciones de algoritmos usados por otras clases que realizan renderizados y manipulación de imágenes. La clase Graphics2D, y clases que implementan BufferedImageOp y RasterOp proporcionan métodos para obtener y establecer individualmente o grupos de claves RenderingHints y sus valores asociados. Cuando estas implementaciones realizan cualquier renderizado u operaciones de manipulación de imágenes deberían examinar estos valores que son requeridos por el llamante y adaptar los algoritmos usados en consecuencia y en la medida de su capacidad.

A partir de aquí paso a explicar cada uno de los indicadores y como modifican el renderizado de los componentes.

KEY_ALPHA_INTERPOLATION
La clave ALPHA_INTERPOLATION es una clave general que proporciona una recomendación de alto nivel para que haciendo uso de un algoritmo de mezcla de alpha elegir entre mayor velocidad o calidad al evaluar ventajas y desventajas en el renderizado.
Esta clave controlaría la elección del factor alpha en los cálculos que sacrificarían algo de precisión para usar tablas de consulta rápida o reducir la precisión de la instrucciones SIMD (Single Instruction, Multiple Data). Esta clave también controlaría si un color y su valor alpha se convierten a un color linear durante los cálculos para un efecto visual mas lineal con el coste de hacer cálculos por pixel adicionales.
Los posibles valores son:

  • VALUE_ALPHA_INTERPOLATION_SPEED
  • VALUE_ALPHA_INTERPOLATION_QUALITY
  • VALUE_ALPHA_INTERPOLATION_DEFAULT


KEY_ANTIALIASING
Clave de suavizado. La clave ANTIALIASING controla si la representación geométrica en los métodos de un objeto Graphics2D intentará reducir el aliasing en los bordes de las formas.
Un algoritmo de suavizado típico funciona fundiendo los colores existentes en la frontera de una forma con el color de relleno de acuerdo a la cobertura de pixeles parcial estimada de la forma.
Los posibles valores son:

  • VALUE_ANTIALIAS_ON
  • VALUE_ANTIALIAS_OFF
  • VALUE_ANTIALIAS_DEFAULT


KEY_COLOR_RENDERING
La clave COLOR_RENDERING controla la precisión de aproximaciones y conversiones al almacenamos colores en una imagen o superficie destino.
Cuando al renderizar o realizar una operación de manipulación de imágenes se produce un valor de color que debe ser guardado en un destino, primero de debe convertir ese color en un tipo capaz de ser almacenado en la imagen o superficie destino. Como mínimo, las componentes del color deben ser convertidas a una representación de bits y ordenarse correctamente o un índice en una tabla de decisión de colores debe elegirse antes de que los datos sean guardados en la memoria destino. Si esta conversión mínima, los datos en el destino podrían perfectamente parecer aleatorios, incorrectos o incluso valores no soportados. Los algoritmos que se usan para convertir los resultados del renderizado rápidamente en el formato de color adecuado son muy conocidos y están bastante optimizados.
Simplemente realizando las conversiones de formato de color más básicas para guardarlos en un destino puede ignorar una diferencia en el calibrado del ColorSpace del origen y destino u otros factores tales como la linealidad de la corrección gamma. A menos que el ColorSpace origen y destino sean idénticos, para realizar correctamente una operación de renderizado con teniendo el máximo cuidado en la precisión de los colores representados, los colores origen deben transformarse a un ColorSpace independiente del dispositivo donde se valla a mostrar y posteriormente convertirlos al ColorSpace destino. Aún más, si cálculos tales como la mezcla de múltiples colores origen se van a realizar durante la operación de renderizado, se puede obtener más claridad si el ColorSpace intermedio elegido tiene una relación lineal entre los valores que se están calculando y la percepción del ojo humano a las curvas de respuesta del dispositivo de salida.
Los posibles valores son:

  • VALUE_COLOR_RENDER_SPEED
  • VALUE_COLOR_RENDER_QUALITY
  • VALUE_COLOR_RENDER_DEFAULT


KEY_DITHERING
Clave de Dithering. La clave DITHERING controla como de cerca aproximar un color cuando lo almacenamos en un destino con una resolución de color limitada.
Algunos destinos de renderizado pueden soportar un número limitado de colores lo cual puede que no permita representar el espectro completo de colores que podrían resultar durante las operaciones de renderizado. Para estos destinos, la clave DITHERING controla si el renderizado se realiza con un color de relleno sólido en un pixel específico que es de los colores permitido el mas cercano al que se solicita, o si las formas se rellenaran con un patrón de colores que se combinan para aproximarse lo máximo posible a este color deseado.
Los posibles valores son:

  • VALUE_DITHER_DISABLE
  • VALUE_DITHER_ENABLE
  • VALUE_DITHER_DEFAULT


KEY_FRACTIONALMETRICS
Clave de métricas fraccionadas en las fuentes. La clave FRACTIONALMETRICS controla si al posicionar los glifos de un carácter en particular se tiene en cuenta la precisión sub-pixel de los avances de carácter escalado de la fuente o si estos vectores de avance se redondean a un entero. Esta clave solo recomienda cuanta precisión debe usarse para posicionar los glifos y no especifica ni recomienda si la rasterización o las fronteras de pixel de un glifo deben modificarse para coincidir.
Renderizar texto a un dispositivo de baja resolución como una pantalla necesariamente implicará una serie de operaciones de redondeo ya que la definición de alta calidad y muy precisa de la forma y métricas de los glifos de un carácter deben ajustarse a un número discreto de pixeles en el dispositivo. Idealmente el posicionado de los glifos durante la disposición del texto debería calcularse escalando las métricas diseñadas en la fuente de acuerdo al tamaño del punto, pero entonces el ancho del avance escalado no será necesariamente un número entero de pixeles. Si los glifos se posicionan con una precisión sub-pixel de acuerdo a estas métricas de diseño escaladas, entonces la rasterización idealmente necesitará ser ajustada para cada posible origen sub-pixel.
Desafortunadamente, escalar cada glifo de manera personalizada a su origen sub-pixel exacto durante la disposición del texto sería prohibitivamente caro por lo que un sistema simplificado basado en las posiciones enteras de un dispositivo se usa para disponer el texto. La rasterización de un glifo y el ancho de avance escalado son ambos ajustados a la vez para conseguir que el texto se vea bien en la resolución del dispositivo y tenga distancias enteras de pixeles entre los glifos que ayude a que los glifos parezcan uniformes y consistentemente espaciados y legibles.
Este proceso de redondeo del ancho del avance para los glifos rasterizados significa que la densidad de un carácter y la longitud promedia de una cadena de texto será diferente entre las medidas teóricas del diseño debido a la acumulación de una serie de pequeñas diferencias en los anchos ajustados de cada glifo. Cada diferencia específica será diferente en cada glifo, algunos siendo mas anchos y otros más estrechos que sus teóricos anchos de diseño. Así la diferencia global en la densidad de carácter y la longitud variará por un número de factores incluyendo la fuente, la resolución específica del dispositivo destino, y los glifos elegidos para representar la cadena que se está renderizando. Como resultado, renderizar la misma cadena en múltiples resoluciones puede arrojar métricas muy varadas sobre cadenas enteras.
Cuando FRACTIONALMETRICS están habilitadas, las métricas de diseño originales se escalan a tamaño de punto y se usan para disponer con precisión sub-pixel. La densidad media de los glifos y la longitud total de una cadena larga de caracteres será por ello más aproximada al diseño teórico de la fuente, pero la legibilidad puede verse afectada ya que cada par individual de caracteres puede que no tengan distancias consistentes además dependiendo de como la acumulación sub-pixel de los orígenes de los glifos se engrane con la malla de pixeles del dispositivo. Habilitar esta indicación puede ser deseado cuando la disposición del texto que se realiza deba ser consistente a lo largo de una variedad de resoluciones de salida. Específicamente, esta indicación puede ser deseable en situaciones cuando la disposición del texto se previsualiza en dispositivos con baja resolución como una pantalla para salidas que serán eventualmente renderizadas en una impresora de alta resolución o dispositivo de composición.
Cuando está deshabilitado, las métricas escaladas se redondean o ajustan a distancias enteras para disponerse. Las distancias entre cada par específico de glifos será mas uniforme en el dispositivo, pero la densidad y longitud total de cadenas largas puede que no coincida ya con las intenciones teóricas del diseñador de la fuente. Deshabilitar este indicador producirá normalmente resultados más legibles en dispositivos de baja resolución como monitores de ordenador.
Los posibles valores son:

  • VALUE_FRACTIONALMETRICS_OFF
  • VALUE_FRACTIONALMETRICS_ON
  • VALUE_FRACTIONALMETRICS_DEFAULT


KEY_INTERPOLATION
Clave de Interpolación. El indicador INTERPOLATION controla como los pixeles de las imágenes se filtran o remuestrean durante una operación de renderizado de imágenes.
Implícitamente las imágenes se definen para proporcionar muestras de color en unas coordenadas enteras. Cuando las imágenes se renderizan tal cual sin escalado al destino, la elección de que pixeles de la imagen se mapean a que pixeles del dispositivo es obvio y las muestras en las coordenadas de la imagen se transfieren a los pixeles correspondientes en la rejilla de pixeles del destino uno a uno. Cuando las imágenes se renderizan en un sistema de coordenadas escalado, rotado o transformado de cualquier manera, entonces el mapeado de los pixeles del dispositivo con la imagen puede originar la pregunta de que muestra de color usar para las continuas coordenadas que existen entre las localizaciones enteras y las proporcionadas en las muestras de la imagen. Los algoritmos de interpolación definen funciones que proporcionan una muestra de color para una coordenada continua en una imagen basada en las muestras de color de las coordenadas colindantes.
Los posibles valores son:

  • VALUE_INTERPOLATION_NEAREST_NEIGHBOR → la muestra de color de la coordenada vecinas mas cercana en la imagen es la usada.
  • VALUE_INTERPOLATION_BILINEAR → la muestra de color se obtiene mediante interpolación lineal de las 4 coordenadas más cercanas.
  • VALUE_INTERPOLATION_BICUBIC → las muestras de color de 9 coordenadas cercanas en la imagen se interpolan usando una función cúbica en X e Y para producir la muestra de color.
KEY_RENDERING

Clave de renderizado. El indicador RENDERING es un indicador general que proporciona recomendaciones de alto nivel sobre como sesgar las opciones de un algoritmo hacia velocidad o calidad cuando evaluá pros y contras. El indicador puede ser consultado por cualquier renderizado u operación de manipulación de imágenes, pero las decisiones normalmente harán honor a otros indicadores mas específicos en relación a este indicador.
Los posibles valores son:

  • VALUE_RENDER_SPEED
  • VALUE_RENDER_QUALITY
  • VALUE_RENDER_DEFAULT


KEY_STROKE_CONTROL
Clave para normalización de trazo. El indicador STROKE_CONTROL controla si una implementación de renderizado debería o tiene permitido modificar la geometría de las formas renderizadas para varios fines.
Algunas implementaciones podrían ser capaces de usar una librería optimizada de la plataforma que podría ser mas rápida que los algoritmos de renderizado software tradicionales en una plataforma dada, pero que podría no soportar coordenadas de punto flotante. Algunas implementaciones podrían también tener sofisticados algoritmos que perturban las coordenadas de un trazado de tal manera que las lineas anchas aparezcan mas uniformes en anchura y espaciado.
Si una implementación realiza cualquier tipo de modificación o "normalización" de un trazado, debería mover las coordenadas mas de medio pixel en cada dirección.
Los posibles valores son:

  • VALUE_STROKE_NORMALIZE
  • VALUE_STROKE_PURE
  • VALUE_STROKE_DEFAULT


KEY_TEXT_ANTIALIASING
Clave de antialiasing de texto. El indicador TEXT_ANTIALIASING puede controlar el uso de algoritmos antialiasing para el texto independientemente de la elección para renderizado de formas. Muchas veces una aplicación puede querer usar antialiasing solo para texto y no para otras formas, Además, los algoritmos para reducir el solapamiento para texto suelen ser mas sofisticados que aquellos que se han desarrollado para renderizado general por lo que este indicador proporciona valores adicionales que pueden controlar las opciones de estos algoritmos específicos para texto. Si se deja en el valor DEFAULT, este indicador diferirá al valor del indicador general KEY_ANTIALIASING.
Los posibles valores son:

  • VALUE_TEXT_ANTIALIAS_ON → Antialiasing habilitado
  • VALUE_TEXT_ANTIALIAS_OFF → Antialiasing deshabilitado
  • VALUE_TEXT_ANTIALIAS_DEFAULT → El renderizado se realiza de acuerdo al valor del indicador KEY_ANTIALIASING
  • VALUE_TEXT_ANTIALIAS_GASP → El renderizado requiere usar la información en el recurso de la fuente que especifica para cada tamaño de punto si usar o no los valores VALUE_TEXT_ANTIALIAS_ON o VALUE_TEXT_ANTIALIAS_OFF.
  • VALUE_TEXT_ANTIALIAS_LCD_HRGB → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de izquierda a derecha RGB, de tal manera que la resolución horizontal subpixel es tres veces la de la resolución de un pixel horizontal completo (HRGB).
  • VALUE_TEXT_ANTIALIAS_LCD_HBGR → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de izquierda a derecha BGR, de tal manera que la resolución vertical subpixel es tres veces la de la resolución de un pixel vertical completo (HBGR).
  • VALUE_TEXT_ANTIALIAS_LCD_VRGB → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de arriba a abajo RGB, de tal manera que la resolución horizontal subpixel es tres veces la de la resolución de un pixel horizontal completo (VRGB).
  • VALUE_TEXT_ANTIALIAS_LCD_VBGR → El texto mostrado será optimizado para un display LCD con subpixeles para mostrar de arriba a abajo BGR, de tal manera que la resolución vertical subpixel es tres veces la de la resolución de un pixel vertical completo (VBGR).


KEY_TEXT_LCD_CONTRAST
Clave de contraste de texto LCD. El valor es un valor Integer que se usa como un ajuste en el contraste del texto cuando se usa en conjunción con un indicador de antialiasing de texto LCD tal como VALUE_TEXT_ANTIALIAS_LCD_HRGB.
Los valores deben ser enteros positivos en el rango 100 a 250.

  • Un valor bajo (100) corresponde a texto con mayor contraste cuando se muestra texto oscuro en un fondo claro.
  • Un valor alto (200) corresponde a texto de bajo contraste cuando se muestra texto oscuro en un fondo claro.
  • Un valor típico esta en el estrecho rango 140-180.
  • Si no se especifica ningún valor, una implementación por defecto o del sistema será aplicada.
El valor por defecto debería ser apropiado para la mayoría de los fines, por lo que los clientes raramente necesitan especificar un valor para este indicador a menos que tengan información concreta sobre un valor apropiado. Un valor más alto no significa mayor contraste, en realidad es al contrario. La corrección se aplica de una manera similar a un ajuste gamma para una respuesta de luminosidad de percepción no lineal de los sistemas de visualización, pero no indica una corrección total para esto.

Y como siempre os dejo algunos ejemplos simples de la aplicación de estos indicadores.

Y por aquí el código del ejemplo:

package RenderingHintsSamples;

import java.awt.BasicStroke;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;

import javax.swing.JLabel;
import javax.swing.JPanel;

public class RenderingHintsSamples extends JPanel {

 public RenderingHintsSamples() {
  this.setLayout(new GridLayout(4, 2));

  this.add(new JLabel("KEY_ANTIALIASING --> OFF"));
  this.add(new AntialiasingPanel(false));
  this.add(new JLabel("KEY_ANTIALIASING --> ON"));
  this.add(new AntialiasingPanel(true));

  this.add(new JLabel("KEY_TEXT_ANTIALIASING --> OFF"));
  this.add(new TextAntialiasingPanel(false));
  this.add(new JLabel("KEY_TEXT_ANTIALIASING --> ON"));
  this.add(new TextAntialiasingPanel(true));
 }

 private class AntialiasingPanel extends JPanel {

  boolean claveActiva = false;

  public AntialiasingPanel(boolean claveActiva) {
   this.claveActiva = claveActiva;
  }

  @Override
  public void paint(Graphics g) {

   Graphics2D g2d = (Graphics2D) g;
   if (claveActiva) {
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
   } else {
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
   }

   g2d.setStroke(new BasicStroke(5f));
   g2d.drawOval(20, 20, 60, 60);
   g2d.drawLine(80, 20, 150, 75);

  }
 }

 private class TextAntialiasingPanel extends JPanel {

  boolean claveActiva = false;

  public TextAntialiasingPanel(boolean claveActiva) {
   this.claveActiva = claveActiva;
  }

  @Override
  public void paint(Graphics g) {

   Graphics2D g2d = (Graphics2D) g;
   if (claveActiva) {
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
   } else {
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
   }

   g2d.setFont(new Font("Serif", Font.ITALIC, 30));
   g2d.drawString("TEXT_ANTIALIASING", 0, 40);

  }
 }

}

package RenderingHintsSamples;

import javax.swing.JFrame;


public class Main {

 private static void createAndShowGUI() {
  JFrame frame = new JFrame("RenderingHints: ejemplos");

  RenderingHintsSamples ejemplos = new RenderingHintsSamples();

     frame.getContentPane().add(ejemplos);
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     frame.setSize(565, 370);
     frame.setVisible(true);
 }

 public static void main(String[] args) {

  javax.swing.SwingUtilities.invokeLater(new Runnable() {
   public void run() {
    createAndShowGUI();
   }
  });
 }
}


Un saludo y hasta la próxima entrada.