Java: come fare la copia veloce di un BufferedImage pixel? (Unit test inclusi)
-
26-09-2019 - |
Domanda
voglio fare una copia (di una zona di rettangolo) dei valori ARGB da una sorgente in un BufferedImage
BufferedImage
destinazione. No composizione dovrebbe essere fatto:. Se copio un pixel con un valore ARGB di 0x8000BE50 (alfa valore a 128), allora il pixel di destinazione deve essere esattamente 0x8000BE50, totalmente ignorando il pixel di destinazione
Ho una domanda molto precisa e ho fatto una prova di unità per mostrare quello che mi serve. Il test di unità è completamente funzionale e autonomo e sta passando bene e sta facendo esattamente quello che voglio.
Tuttavia, voglio un più veloce e più efficiente della memoria metodo per sostituire copySrcIntoDstAt (...).
Questo è il punto di tutta la mia domanda: io non sto cercando il modo per "riempire" l'immagine in un modo più veloce (quello che ho fatto è solo un esempio per avere una prova di unità). Tutto quello che voglio è sapere quello che sarebbe un veloce ed efficiente della memoria modo per farlo (cioè veloce e non la creazione di oggetti inutili).
L'implementazione proof-of-concept che ho fatto è ovviamente molto efficiente della memoria, ma è lento (eseguendo una getRGB
e uno setRGB
per ogni pixel).
Schematicamente, ho questo: (dove A indica pixel dall'immagine di destinazione corrispondente prima che la copia)
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
E voglio avere questo:
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAAAAAAAAA
dove 'B' rappresenta i pixel dalla src immagine.
Si noti che sto cercando un sostituto esatta del copySrcIntoDstAt (...) metodo, non per un collegamento API / preventivo.
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 );
}
}
}
}
Soluzione
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);
}
}