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
Ты прав. Спасибо за указание на это. Отредактирую вопрос соответственно.
Arek Wilk
@ user902383 Даже если они не отвечают на мой вопрос напрямую - это тоже отличные решения.
Arek Wilk
Мелочь для OP: метод ImageIO.read(File)возвращает BufferedImageподпись. ( Ссылка ) Нет необходимости сначала назначать Imageпеременной, а затем приводить ее к типу BufferedImage. Это может сбить с толку людей, читающих ваш код.
kevinarpe 08

Ответы:

124

Из игрового движка Java :

/**
 * 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-приложениями, другие разработчики определенно не беспокоятся о памяти.
Tomáš Zato - Reinstate Monica
1
@ TomášZato Мне показалось, что вы из мира C ++ думаете повторно использовать память пикселей данных изображения. Под своим предыдущим комментарием я подразумеваю, что в этом случае не нужно беспокоиться о памяти, так как GC позаботится об этом в Java.
Шри Харша Чилакапати,
2
@SriHarshaChilakapati Значит, сборщики мусора не потребляют никаких ресурсов? GC только избавляет вас от кода, окружающего память. Это не устраняет аппаратных ограничений.
Эндрю Санниер
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);

Это должно сработать без кастинга.

Salbeira
источник
2
Никогда не забывайте избавляться от созданных экземпляров графики
Шри Харша Чилакапати
Как «избавиться от созданных графических интерфейсов»?
Buffalo
Должен ли тип в конструкторе BufferedImage совпадать с типом в getScaledInstance?
Drazen Bjelovuk
Нет, TYPE - это что-то вроде ARGB или RGBA, способ хранения данных изображения внутри - выберите то, что наиболее естественно для вашего приложения; Просто загляните в свое автозаполнение при вводе BufferedImage. [Автозаполнение], чтобы увидеть все варианты
salbeira
3

Если вы возвращаете a sun.awt.image.ToolkitImage, вы можете применить к нему Image, а затем использовать 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()
Стивен Спунгин
источник