2010-08-18 13 views
98

Mam obiekt, który zawiera wiele buforowanych obrazów, chcę utworzyć nowy obiekt, kopiując wszystkie buforowane obrazy do nowego obiektu, ale te nowe obrazy mogą zostać zmienione i nie chcę oryginalne obrazy obiektów można zmieniać, zmieniając obrazy nowych obiektów.Jak klonować obiekt BufferedImage

jest to jasne?

Czy można to zrobić i czy ktoś może zaproponować dobry sposób, aby to zrobić? Zastanowiłem się nad getSubImage, ale przeczytałem gdzieś, że wszelkie zmiany w podobrazie są odświeżane z powrotem do obrazu macierzystego.

Chcę po prostu być w stanie uzyskać świeży całkowicie oddzielną kopię lub klon BufferedImage

+1

nie można wywołać 'clone()' metoda? A może coś przeoczyłem? Nie wiem zbyt wiele na temat klonu "BufferedImage" klasy –

+1

zapewnia tylko płytką kopię, więc zawierałaby odniesienia do buforowanych obrazów; nie ich kopie. –

+7

@NoelM, UltimateGobblement: 'BufferedImage' nie implementuje' Cloneable', a metoda 'clone()' ma chroniony dostęp. – Robert

Odpowiedz

147

Coś takiego?

static BufferedImage deepCopy(BufferedImage bi) { 
ColorModel cm = bi.getColorModel(); 
boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); 
WritableRaster raster = bi.copyData(null); 
return new BufferedImage(cm, raster, isAlphaPremultiplied, null); 
} 
+2

dzięki ive użyłem tego do skopiowania mojego bufferedimage – f1wade

+3

Pożyczyłem to również w moim programie =) – BlackSheep

+0

Nie działa dla mnie! Kopia była o jeden piksel szersza. –

2

To było szalenie przydatna dla programu, który używam do rysowania rzeczy, i nie był w stanie wdrożyć Undo/Redo stanów powodu BufferedImages na Stosy jest praktycznie to samo.

Swoją drogą, proponuję całą drogę przy użyciu kilku stosów do tego rodzaju operacji! Za każdym razem gdy coś zrobić, natychmiast utworzyć nowy obraz, należy użyć metody deepcopy wspomniano powyżej

image = deepCopy((BufferedImage) stackUndo.peek()); 

zmieniać obraz jak należy, a kiedy przestać edycji (jak po zwolnieniu przycisku myszy) zrobić

stackUndo.push(image);                                  

i zawsze malować element w górnej części lewej stos

g.drawImage(stackUndo.peek(),x,y,null); 

a następnie, jeśli nie trochę cofnąć operację/redo, wykonaj coś jak to

public void undoOrRedo(String op) { 
    if(op.equals("undo") && stackUndo.size()>1){ 
     stackRedo.push(stackUndo.pop()); 
     repaint(); 
    } 
    if(op.equals("redo") && stackRedo.size()>0){ 
     stackUndo.push(stackRedo.pop()); 
     repaint(); 
    } 
} 

należy zawsze opuścił coś w lewym stosie, bo do malowania będzie zawsze użyć elementu w górnym (PEEK) od niego!

34

zrobić to:

public static BufferedImage copyImage(BufferedImage source){ 
    BufferedImage b = new BufferedImage(source.getWidth(), source.getHeight(), source.getType()); 
    Graphics g = b.getGraphics(); 
    g.drawImage(source, 0, 0, null); 
    g.dispose(); 
    return b; 
} 

To działa dość dobrze i jest prosty w obsłudze.

+2

To wygląda całkiem prosto. Dlaczego nie jest to najlepsza odpowiedź? Czy jest jakaś wada, o której nie wiem? – WVrock

+2

@WVrock Nie działa, jeśli typ obrazu to 0 (niestandardowe) –

+1

zamień grafikę g = b.getGraphics(); przez Graphics2D g = b.createGraphics(); i jest idealny – Nadir

13

Wymieniona wcześniej procedura kończy się niepowodzeniem po zastosowaniu do obrazów podrzędnych. Tutaj jest bardziej kompletne rozwiązanie:

public static BufferedImage deepCopy(BufferedImage bi) { 
    ColorModel cm = bi.getColorModel(); 
    boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); 
    WritableRaster raster = bi.copyData(bi.getRaster().createCompatibleWritableRaster()); 
    return new BufferedImage(cm, raster, isAlphaPremultiplied, null); 
} 
1

Innym sposobem jest użycie klasy Graphics2D narysować obraz na nowym pustym obrazem. To naprawdę nie klonuje obrazu, ale powoduje powstanie kopii tworzonego obrazu.

public static final BufferedImage clone(BufferedImage image) { 
    BufferedImage clone = new BufferedImage(image.getWidth(), 
      image.getHeight(), image.getType()); 
    Graphics2D g2d = clone.createGraphics(); 
    g2d.drawImage(image, 0, 0, null); 
    g2d.dispose(); 
    return clone; 
} 
0

Wiem, że to pytanie jest dość stary, ale dla przyszłych gości, oto rozwiązanie użyję:

Image oldImage = getImage(); 
Image newImage = oldImage.getScaledInstance(oldImage.getWidth(null), oldImage.getHeight(null), Image.SCALE_DEFAULT); 

Proszę mnie poprawić jeśli zmieniając tylko uzyskuje newImage wpływa również oryginalny obraz w jakikolwiek sposób.
->Javadoc for getScaledInstance
->Javadoc for SCALE_DEFAULT (pozostałe stałe są wymienione poniżej tej jednej)

+0

Myślę, że w rzeczywistości nie skopiowałbym obrazu, tj. Gdybyś zmienił oryginał, skalowany również zmieni się, ale przez jakiś czas był tak chory, niech ktoś inny powie na pewno. – f1wade