2010-05-13 5 views
17

Quiero hacer una copia (de un área rectangular) de los valores ARGB de una fuente BufferedImage en un destino BufferedImage. No se debe hacer ninguna composición: si copio un píxel con un valor ARGB de 0x8000BE50 (valor alfa a 128), entonces el píxel de destino debe ser exactamente 0x8000BE50, anulando por completo el píxel de destino.Java: ¿cómo hacer una copia rápida de los píxeles de BufferedImage? (prueba unitaria incluida)

Tengo una pregunta muy precisa e hice una prueba unitaria para mostrar lo que necesito. La prueba unitaria es completamente funcional y autónoma, está pasando bien y está haciendo exactamente lo que yo quiero.

Sin embargo, quiero un eficiente método demás rápido y más memoria para reemplazar copySrcIntoDstAt (...).

Ese es el punto de mi pregunta: no busco cómo "llenar" la imagen de una manera más rápida (lo que hice es solo un ejemplo para tener una prueba unitaria). Todo lo que quiero es saber lo que sería rápido y eficiente con la memoria manera de hacerlo (es decir, rápido y sin crear objetos innecesarios).

La implementación de la prueba de concepto que hice obviamente es muy eficiente en cuanto a la memoria, pero es lenta (haciendo una getRGB y una setRGB por cada píxel).

Esquemáticamente, lo he entendido: (donde A indica píxeles correspondientes de la imagen de destino antes de la copia)

AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 

Y yo quiero tener esto:

AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAABBBBAAA 
AAAAAAAAAAAAABBBBAAA 
AAAAAAAAAAAAAAAAAAAA 

donde 'B 'representa los píxeles de src imagen.

Tenga en cuenta que estoy buscando un reemplazo exacto del método copySrcIntoDstAt (...), no para un enlace/cita API.

import org.junit.Test; 

import java.awt.image.BufferedImage; 

import static org.junit.Assert.*; 

public class TestCopy { 

    private static final int COL1 = 0x8000BE50; // alpha at 128 
    private static final int COL2 = 0x1732FE87; // alpha at 23 

    @Test 
    public void testPixelsCopy() { 
     final BufferedImage src = new BufferedImage( 5, 5, BufferedImage.TYPE_INT_ARGB); 
     final BufferedImage dst = new BufferedImage(20, 20, BufferedImage.TYPE_INT_ARGB); 
     convenienceFill(src, COL1); 
     convenienceFill(dst, COL2); 
     copySrcIntoDstAt(src, dst, 3, 4); 
     for (int x = 0; x < dst.getWidth(); x++) { 
      for (int y = 0; y < dst.getHeight(); y++) { 
       if (x >= 3 && x <= 7 && y >= 4 && y <= 8) { 
        assertEquals(COL1, dst.getRGB(x,y)); 
       } else { 
        assertEquals(COL2, dst.getRGB(x,y)); 
       } 
      } 
     } 
    } 

    // clipping is unnecessary 
    private static void copySrcIntoDstAt(
      final BufferedImage src, 
      final BufferedImage dst, 
      final int dx, 
      final int dy 
    ) { 
     // TODO: replace this by a much more efficient method 
     for (int x = 0; x < src.getWidth(); x++) { 
      for (int y = 0; y < src.getHeight(); y++) { 
       dst.setRGB(dx + x, dy + y, src.getRGB(x,y)); 
      } 
     } 
    } 

    // This method is just a convenience method, there's 
    // no point in optimizing this method, this is not what 
    // this question is about 
    private static void convenienceFill(
      final BufferedImage bi, 
      final int color 
    ) { 
     for (int x = 0; x < bi.getWidth(); x++) { 
      for (int y = 0; y < bi.getHeight(); y++) { 
       bi.setRGB(x, y, color); 
      } 
     } 
    } 

} 

Respuesta

20
private static void copySrcIntoDstAt(final BufferedImage src, 
     final BufferedImage dst, final int dx, final int dy) { 
    int[] srcbuf = ((DataBufferInt) src.getRaster().getDataBuffer()).getData(); 
    int[] dstbuf = ((DataBufferInt) dst.getRaster().getDataBuffer()).getData(); 
    int width = src.getWidth(); 
    int height = src.getHeight(); 
    int dstoffs = dx + dy * dst.getWidth(); 
    int srcoffs = 0; 
    for (int y = 0 ; y < height ; y++ , dstoffs+= dst.getWidth(), srcoffs += width) { 
     System.arraycopy(srcbuf, srcoffs , dstbuf, dstoffs, width); 
    } 
} 
+1

+1 muy agradable ... nunca pensé usando varios * * System.arraycopy sería el camino a seguir. ¡Supongo que cada Imagen Buffered siempre tiene un ráster y que no hay creación de objetos aquí, ¿cierto? Es realmente agradable, pero al mismo tiempo parece un poco raro: esperaba algo preexistente haciendo el trabajo sin tener que hacer un * por * loop y System.arraycopy manualmente. Pero, sí, muy bien (lo intenté por cierto y parece estar bien :) – SyntaxT3rr0r

+0

@WizardOfOds Gracias, subrayó "más rápido y más eficiente en la memoria", siempre se requiere algún tipo de bucle para mover las compensaciones. Manipular las estructuras internas sin hacer copias y crear objetos. Dudo que haya un método que no sea JNI y que funcione mejor. – stacker

Cuestiones relacionadas