2009-05-31 18 views
8

Soy un programador de Java razonablemente experimentado pero relativamente nuevo en Java2D. Estoy intentando escalar una imagen, pero obtengo resultados de mala calidad. La imagen es una vista previa de un panel, por lo que contiene elementos como texto y campos de texto. Siempre voy a reducir la escala, nunca subiré.Java2D: problemas de escala

Actualmente estoy usando el siguiente código: -

g.drawImage(panelImage, 0, 0, scaledWidth, scaledHeight, null); 

Dónde panelImage es la vista previa de tamaño completo (BufferedImage) y scaledWidth y scaledHeight son las respectivas dimensiones de destino. Parece que pierdo muchos detalles en el texto y los bordes de cosas como campos de texto, etc.

¿Hay una mejor llamada que debería usar para escalar la imagen?

Gracias, John

Respuesta

11

Una sugerencia que puedo hacer es cambiar el tamaño en primer lugar la imagen en una separada BufferedImage. El motivo es que se puede obtener un objeto Graphics2D del BufferedImage para producir una imagen escalada de mejor calidad.

Graphics2D pueden aceptar "indicaciones de representación" que indican la forma en que el objeto Graphics2D debe realizar el procesamiento de imágenes. El método setRenderingHint es uno de los métodos que se pueden usar para establecer esas sugerencias de representación. Se pueden usar los consejos de renderización de la clase RenderingHints.

Luego, utilizando ese objeto Graphics2D, se puede dibujar una imagen al BufferedImage usando las sugerencias de representación especificadas anteriormente.

A (no probado) código áspera funcionaría como los siguientes:

BufferedImage scaledImage = new BufferedImage(
    scaledWidth, 
    scaledHeight, 
    BufferedImage.TYPE_INT_RGB 
); 

Graphics2D g = scaledImage.createGraphics(); 
g.setRenderingHints(
    RenderingHints.Key.KEY_INTERPOLATION, 
    RenderingHints.VALUE_INTERPOLATION_BICUBIC 
); 

g.drawImage(panelImage, 0, 0, scaledWidth, scaledHeight, null); 
g.dispose(); 

Otros consejos representación de interés pueden incluir:

El Controlling Rendering Quality sección de The Java Tutorials als o tiene más información sobre cómo controlar la calidad de representación de los objetos Graphics2D.

Y para una muy buena fuente de información sobre el manejo de interfaces gráficas en general, Filthy Rich Clients de Chet Haase y Romain Guy es muy recomendable. Hay una sección del libro que trata el problema de escalar imágenes, lo que parece bastante relevante.

+0

Gracias, tengo una copia de ese libro y me metí en él para leer el capítulo. Debería haber pensado en mirar allí antes de publicar. Me olvidé por completo de dar pistas para escalar. ¡Gracias! John – Johnathan

+0

De nada :) Las páginas 98-113 tratan sobre la Escala de imagen e incluyen algunos buenos ejemplos. De particular interés para mí fue la idea del escalado bilineal progresivo presentado en la página 104. – coobird

+0

Sí, lo vi, pero no creo que mi aplicación realmente lo amerite. BICUBIC o BILINEAR son lo suficientemente buenos para mí. ¡Es hora de experimentar! – Johnathan

2

puede ser usted debe llamar:

g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 

y

g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
0

Coobird tiene la idea correcta. También probaría la interpolación RenderingHints.VALUE_INTERPOLATION_BILINEAR y vería si se ve mejor. Sin embargo, Bicubic funciona mejor cuando se realiza una ampliación. Para obtener los mejores resultados cuando se realiza una reducción a escala, se debe reducir el tamaño en varios pasos. Primero reduzca a la mitad la resolución, luego divida a la mitad otra vez, etc. hasta que se acerque a la resolución deseada (es decir, no puede reducir a la mitad o la imagen se volverá demasiado pequeña).El paso final es escalar a la resolución deseada.

Por ejemplo, digamos que su imagen de entrada es 800x600 y desea reducir la escala a 160x120:

  1. Downscale 50%. ->400x300
  2. Downscale 50%. ->200x150
  3. Downscale a 160x120.
+0

¿Por qué la reducción de escala en varios pasos sería una ventaja? Por favor, elabore: D –

+0

Aquí hay algo sobre el tema: http://www.nobel-joergensen.com/roller/java/entry/downscaling_images_in_java Aparte de eso no tengo nada, pero en mi experiencia de downscaling en pasos proporciona un mejor resultado final. Vale la pena probar al menos. :) – MH114

+1

Esta es la idea detrás de la "escala bilineal progresiva": realizando una escala bilineal en varios pasos, la información de cada píxel se conserva, en lugar de descartarse realizando un escalado bilineal de la imagen en un solo paso. – coobird

1

Coobird tiene razón en que necesita bajar progresivamente (preferiblemente usando BICUBIC) para obtener un resultado atractivo para una miniatura lo suficientemente pequeña. Image.getScaledInstance solía hacer esto con el enfoque AREA_AVERAGED, pero es mucho más lento que el downscale incremental propuesto originalmente por Chris Campbell en su artículo "Perils of Image.getScaledInstance()".

Disculpe la autopromoción aquí, pero lancé un puñado de "prácticas nativas de Java" cuando se trata de escalar imágenes en una biblioteca llamada imgscalr.

Está disponible bajo una licencia Apache 2 y la fuente está en GitHub; el objetivo de la biblioteca era hacer escala de imágenes en Java nativo dead-easy (1 clase, 5 métodos estáticos) y garantizar el mejor resultado (que es lo que originalmente quería), el resultado más rápido (excelente al escalar entre imágenes grandes)) o un equilibrio entre los dos y dejar que la biblioteca decida cuál usar.

Solo quería una lib que podría "Cambiar el tamaño de mi imagen y salirse de mi camino" y después de leer todas estas publicaciones durante unos días mientras me dirigía al punto de dolor (la mía también) estaba dando vueltas y compartiendo el trabajo para cualquier otra persona puede ayudar.

+0

El sitio original no responde en este momento, parece que el repositorio oficial de la lib está aquí https://github.com/rkalla/imgscalr –

+0

Sí, usted encontró el repositorio correcto - Cerré todo el viejo 'The Buzz' Lo de los medios (no he tenido tiempo durante aproximadamente 5 años para mantener eso) y lo moví todo a mi espacio de repositorio personal. También está en repositorio Maven por defecto. –