How to capture colors of an image in a JLabel that behind another JLabel?

1

I need to get the pixel colors of an image embedded in a JLabel with MouseMotionListener , and this JLabel is under or behind another JLabel. I know I can get a background color behind a JLabel, but what I need to capture are colors of an image that are inserted into a JLabel.

This is the code:

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.MouseMotionListener;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;


public class Main extends JFrame {

public static void main(String[] args) throws AWTException
{
    JFrame frame;
    Robot robot;
    JLayeredPane layeredPane;
    MouseMotionListener ml;

    robot = new Robot();
    frame = new JFrame("Pc");
    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

    layeredPane = new JLayeredPane();
    layeredPane.setPreferredSize(new Dimension(300, 310));
    layeredPane.setBorder(BorderFactory.createTitledBorder(
                                "capture color under the label"));
    JLabel label = new JLabel(new ImageIcon("folder/matiz.jpg"));
    label.setBounds(15, 15, 300, 300);
    label.setOpaque(true);
    label.setBackground(Color.red);

    JLabel label1 = new JLabel();
    label1.setBounds(60, 60, 300, 300);
    label1.setOpaque(true);
    label1.setBackground(new Color(255,255,255));

    layeredPane.add(label, 0, 0);
    layeredPane.add(label1, 1, 0);


    frame.setSize(660, 400);

    frame.getContentPane().setBackground(Color.red);
    frame.setGlassPane(layeredPane);
    layeredPane.setVisible(true);
    frame.setVisible(true); 

       ml = new MouseMotionAdapter() {

      public void mouseMoved(MouseEvent evt) {

          JLabel comp = (JLabel) evt.getSource();
          Point point = evt.getLocationOnScreen();

                Color color = robot.getPixelColor((int)point.getX(),(int)point.getY());
                System.out.println(color);
            }
  };        
            label1.removeMouseMotionListener(ml);
            label.addMouseMotionListener(ml);
    }
}
    
asked by anonymous 14.04.2017 / 04:14

1 answer

3

First and foremost I want to leave two alerts about your code:

  

Always start the screen inside the Event-Dispatch-Thread because swing is not < in> Thread-Safe , and the entire GUI needs to start within this unique Thread. This answer further explains the reason for this and any issues that may occur. This other answer shows you some ways to start the application within this Thread.

     

Avoid using absolute layout , the swing API comes in many Layouts Managers to make the programmer's life easier when creating screens, as well as making the screen flexible to different monitor sizes and resolutions, without requiring this to be handled directly in the code. Absolute layout will break the look of your application, depending on the monitor where the application is run.

Using the BufferedImage class you can get RGB colors of an image. First, you must create an instance of this class by passing the dimensions of the image:

BufferedImage bufImage = new BufferedImage(image.getIconWidth(), image.getIconHeight(),
                BufferedImage.TYPE_INT_RGB);

After this, you need to "populate" the buffer with the image. The JLabel is populated with a ImageIcon but the drawimage() " expects a type Image . You can retrieve this type from ImageIcon by getimage() :

    ImageIcon imgIcon= label.getIcon();
    Graphics g = bufImage.createGraphics();

    g.drawImage(imgIcon.getImage(), 0, 0, null);

With the image already buffered, just use the getRGB(x,y) to retrieve the RGB value of the pixel, according to the coordinates passed by the mouse movement, limiting to the image size:

    int x = (int) e.getX();
    int y = (int) e.getY();

    if(x < imgIcon.getIconWidth() && y < imgIcon.getIconHeight()){
        int rgb = bufImage.getRGB(x, y);
        System.out.println(new Color(rgb));
    }
Just inserting these snippets into your mouseMoved method would already solve the problem, but to separate the responsibility of handling the Label of the main class, better organize the code and make the component reusable, you can create a class of JLabel and apply those changes only to it. In this case, I created the class CustomLabel to exemplify:

class CustomLabel extends JLabel implements MouseMotionListener {

    private ImageIcon image;

    public CustomLabel(ImageIcon image) {
        this.image = image;
        setIcon(image);
        this.addMouseMotionListener(this);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // TODO Auto-generated method stub
    }

    @Override
    public void mouseMoved(MouseEvent e) {

        int x = (int) e.getX();
        int y = (int) e.getY();

        BufferedImage bufImage = new BufferedImage(image.getIconWidth(), image.getIconHeight(),
                BufferedImage.TYPE_INT_RGB);

        Graphics g = bufImage.createGraphics();

        g.drawImage(image.getImage(), 0, 0, null);

        if(x < image.getIconWidth() && y < image.getIconHeight()){
            int rgb = bufImage.getRGB(x, y);
            System.out.println(new Color(rgb));
        }

    }
}

To use in your code, simply create this class in your project and replace:

JLabel label = new JLabel(new ImageIcon("folder/matiz.jpg"));

by:

CustomLabel label = new CustomLabel(new ImageIcon("folder/matiz.jpg"));

See a working example of your code with the class above:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.net.*;

public class GetPixelImageComponent {

    public void showAndCreateGUI() throws MalformedURLException, AWTException {

        JFrame frame;
        Robot robot;
        JLayeredPane layeredPane;
        MouseMotionListener ml;

        robot = new Robot();
        frame = new JFrame("Pc");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        layeredPane = new JLayeredPane();
        layeredPane.setPreferredSize(new Dimension(300, 310));
        layeredPane.setBorder(BorderFactory.createTitledBorder("capture color under the label"));



        /** ESTAS DUAS LINHAS SÃO APENAS PARA DEMONSTRAÇÃO **/
        URL url = new URL("http://wimages.vr-zone.net/2013/06/10-15-2012-2-22-52-PM-300x300.png");
        CustomLabel label = new CustomLabel(new ImageIcon(url));

        //CustomLabel label = new JLabel(new ImageIcon("folder/matiz.jpg"));        
        label.setBounds(15, 15, 300, 300);
        label.setOpaque(true);
        label.setBackground(Color.black);

        JLabel label1 = new JLabel();
        label1.setBounds(60, 60, 300, 300);
        label1.setOpaque(true);
        label1.setBackground(new Color(255, 255, 255));

        layeredPane.add(label, 0, 0);
        layeredPane.add(label1, 1, 0);

        frame.setSize(660, 400);

        frame.getContentPane().setBackground(Color.red);
        frame.setGlassPane(layeredPane);
        layeredPane.setVisible(true);
        frame.setVisible(true);

    }

    public static void main(String[] args) throws Exception {
        EventQueue.invokeLater(() -> {
            try {
                new GetPixelImageComponent().showAndCreateGUI();
            } catch (MalformedURLException | AWTException e) {
                e.printStackTrace();
            }
        });
    }

    class CustomLabel extends JLabel implements MouseMotionListener {

        private ImageIcon image;

        public CustomLabel(ImageIcon image) {
            this.image = image;
            setIcon(image);
            this.addMouseMotionListener(this);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            // TODO Auto-generated method stub
        }

        @Override
        public void mouseMoved(MouseEvent e) {

            int x = (int) e.getX();
            int y = (int) e.getY();

            BufferedImage bufImage = new BufferedImage(image.getIconWidth(), image.getIconHeight(),
                    BufferedImage.TYPE_INT_RGB);

            Graphics g = bufImage.createGraphics();

            g.drawImage(image.getImage(), 0, 0, null);

            if(x < image.getIconWidth() && y < image.getIconHeight()){
                int rgb = bufImage.getRGB(x, y);
                System.out.println(new Color(rgb));
            }

        }
    }
}

That results in:

    
18.04.2017 / 15:14