Java: Wie schnell Kopie eines BufferedImage des Pixels zu tun? (Einheit Test eingeschlossen)
-
26-09-2019 - |
Frage
Ich mag eine Kopie tun (ein Rechteck Fläche) des ARGB Wertes von einer Quelle BufferedImage
in ein Ziel BufferedImage
. Kein Compositing getan werden soll. Wenn ich ein Pixel mit dem ARGB-Wert 0x8000BE50 (Alpha-Wert bei 128) zu kopieren, muss das Zielpixel sein genau 0x8000BE50, total Überschreiben den Zielpixels
Ich habe eine sehr präzise Frage, und ich machte einen Unit-Test zu zeigen, was ich brauche. Die Unit-Test ist voll funktionsfähig und in sich geschlossene und vergeht gut und tut genau das, was ich will.
Allerdings möchte ich eine schneller und speichereffiziente Methode ersetzen copySrcIntoDstAt (...).
Das ist der ganze Punkt meiner Frage: Ich bin nicht nach, wie man „fill“ das Bild in einem schnelleren Weg (was ich tat, ist nur ein Beispiel eine Einheit Test haben). Alles, was ich will, ist zu wissen, was ein schneller und effiziente Speicher , wie es (dh schnell und nicht zu schaffen unnötigen Objekte) zu tun wäre.
Die Proof-of-Concept-Implementierung ich gemacht habe, ist offensichtlich sehr speichereffizient, aber es ist langsam (tut einem getRGB
und ein setRGB
für jedes Pixel).
Schematisch, ich habe diese bekommt: (wobei A zeigt Pixel von dem Zielbild vor der Kopie entspricht)
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
Und ich will diese haben:
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAAAAAAAAA
Dabei steht 'B' steht für die Pixel aus der src Bild.
Beachten Sie, dass ich für einen exakten Ersatz der Suche copySrcIntoDstAt (...) Methode nicht für eine API-Link / quote.
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 );
}
}
}
}
Lösung
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);
}
}