Java перетворює зображення в BufferedImage


83

У StackOverflow вже є таке питання, як це посилання, і прийнятою відповіддю є "лиття":

Image image = ImageIO.read(new File(file));
BufferedImage buffered = (BufferedImage) image;

У своїй програмі я намагаюся:

final float FACTOR  = 4f;
BufferedImage img = ImageIO.read(new File("graphic.png"));
int scaleX = (int) (img.getWidth() * FACTOR);
int scaleY = (int) (img.getHeight() * FACTOR);
Image image = img.getScaledInstance(scaleX, scaleY, Image.SCALE_SMOOTH);
BufferedImage buffered = (BufferedImage) image;

На жаль, я отримую помилку часу роботи:

sun.awt.image.ToolkitImage не можна передати в java.awt.image.BufferedImage

Очевидно, кастинг не працює.
Питання: Який (або існує) правильний спосіб перетворення зображення в BufferedImage?


якщо ви хочете плавно змінювати масштаб буферизованного зображення, спробуйте це спробувати це [ stackoverflow.com/questions/4216123 / ... [1]: stackoverflow.com/questions/4216123 / ...
user902383

7
Для запису, це говорить НЕ компілятор. Ви насправді бачите помилку виконання ... не помилку компіляції.
Stephen C

1
Ти правий. Дякуємо, що вказали на це. Я відредагую питання відповідно.
Арек Вілк

@ user902383 Навіть якщо вони не відповідають прямо на моє запитання - це теж чудові рішення.
Арек Вілк

Small Thing для OP: Метод ImageIO.read(File)повертає a BufferedImageпідписом. ( Посилання ) Немає необхідності спочатку призначати Imageзмінну, а потім відтворювати тип BufferedImage. Це може заплутати людей, які читають ваш код.
kevinarpe

Відповіді:


124

З Java Game Engine :

/**
 * Converts a given Image into a BufferedImage
 *
 * @param img The Image to be converted
 * @return The converted BufferedImage
 */
public static BufferedImage toBufferedImage(Image img)
{
    if (img instanceof BufferedImage)
    {
        return (BufferedImage) img;
    }

    // Create a buffered image with transparency
    BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);

    // Draw the image on to the buffered image
    Graphics2D bGr = bimage.createGraphics();
    bGr.drawImage(img, 0, 0, null);
    bGr.dispose();

    // Return the buffered image
    return bimage;
}

7
@SriHarshaChilakapati You shouldn't be worrying about the memory when using Java.Судячи із середнього споживання пам'яті програмами Java, інші розробники точно не хвилюються про пам'ять.
Томаш Зато - відновити Моніку

1
@ TomášZato Мені здалося, що ти з світу C ++ і думаєш використати пам'ять пікселів даних зображення повторно. Я маю на увазі під своїм попереднім коментарем, що в цьому випадку не потрібно турбуватися про пам'ять, оскільки GC подбає про це на Java.
Шрі Харша Чилакапаті,

2
@SriHarshaChilakapati Тож збирачі сміття не споживають жодних ресурсів? GC рятує лише від коду, що оточує пам’ять. Це не викорінює апаратне обмеження.
Andrew Sannier,

5
Це не буде працювати, якщо Imageще не завантажено, оскільки getWidth(null)або getHeight(null)повернеться -1у справу
Dims

1
Мені довелося використовувати BufferedImage.TYPE_INT_RGBзамість ARGB, щоб правильно підібрати кольори моєї мініатюри
Стефані

20

Один із способів вирішити це - створити новий BufferedImage і повідомити, що графічний об’єкт намалює масштабоване зображення в новому BufferedImage:

final float FACTOR  = 4f;
BufferedImage img = ImageIO.read(new File("graphic.png"));
int scaleX = (int) (img.getWidth() * FACTOR);
int scaleY = (int) (img.getHeight() * FACTOR);
Image image = img.getScaledInstance(scaleX, scaleY, Image.SCALE_SMOOTH);
BufferedImage buffered = new BufferedImage(scaleX, scaleY, TYPE);
buffered.getGraphics().drawImage(image, 0, 0 , null);

Це повинно зробити трюк без кастингу.


2
Ніколи не забувайте утилізувати створені графічні екземпляри
Шрі Харша Чилакапаті

Як "розпорядитися створеними графічними інтерфейсами"?
Буффало

Чи повинен тип у конструкторі BufferedImage збігатися з типом у getScaledInstance?
Дражен Бєловук

Ні, TYPE - це щось на зразок ARGB або RGBA, спосіб внутрішнього зберігання даних зображень - виберіть те, що найбільш природно сприймається для вашої програми; Просто загляньте у своє автозаповнення, набираючи BufferedImage. [Автозавершення], щоб побачити всі варіанти
salbeira

3

Якщо ви повертаєте a sun.awt.image.ToolkitImage, ви можете передати зображення до нього, а потім скористатися getBufferedImage (), щоб отримати BufferedImage.

Отже, замість останнього рядка коду, де ви проводите трансляцію, ви просто зробите:

BufferedImage buffered = ((ToolkitImage) image).getBufferedImage();

7
1) Використовувати класи з sunпакету з побоюванням. Вони не гарантовано будуть доступні в JDK, що не належать Oracle. 2) Метод getBufferedImage()працює лише в тому випадку, якщо буферизоване зображення було сформовано внутрішньо TookitImage. Найчастіше (99%) це не так, тому повертається значення null. Посилання на джерело
kevinarpe

3

Якщо ви використовуєте Kotlin, ви можете додати метод розширення до Image таким же чином, як пропонує Шрі Харша Чилакапаті.

fun Image.toBufferedImage(): BufferedImage {
    if (this is BufferedImage) {
        return this
    }
    val bufferedImage = BufferedImage(this.getWidth(null), this.getHeight(null), BufferedImage.TYPE_INT_ARGB)

    val graphics2D = bufferedImage.createGraphics()
    graphics2D.drawImage(this, 0, 0, null)
    graphics2D.dispose()

    return bufferedImage
}

І використовуйте його так:

myImage.toBufferedImage()
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.