Search code examples
javagraphicscopybufferedimage

How to copy image data into a subclass of BufferedImage?


I have a class called Bitmap which extends from BufferedImage,

public class Bitmap extends BufferedImage {...

One of its methods called copyImage, which copies contents from a source image into the class, it worked but this method doesn't maintain the original aspect ratio and dimensions of the source image.

public void copyImage(Image image) {
    if (image != null) {
        BufferedImage bi = (BufferedImage) image;
        Graphics g = getGraphics();

        g.drawImage(bi, 0, 0, width, height, null);
    }
}

I want this method to copy the source image to the class with its original aspect ratio and dimensions maintained, I thought of resizing an width and height I modified the code above to this:

public void copyImage(Image image) {
    if (image != null) {
        this.width = image.getWidth(null);
        this.height = image.getWidth(null);

        BufferedImage bi = (BufferedImage) image;
        Graphics g = getGraphics();

        g.drawImage(bi, 0, 0, width, height, null);
    }
}

But it didn't work, how can I modify the code above to copy the image? Thanks in advance.


Solution

  • This is in error:

    public void copyImage(Image image) {
        if (image != null) {
            this.width = image.getWidth(null);
            this.height = image.getWidth(null);
    
            BufferedImage bi = (BufferedImage) image;
            Graphics g = getGraphics();
    
            g.drawImage(bi, 0, 0, width, height, null);
        }
    }
    

    Your main problems are:

    1. You appear to be trying to change the intrinsic width and height of the original image, the this image, and you shouldn't do this, not this way
    2. You are assigning the parameter image's width to the this.height field with this.height = image.getWidth(null);

    Other issues:

    • You're not conserving resources
    • You're making a dangerous and unnecessary cast

    and it should be

    public void copyImage(Image image) {
        if (image != null) {
            // don't change the width/height of your original image
            int width = image.getWidth(null);
            // int height = image.getWidth(null);
            int height = image.getHeight(null); // *** Note change ***
    
            // BufferedImage bi = (BufferedImage) image;  // *** no need ***
            Graphics g = getGraphics();
    
            g.drawImage(image, 0, 0, width, height, null);
            g.dispose();  // save resources
        }
    }   
    

    Test code using a MCVE showing proof of concept:

    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.image.BufferedImage;
    import java.io.IOException;
    import java.net.URL;
    
    import javax.imageio.ImageIO;
    import javax.swing.Icon;
    import javax.swing.ImageIcon;
    import javax.swing.JOptionPane;
    
    public class TestImage {
        public static final String SOMME_PATH = "https://upload.wikimedia.org/"
                + "wikipedia/commons/thumb/f/fa/Cheshire_Regiment_trench_Somme_1916.jpg"
                + "/1024px-Cheshire_Regiment_trench_Somme_1916.jpg";
        public static final String BATTLE_PATH = "https://upload.wikimedia.org/wikipedia/"
                + "commons/1/13/K%C3%A4mpfe_auf_dem_Doberdo.JPG";
    
        public static void main(String[] args) {
            int imgW = 1000;
            int imgH = 700;
            MyImage myImage = new MyImage(imgW, imgH, BufferedImage.TYPE_INT_ARGB);
            BufferedImage sommeTrench = null;
            BufferedImage battleOfDoberdò = null;
    
            try {
                URL url = new URL(SOMME_PATH);
                sommeTrench = ImageIO.read(url);
    
                url = new URL(BATTLE_PATH);
                battleOfDoberdò = ImageIO.read(url);
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(-1);
            }
    
            Icon icon = new ImageIcon(myImage);
            JOptionPane.showMessageDialog(null, icon, "Original MyImage", JOptionPane.PLAIN_MESSAGE);
    
            myImage.copyImage(sommeTrench);
            icon = new ImageIcon(myImage);
            JOptionPane.showMessageDialog(null, icon, "MyImage with Somme Trench", JOptionPane.PLAIN_MESSAGE);
    
            myImage.copyImage(battleOfDoberdò);        
            icon = new ImageIcon(myImage);
            JOptionPane.showMessageDialog(null, icon, "MyImage with Battle Of Doberdò", JOptionPane.PLAIN_MESSAGE);
    
        }
    }
    

    class MyImage extends BufferedImage {
    
        public MyImage(int width, int height, int imageType) {
            super(width, height, imageType);
        }
    
        public void copyImage(Image image) {
            if (image != null) {
                int width = image.getWidth(null);
    
                int height = image.getHeight(null); // *** Note change ***
    
                Graphics g = getGraphics();
    
                g.drawImage(image, 0, 0, width, height, null);
                g.dispose(); // save resources
            }
        }    
    }
    

    If you run this code you will see 3 images displaying as ImageIcons within 3 JOptionPanes, the first the original blank MyImage object, and then after 2 images from World War I have been copied into the original image.