Search code examples
bufferedimagepixel

Loading the pixels of a scaled BufferedImage


I'm trying to scale an image to a different width, and height. Then create a pixel array from the pixels of the scaled image. The problem is I get an error.

 java.lang.ClassCastException: sun.awt.image.ToolkitImage cannot be cast to java.awt.image.BufferedImage    

any way I can get the pixels of the new sized image?

here is the code:

protected void scaleImage(int newWidth, int newHeight) {
    try {

        BufferedImage image = (BufferedImage) img.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);

        width = newWidth;
        height = newHeight;
        scaledWidth = newWidth;
        scaledHeight = newHeight;
        //re init the pixels
        pixels = new int[scaledWidth * scaledHeight];

        ((BufferedImage) image).getRGB(0, 0, scaledWidth, scaledHeight, pixels, 0, scaledWidth);
    } catch (Exception e) {
        e.printStackTrace();
        System.exit(0);
    }
}

Solution

  • The problem you run into is that image.getScaledInstance(...) returns an image, regardless of whether image is an Image or a BufferedImage.

    Now, for this reason (and others, mainly performance-related) it is not recommended to use image.getScaledImage(...). See for example The Perils of Image.getScaledInstance() for more information, and some alternative methods of scaling.

    Adapted from your code, you can use:

    int newWidth, int newHeight; // from method parameters
    
    BufferedImage image = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
    Graphics2D g = image.createGraphics();
    
    try {
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.drawImage(img, 0, 0, newWidth, newHeight, null);
    }
    finally {
        g.dispose();
    }
    
    scaledWidth = newWidth;
    scaledHeight = newHeight;
    
    //re init the pixels
    pixels = new int[scaledWidth * scaledHeight];
    image.getRGB(0, 0, scaledWidth, scaledHeight, pixels, 0, scaledWidth);
    

    See the above link for a step-wise alternative, or use a library like imgscalr for even better results.

    If you really want to use getScaledInstace() even after you read the above link, you can use the ImageProducer/ImageConsumer API, to get at the pixels in asynchronous fashion. But the API is old and a little inconvenient to work with.