2010-05-13 4 views
17

Я хочу сделать копию (области прямоугольника) значений ARGB от источника BufferedImage в пункт назначения BufferedImage. Никакой компоновки не должно быть сделано: если я копирую пиксель с ARGB значением 0x8000BE50 (значение альфа на 128), то целевой пиксель должен быть ровно 0x8000BE50, полностью перекрывая пиксель назначения.Java: как сделать быструю копию пикселей BufferedImage? (включенный тест)

У меня есть очень точный вопрос, и я сделал единичный тест, чтобы показать, что мне нужно. Единичный тест полностью функциональный и автономный и проходит отлично и делает именно то, что я хочу.

Однако, я хочу эффективный методбыстрее и больше памяти для замены copySrcIntoDstAt (...).

В этом весь мой вопрос: я не знаю, как «заполнить» изображение быстрее (то, что я сделал, является просто примером для модульного теста). Все, что я хочу, - это знать, что может сделать быстрый и эффективный способ сделать это (то есть быстро и не создавать ненужные объекты).

Реализация концептуальной концепции, которую я сделал, очевидно, очень эффективна с точки зрения памяти, но она медленная (делает один getRGB и один setRGB для каждого пикселя).

Схематично, у меня есть это: (где А обозначает соответствующие пиксели от целевого изображения до копии)

AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 

И я хочу, чтобы это:

AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAAAAAAAAA 
AAAAAAAAAAAAABBBBAAA 
AAAAAAAAAAAAABBBBAAA 
AAAAAAAAAAAAAAAAAAAA 

где «B 'представляет пиксели изображения src.

Обратите внимание, что я ищу точную замену метода copy44rsIntoDstAt (...) , а не для ссылки/цитаты 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); 
      } 
     } 
    } 

} 

ответ

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 * loop и System.arraycopy вручную. Но, да, действительно хорошо (просто попробовал это кстати, и это кажется прекрасным :) – SyntaxT3rr0r

+0

@WizardOfOds Спасибо, вы подчеркнули, что «быстрее и эффективнее с точки зрения памяти» какой-то цикл необходим для перемещения смещений. Манипулируя внутренними структурами, не делая копии и создавая объекты, я сомневаюсь, что будет работать не более JNI-метод. – stacker