Voglio fare una copia (di un'area rettangolare) dei valori ARGB da una fonte BufferedImage
in una destinazione BufferedImage
. Nessun compositing dovrebbe essere fatto: se copio un pixel con un valore ARGB di 0x8000BE50 (valore alfa a 128), il pixel di destinazione deve essere esattamente 0x8000BE50, ignorando totalmente il pixel di destinazione.Java: come eseguire una copia veloce dei pixel di BufferedImage? (unit test incluso)
Ho una domanda molto precisa e ho fatto un test unitario per mostrare ciò di cui ho bisogno. Il test unitario è completamente funzionale e autonomo e sta passando bene e sta facendo esattamente quello che voglio.
Tuttavia, voglio un efficiente metodo di memoria più veloce e più per sostituire copySrcIntoDstAt (...).
Questo è il punto della mia domanda: non sto cercando di "riempire" l'immagine in un modo più veloce (quello che ho fatto è solo un esempio per fare un test unitario). Tutto quello che voglio è sapere quale sarebbe il modo veloce ed efficiente per farlo (cioè veloce e non creare oggetti inutili).
L'implementazione di proof-of-concept che ho realizzato è ovviamente molto efficiente in termini di memoria, ma è lenta (eseguendo uno getRGB
e uno setRGB
per ogni pixel).
Schematicamente, ho questo: (dove A indica pixel corrispondenti dal dell'immagine di destinazione prima della copia)
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
E voglio avere questo:
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAABBBBAAA
AAAAAAAAAAAAAAAAAAAA
dove 'B 'rappresenta i pixel dell'immagine src.
Nota che sto cercando una sostituzione esatta del metodo copySrcIntoDstAt (...), non per un collegamento/preventivo 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);
}
}
}
}
+1 molto bello ... Non ho mai pensato utilizzando diversi * * System.arraycopy sarebbe la strada da percorrere. Suppongo che ogni BufferedImage abbia sempre un raster e che non ci sia creazione di oggetti in corso qui a destra !? È davvero bello ma allo stesso tempo sembra un po 'strano: mi sarei aspettato qualcosa di preesistente nel fare il lavoro senza dover fare manualmente un ciclo * for * e System.arraycopy. Ma, sì, davvero bello (l'ho appena provato e mi sembra bello :) – SyntaxT3rr0r
@WizardOfOds Grazie, hai sottolineato "più veloce e più efficiente in termini di memoria" è sempre necessario un qualche tipo di ciclo per spostare gli offset. Manipolando le strutture interne senza fare copie e creando oggetti, dubito che ci sarebbe un metodo non JNI che funzioni meglio. – stacker