2

is it possible to display two pictures, next to each other with BufferedImage and Graphics2D ? or should I do it with other method ?

In my code below, I was able to display two images, but the picture 1 overlaps to the picture 2.

package zdjecie;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

public class ObrazPanel extends JPanel {

    private BufferedImage image;
    private BufferedImage image2;

    public ObrazPanel() {
        super();

    File imageFile = new File("C:\\Users\\KostrzewskiT\\eclipse-workspace\\zdjecie\\src\\zdjecie\\java.jpg");
    File imageFile2 = new File("C:\\Users\\KostrzewskiT\\eclipse-workspace\\zdjecie\\src\\zdjecie\\java2.jpg"); 

        try {
            image = ImageIO.read(imageFile);
            image2 = ImageIO.read(imageFile2);
        } catch (IOException e) {
            System.err.println("Blad odczytu obrazka");
            e.printStackTrace();
        }


        Dimension dimension = new Dimension(image.getWidth(), image.getHeight());
        setPreferredSize(dimension);
        Dimension dimension2 = new Dimension(image2.getWidth(), image2.getHeight());
        setPreferredSize(dimension2);
    }


    @Override
    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(image, 0, 0, this);
        g2d.drawImage(image2, 200, 200, this);
    }
}
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • If they overlap, is it because you're not positioning them correctly? – Steve Smith Jan 28 '19 at 13:54
  • so how to position them correctly Steve ? – Tomasz Kostrzewski Jan 28 '19 at 13:55
  • And I think your `setPreferredSize(dimension);` code is wrong, since you're calling it on the JPanel. Are you hoping this will change the size of the images? – Steve Smith Jan 28 '19 at 13:55
  • 1
    Change the values in `g2d.drawImage(image2, 200, 200, this);` so they don't overlap. – Steve Smith Jan 28 '19 at 13:56
  • `with BufferedImage and Graphics2D ` - why? Just create an ImagIcon from the BufferedImage and use the ImageIcon to create a JLabel. Then you just add the label to the panel and you can use whatever layout manager you want to show the images. The default FlowLabel of a JPanel with display the images side by side. – camickr Jan 28 '19 at 15:30
  • 1) For better help sooner, [edit] to add a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). 2) One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). E.G. [This answer](https://stackoverflow.com/a/10862262/418556) hot links to an image embedded in [this question](https://stackoverflow.com/q/10861852/418556). (This is also demonstrated in [my answer](https://stackoverflow.com/a/54407143/418556) below.) – Andrew Thompson Jan 28 '19 at 17:19

4 Answers4

4

You call setPreferredSize twice, which results in the first call doing basically nothing. That means you always have a preferredSize equal to the dimensions of the second image. What you should do is to set the size to new Dimension(image.getWidth() + image2.getWidth(), image2.getHeight()) assuming both have the same height. If that is not the case set the height as the maximum of both images.

Secondly you need to offset the second image from the first image exactly by the width of the first image:

g2d.drawImage(image, 0, 0, this);
g2d.drawImage(image2, image.getWidth(), 0, this);
luk2302
  • 55,258
  • 23
  • 97
  • 137
2

The logic of the math was incorrect. See the getPreferredSize() method for the correct way to calculate the required width, and the changes to the paintComponent(Graphics) method to place them side-by-side.

An alternative (not examined in this answer) is to put each image into a JLabel, then add the labels to a panel with an appropriate layout.

This is the effect of the changes:

enter image description here

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.net.*;
import javax.imageio.ImageIO;

public class ObrazPanel extends JPanel {

    private BufferedImage image;
    private BufferedImage image2;

    public ObrazPanel() throws MalformedURLException {
        super();

        URL imageFile = new URL("https://i.stack.imgur.com/7bI1Y.jpg");
        URL imageFile2 = new URL("https://i.stack.imgur.com/aH5zB.jpg");

        try {
            image = ImageIO.read(imageFile);
            image2 = ImageIO.read(imageFile2);
        } catch (Exception e) {
            System.err.println("Blad odczytu obrazka");
            e.printStackTrace();
        }
    }

    @Override
    public Dimension getPreferredSize() {
        int w = image.getWidth() + image2.getWidth();
        int h1 = image.getHeight();
        int h2 = image2.getHeight();
        int h = h1>h2 ? h1 : h2;
        return new Dimension(w,h);
    }

    @Override
    public void paintComponent(Graphics g) {
        // always best to start with this.. 
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.drawImage(image, 0, 0, this);
        g2d.drawImage(image2, image.getWidth(), 0, this);
    }

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception useDefault) {
                }
                ObrazPanel o;
                try {
                    o = new ObrazPanel();
                    JFrame f = new JFrame(o.getClass().getSimpleName());
                    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                    f.setLocationByPlatform(true);

                    f.setContentPane(o);
                    f.pack();
                    f.setMinimumSize(f.getSize());

                    f.setVisible(true);
                } catch (MalformedURLException ex) {
                    ex.printStackTrace();
                }
            }
        };
        SwingUtilities.invokeLater(r);
    }
}
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
1

I found some errors in your code and I did not got what are you trying to do...

1] Over there you are actually not using the first setup

    Dimension dimension = new Dimension(image.getWidth(), image.getHeight());
    setPreferredSize(dimension); //not used
    Dimension dimension2 = new Dimension(image2.getWidth(), image2.getHeight());
    setPreferredSize(dimension2); //because overridden by this

It means, panel is having dimensions same as the image2, you should to set it as follows:

  • height as max of the heights of both images
  • width at least as summarize of widths of both pictures (if you want to paint them in same panel, as you are trying)

2] what is the image and image2 datatypes? in the block above you have File but with different naming variables, File class ofcourse dont have width or height argument

I am assuming its Image due usage in Graphics.drawImage, then:

You need to setup preferred size as I mentioned:

  • height to max value of height from images
  • width at least as summarize value of each widths

Dimensions things:

Dimension panelDim = new Dimension(image.getWidth() + image2.getWidth(),Math.max(image.getHeight(),image2.getHeight()));
setPreferredSize(panelDim)

Then you can draw images in the original size - due coordinates are having 0;0 in the left top corner and right bottom is this.getWidth(); this.getHeight() - check eg. this explanation - you need to start paint in the left bottom corner and then move to correct position increase "X" as the width of first image

@Override
public void paintComponent(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
        /* public abstract boolean drawImage(Image img,
        int x,
        int y,
        Color bgcolor,
        ImageObserver observer)
        */
    //start to paint at [0;0]
    g2d.drawImage(image, 0, 0, this); 
    //start to paint just on the right side of first image (offset equals to width of first picture)- next pixel on the same line, on the bottom of the screen 
    g2d.drawImage(image2,image2.getWidth()+1, 0, this);
}

I didn't had a chance to test it, but it should be like this. Important things are

  • you need to have proper dimensions for fitting both images
  • screen coordinates starts in the left top corner of the screens [0;0]
xxxvodnikxxx
  • 1,270
  • 2
  • 18
  • 37
1

I would join the images whenever something changes and draw them to another buffered image. Then I can just redraw the combined image whenever the panel needs to be redrawn.

Application

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;

public class SideBySideImagePanel extends JPanel {
    private static final long serialVersionUID = 5868633578732134172L;
    private BufferedImage left;
    private BufferedImage right;
    private BufferedImage join;

    public SideBySideImagePanel() {
        ClassLoader loader = this.getClass().getClassLoader();
        BufferedImage left = null, right = null;

        try {
            left = ImageIO.read(loader.getResourceAsStream("resources/Android.png"));
            right = ImageIO.read(loader.getResourceAsStream("resources/Java.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        this.setLeft(left);
        this.setRight(right);
    }

    public BufferedImage getLeft() {
        return left;
    }

    public void setLeft(BufferedImage left) {
        this.left = left;
    }

    public BufferedImage getRight() {
        return right;
    }

    public void setRight(BufferedImage right) {
        this.right = right;
    }

    @Override
    public void invalidate() {
        super.invalidate();
        join = combineImages(left, right);
        setPreferredSize(new Dimension(join.getWidth(), join.getHeight()));
    }

    @Override
    public void paintComponent(Graphics g) {
        g.drawImage(join, 0, 0, null);
    }

    private BufferedImage combineImages(BufferedImage left, BufferedImage right) {
        int width = left.getWidth() + right.getWidth();
        int height = Math.max(left.getHeight(), right.getHeight());
        BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
        Graphics g = combined.getGraphics();

        g.drawImage(left, 0, 0, null);
        g.drawImage(right, left.getWidth(), 0, null);

        return combined;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("Image Joiner");
                SideBySideImagePanel panel = new SideBySideImagePanel();

                frame.getContentPane().add(panel);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLocationRelativeTo(null);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132