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

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


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()
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.