95

There is already question like this link on StackOverflow and the accepted answer is "casting":

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

In my program I try:

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;

Unfortunatelly I get run time error:

sun.awt.image.ToolkitImage cannot be cast to java.awt.image.BufferedImage

Obviously casting does not work.
Question is: What is (or is there) the proper way of converting Image to BufferedImage?

Community
  • 1
  • 1
Arek Wilk
  • 1,062
  • 1
  • 9
  • 12
  • if you want to scale buffered image, try this try this [http://stackoverflow.com/questions/4216123/how-to-scale-a-bufferedimage][1] [1]: http://stackoverflow.com/questions/4216123/how-to-scale-a-bufferedimage – user902383 Nov 28 '12 at 12:41
  • 7
    For the record, it is NOT the compiler that is saying that. You are actually seeing a runtime error ... not a compilation error. – Stephen C Nov 28 '12 at 12:42
  • 1
    You are right. Thanks for pointing this out. I will edit question accordingly. – Arek Wilk Nov 28 '12 at 12:46
  • @user902383 Even if they are not answering my question directly - those are great solutions as well. – Arek Wilk Nov 28 '12 at 14:41
  • Small Thing to OP: Method `ImageIO.read(File)` returns a `BufferedImage` by its signature. ([Reference](http://docs.oracle.com/javase/6/docs/api/javax/imageio/ImageIO.html#read%28java.io.File%29)) There is no need to first assign to an `Image` variable then cast to type `BufferedImage`. That might confuse people reading your code. – kevinarpe Aug 08 '13 at 15:33
  • @kevinarpe - I thought it is quite clear that the part of code you mention is not actual mine. I wrote in the question - this is "accepted answer" from a [similar question](http://stackoverflow.com/questions/9132149/how-to-convert-buffered-image-to-image-and-vice-versa) on SO. – Arek Wilk Aug 12 '13 at 23:53
  • Why do you first create an `Image` object, and then cast it to a `BufferedImage`, when you have the option to create a `BufferedImage` from the beginning? – Daniel Kvist Dec 29 '14 at 14:40

4 Answers4

149

From a 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;
}
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Sri Harsha Chilakapati
  • 11,744
  • 6
  • 50
  • 91
  • Is it really necessary to copy the whole image memory? – Tomáš Zato Mar 15 '15 at 23:38
  • @TomášZato I think that's the only way to convert from an `Image` to a `BufferedImage`. You shouldn't be worrying about the memory when using Java. – Sri Harsha Chilakapati Mar 16 '15 at 04:14
  • 7
    @SriHarshaChilakapati `You shouldn't be worrying about the memory when using Java.` Judging from average memory consumption by Java applications, other developers definitely don't worry about memory a little bit. – Tomáš Zato Mar 16 '15 at 04:29
  • 1
    @TomášZato It seemed to me that you were from the C++ world, thinking to reuse the memory of the pixels of the image data. I mean by my previous comment that there is no need to worry about the memory in this case, as the GC will take care of it in Java. – Sri Harsha Chilakapati Mar 16 '15 at 05:24
  • 2
    @SriHarshaChilakapati So garbage collectors don't consume any resources? GC only saves you from the *code* surrounding memory. It doesn't eradicate a hardware limit. – Claire Sannier Jul 10 '15 at 03:56
  • 7
    This won't work if `Image` is not loaded yet, since `getWidth(null)` or `getHeight(null)` will return `-1` in the case – Dims Sep 22 '15 at 10:33
  • @Dims Yup true, but in order to convert, one must load the file. – Sri Harsha Chilakapati Sep 22 '15 at 12:57
  • 3
    I had to use `BufferedImage.TYPE_INT_RGB` instead of ARGB to get the colours of my thumbnail right – Stephanie Feb 25 '19 at 15:52
  • A simple example is created here 'https://github.com/satyarajp/ImageManager/tree/main/resize/src/main/java/com/dynimg/resize/controllers' for more clarity. Thanks @Stephani I also faced the same issue. – SatyaRajC Feb 18 '22 at 10:13
22

One way to handle this is to create a new BufferedImage, and tell it's graphics object to draw your scaled image into the new 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);

That should do the trick without casting.

salbeira
  • 2,375
  • 5
  • 26
  • 40
4

If you use Kotlin, you can add an extension method to Image in the same manner Sri Harsha Chilakapati suggests.

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
}

And use it like this:

myImage.toBufferedImage()
Steven Spungin
  • 27,002
  • 5
  • 88
  • 78
3

If you are getting back a sun.awt.image.ToolkitImage, you can cast the Image to that, and then use getBufferedImage() to get the BufferedImage.

So instead of your last line of code where you are casting you would just do:

BufferedImage buffered = ((ToolkitImage) image).getBufferedImage();
Hermann Hans
  • 1,798
  • 1
  • 13
  • 24
  • 10
    1) It is frowned upon to use classes from the `sun` package. They are not guaranteed to be available in non-Oracle JDKs. 2) Method `getBufferedImage()` only works if the buffered image has been generated internally by `TookitImage`. Most often (99%) it is not, so the return value is `null`. [Source Reference](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/awt/image/ToolkitImage.java#ToolkitImage.getBufferedImage%28%29) – kevinarpe Aug 07 '13 at 13:08