Java: comment faire une copie rapide d'un pixel de BufferedImage? (Test unitaire inclus)
-
26-09-2019 - |
Question
Je veux faire une copie (d'une zone rectangulaire) des valeurs ARVB d'une BufferedImage
source dans un BufferedImage
de destination. Non compositing doit être fait. Si je copie un pixel avec une valeur ARGB de 0x8000BE50 (alpha valeur à 128), le pixel de destination doit être exactement 0x8000BE50, remplaçant totalement le pixel de destination
J'ai une question très précise et j'ai fait un test unitaire pour montrer ce que je dois. Le test unitaire est entièrement fonctionnelle et autonome et passe très bien et fait exactement ce que je veux.
Cependant, je veux un plus rapide et plus efficace de la mémoire méthode pour remplacer copySrcIntoDstAt (...).
C'est tout le point de ma question: je ne suis pas après comment « remplir » l'image d'une manière plus rapide (ce que je faisais est juste un exemple pour un test unitaire). Tout ce que je veux est de savoir ce qui serait un rapide et efficace de la mémoire façon de le faire (par exemple rapide et ne pas créer des objets inutiles).
La preuve de concept mise en œuvre, je l'ai fait est évidemment très efficace de la mémoire, mais il est lent (faire un getRGB
et un setRGB
pour chaque pixel).
Schématiquement, j'ai ceci: (où A indique pixels correspondant de l'image de destination avant la copie)
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
Et je veux avoir ceci:
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAAAAAAAAA
où 'B' représente les pixels dans src image.
Notez que je suis à la recherche d'un remplacement exact de la copySrcIntoDstAt (...) méthode, pas un lien API / citation.
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 );
}
}
}
}
La solution
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);
}
}