Як клонувати BuferiImage


120

У мене є об'єкт, у якому багато буферизованих зображень, я хочу створити новий об'єкт, який копіює всі буферизовані зображення в новий об’єкт, але ці нові зображення можуть бути змінені, і я не хочу, щоб оригінальні зображення об'єкта були змінені зміною зображення нових об'єктів.

це зрозуміло?

Чи можливо це зробити і чи може хтось запропонувати хороший спосіб зробити це, будь ласка? Я подумав про getSubImage, але десь прочитав, що будь-які зміни в субмагніті повертаються до батьківського зображення.

Я просто хочу мати змогу отримати свіжу цілком окрему копію або клон BufferedImage


1
ви не можете викликати clone()метод? Або я щось пропустив? Я не знаю багато про BufferedImageклас
Ноель М,

1
клон надає лише дрібну копію, щоб вона містила посилання на забуферовані зображення; не їх копії.
Ultimate Gobblement

7
@NoelM, UltimateGobblement: BufferedImageне реалізується Cloneableі clone()метод захищає доступ.
Роберт

Відповіді:


173

Щось на зразок цього?

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);
}

4
Я також запозичую це у своїй програмі =)
Даніель Кац

випустили цей метод при копіюванні
підрозділу

7
Хоча це працює за більшості обставин, він не працює належним чином, коли BufferedImage був обрізаний (він повертає все зображення до його обрізання). Просте виправлення цього полягає в тому, щоб змінити останній рядок на:
HaydenStudios

3
повернути новий BufferedImage (см, растр, isAlphaPremultipted, null) .getSubimage (0, 0, bi.getWidth (), bi.getHeight ());
HaydenStudios

copyData (null) не завжди працює, тому що він може працювати на батьківському растрі (тобто, коли зображення є
допоміжним

46

Я роблю це:

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;
}

Він працює досить добре і простий у використанні.


3
Це виглядає досить просто. Чому це не найкраща відповідь? Чи є недолік, про який я не знаю?
WVrock

2
@WVrock Це не працює, якщо тип зображення 0 (звичайний)
Tilman Hausherr

3
замінити графіку g = b.getGraphics (); by Graphics2D g = b.createGraphics (); і це ідеально
Надір

1
Я думаю, що це найчистіша відповідь. Хоча чи є різниця між виконанням та прийнятою відповіддю? Я відчуваю себе нікчемним, якщо ні? Чи може це бути швидше, тому що створення об'єкта оптимізовано в jvm. Також використовую openjdk 11. Якщо хтось може відповісти на це питання.
thekevshow

18

Згадана раніше процедура не працює при застосуванні до додаткових зображень. Ось більш повне рішення:

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);
}

Дякую, я отримував помилку зсуву, намагаючись клонувати підмножину. Ця версія саме те, що мені було потрібно.
рококо

5

Інший спосіб - використовувати Graphics2Dклас для малювання зображення на новому порожньому зображенні. Це насправді не клонує зображення, але це призводить до отримання копії зображення.

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;
}


4

Я знаю, що це питання досить давнє, але для майбутніх відвідувачів ось таке рішення я б використав:

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

Будь ласка, виправте мене, якщо зміна тільки що отриманого newImageтакож будь-яким чином вплине на оригінальне зображення.
-> Javadoc для getScaledInstance
-> Javadoc для SCALE_DEFAULT (інші константи перераховані трохи нижче цієї)


Я думаю, що насправді це не буде копіювати зображення, тобто, якщо ви змінили оригінал, то масштабне зміна також зміниться, але це було деякий час, так хворий, нехай хтось інший скаже точно.
f1wade

1
Це насправді копіює зображення, оскільки зміни оригіналу не змінять копію. Ця відповідь коротка і коротка і не обмежується навіть BufferedImages. Єдине питання полягає в тому, що він повертається Image, а не BufferedImage.
Kröw
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.