2010-05-13 5 views
17

소스 (BufferedImage)의 ARGB 값 ()으로 복사본을 만들고 싶습니다. 합성하지 않아야합니다. ARGB 값이 0x8000BE50 인 픽셀 (128의 알파 값)을 복사하면 대상 픽셀은 정확히 0x8000BE50이어야하며 대상 픽셀을 완전히 무시해야합니다.Java : BufferedImage의 픽셀을 빠르게 복사하는 방법은 무엇입니까? (단위 테스트 포함)

나는 매우 정확한 질문을하고 내가 필요한 것을 보여주기 위해 단위 테스트를했다. 단위 테스트는 완벽하게 기능적이며 자급 자족하며 잘 통과하고 있으며 원하는대로 정확하게 테스트하고 있습니다.

그러나, 나는 더 빠르고 메모리 효율적인 방법은 copySrcIntoDstAt (...)를 대체합니다.

그게 내 질문의 핵심이다. 나는 이미지를 더 빠르게 채우는 방법이 아니다. (내가했던 것은 단위 테스트를하는 예제 일 뿐이다.) 내가 원했던 것은 이 무엇이 될 것인지를 아는 것이다. 빠른 속도와 메모리 효율적인 (즉, 빠르며 불필요한 객체를 생성하지 않는다).

필자가 만든 개념 증명 구현은 분명히 메모리 효율이 뛰어나지 만 속도가 느립니다 (각 픽셀에 대해 getRGBsetRGB 한 개를 수행함).

도식적으로,이있어 :

AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAABBBBAAA 
AAAAAAAAAAAAABBBBAAA 
AAAAAAAAAAAAAAAAAAAA 

여기서 'B :

AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 

(A는 복사하기 전에 대상 이미지에서 해당 픽셀을 나타내는 경우) 그리고 나는이 갖고 싶어 '는 src 이미지의 픽셀을 나타냅니다.

API 링크/견적이 아닌 copySrcIntoDstAt (...) 메서드의 정확한 대체품을 찾고 있습니다.

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); 
      } 
     } 
    } 

} 

답변

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 아주 좋은 ... 나는 * 될 것이다 갈 수있는 방법을 몇 가지 * System.arraycopy에를 사용하여 생각하지 않았다. 나는 모든 BufferedImage가 항상 래스터를 가지고 있고 여기에 객체 생성이 없다고 생각합니다!? 정말 좋지만 동시에 이상하게 보입니다. * for * 루프 및 System.arraycopy를 수동으로 수행하지 않고도 기존 작업을 수행 할 것으로 기대했을 것입니다. 하지만, 정말 멋지다. (그냥 시도해 보니 괜찮아 보인다.) – SyntaxT3rr0r

+0

@WizardOfOds 감사합니다. 여러분은 오프셋을 이동하는 데 필요한 어떤 종류의 루프가 "더 빠르고 더 효율적입니다"라고 강조했습니다. 복사를하지 않고 객체를 생성하지 않고 내부 구조를 조작하면 JNI가 아닌 메소드가 더 잘 수행 될 것입니다. – stacker

관련 문제