Java Swing:如何获取JFrame像素的颜色 [英] Java Swing: how to get the color of a pixel of a JFrame

查看:61
本文介绍了Java Swing:如何获取JFrame像素的颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为组件的选定(x,y)像素获取Swing JFrame的颜色.

I'm trying to get the color of a Swing JFrame, for a chosen (x,y) pixel of the component.

例如,我想知道给定 JFrame 在其(0,0)点处的颜色.

For example, I want to know the color of a given JFrame at their (0,0) point.

原因是我的组件是部分透明的覆盖层,下面是 JPanel .对于不透明的像素,鼠标事件应由叠加层处理.对于透明的像素,应该将鼠标事件转发到下面的 JPanel .

The reason is that my component is a partially transparent overlay, with a JPanel underneath. For pixels that are opaque, the mouse events should be dealt by the overlay. For pixels that are transparent, the mouse events should instead be forwarded to the JPanel underneath.

这是做到这一点的方法吗?

Is this a way to do this?

推荐答案

我想说(希望这样做会带来更好的性能),如果您愿意使用 Image 方法为此,最好创建一个尺寸为1x1像素的图像,然后转换其创建的图形以匹配请求的点.并将此图像重新用于同一 Component (甚至是 GraphicsConfiguration )的后续采样.

I would like to say (hoping this will introduce better performance) that maybe, if you are willing to go with the Image approach for this, it could be good to create an image of dimensions 1x1 pixels and then translate its created graphics to match the requested point. And also reuse this image for subsequent samplings of the same Component (or even GraphicsConfiguration).

我通过创建以下方法进行了一些性能测试:

I did some performance tests with creating the following approaches:

  1. 一种称为 getColorAtClipped 的方法,该方法设置了 Image 的创建的 Graphics 的剪辑,因此不必绘制所有操作.
  2. 一种名为 getColorAtRelocation 的方法,该方法将组件的位置临时设置在需要采样的位置,然后(实际上使速度更快)创建尺寸为1x1的图像并在其上绘制父对象.尽管此方法对于Swing来说并不是真正的线程安全方法,因为它需要前后设置 Component 的位置.它还为父容器 Container 调用 printAll ,这意味着需要绘制更多的 Component .
  3. 然后一个名为 getColorAtTranslation 的方法将创建一个1x1图像并转换其 Graphics 实例,以便所需的位置实际上将绘制在(0,0)处,即图像中实际上只有像素.事实证明,对于这前三种方法来说,这种方法是最快的.
  4. 那为什么不为以后的样本重用相同的资源呢?...这导致了我的最终方法:一个包含所有参与样本的必需资源的类:一个名为 ComponentColorSampler 的类以下代码
  1. A method called getColorAtClipped which sets the clip of the created Graphics of the Image so not all operations have to be drawn.
  2. A method called getColorAtRelocation which sets the location of the component temporarily at the location needed to be sampled and then (what actually makes it faster) create an image of dimensions 1x1 and draw the parent on it. Although this method is not really thread safe for Swing as it requires to set the location of the Component back and forth. It also calls printAll for the parent Container which means more Components to be painted.
  3. Then a method called getColorAtTranslation which creates an 1x1 image and translates its Graphics instance so as the required location will be drawn actually at (0,0) which is the only pixel really in the image. This method turned out to be the fastest for up to this 3 first methods.
  4. Then why not reuse the same resources for subsequent samples?... So that leads me to the final approach: a class enclosing all required resources which participate in the sampling: the one called ComponentColorSampler in the following code

测试代码:

本节中将介绍用于测试上述方法的性能的代码.如果不正确,请在评论中让我知道,但请注意,我对每种方法进行了约300万次采样,以期避免附带的延迟.每百万种测试方法的样本中,我会打印一些时间,然后重新启动该过程以测试另外一百万种(最多3个).

Testing code:

A code to test the performance of the above approaches follows in this section. If it is not correct, let me know in the comments, but be aware that I ran each method for about 3 million samplings in hope that collateral delays will be dwarfed. Every million samples of a test method, I printed some timings, and then restarted the process to test another million, up to 3.

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;
import java.util.function.IntBinaryOperator;
import java.util.function.Supplier;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Main {

    public static Color getColorAtClipped(final Component comp, final Point p) {
        final BufferedImage bimg = comp.getGraphicsConfiguration().createCompatibleImage(comp.getWidth(), comp.getHeight());
        final Graphics2D g2d = (Graphics2D) bimg.createGraphics();
        g2d.setClip(p.x, p.y, 1, 1);
        comp.printAll(g2d);
        g2d.dispose();
        final Color c = new Color(bimg.getRGB(p.x, p.y), true);
        bimg.flush();
        return c;
    }

    public static Color getColorAtRelocation(final Component comp, final Point p) {
        final Point loc = comp.getLocation();
        final BufferedImage bimg = comp.getGraphicsConfiguration().createCompatibleImage(1, 1);
        comp.setLocation(loc.x - p.x, loc.y - p.y);
        final Graphics2D g2d = (Graphics2D) bimg.createGraphics();
        //g2d.setClip(0, 0, 1, 1);
        comp.getParent().printAll(g2d);
        comp.setLocation(loc);
        g2d.dispose();
        final Color c = new Color(bimg.getRGB(0, 0), true);
        bimg.flush();
        return c;
    }

    public static Color getColorAtTranslation(final Component comp, final Point p) {
        final BufferedImage bimg = comp.getGraphicsConfiguration().createCompatibleImage(1, 1);
        final Graphics2D g2d = (Graphics2D) bimg.createGraphics();
        g2d.translate(-p.x, -p.y);
        //g2d.setClip(0, 0, 1, 1);
        comp.printAll(g2d);
        g2d.dispose();
        final Color c = new Color(bimg.getRGB(0, 0), true);
        bimg.flush();
        return c;
    }

    public static class ComponentColorSampler<C extends Component> implements AutoCloseable, IntBinaryOperator, Supplier<C> {
        private final C comp;
        private final BufferedImage bimg;
        private final Graphics2D g2d;
        private int x, y;

        public ComponentColorSampler(final C comp) {
            this.comp = Objects.requireNonNull(comp);
            bimg = comp.getGraphicsConfiguration().createCompatibleImage(1, 1);
            g2d = bimg.createGraphics();
            //g2d.setClip(0, 0, 1, 1);
            x = y = 0;
        }

        @Override
        public C get() {
            return comp;
        }

        @Override
        public int applyAsInt(final int x, final int y) {
            g2d.clearRect(0, 0, 1, 1);
            g2d.translate(this.x - x, this.y - y);
            this.x = x;
            this.y = y;
            comp.printAll(g2d);
            return bimg.getRGB(0, 0);
        }

        public Color sample(final int x, final int y) {
            return new Color(applyAsInt(x, y), true);
        }

        @Override
        public void close() {
            g2d.dispose();
            bimg.flush();
        }
    }

    public static class DrawPanel extends JPanel {
        private final int x, y;
        private Color c;

        public DrawPanel(final int x, final int y) {
            this.x = x;
            this.y = y;
            c = Color.BLUE;
        }

        @Override
        protected void paintComponent(final Graphics g) {
            super.paintComponent(g);
            g.setColor(c);
            g.fillRect(x, y, 1, 1);
        }

        public void setColor(final Color c) {
            this.c = Objects.requireNonNull(c);
            paintImmediately(0, 0, getWidth(), getHeight()); //Not sure yet.
            repaint(); //Just to be sure now.
        }
    }

    //@SuppressWarnings("SleepWhileInLoop")
    public static boolean checkValid(final DrawPanel dp, final Supplier<Color> sampler) throws InterruptedException, InvocationTargetException {
        for (final Color c: new Color[]{Color.BLUE, Color.RED, Color.BLACK, Color.WHITE, Color.BLACK, Color.CYAN}) {
            SwingUtilities.invokeAndWait(() -> dp.setColor(c));
            Thread.sleep(250); //Let it some time to change (not sure if needed).
            if (!Objects.equals(c, sampler.get()))
                return false;
        }
        return true;
    }

    public static long checkTime(final Supplier<Color> sampler) {
        final long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000; ++i)
            sampler.get();
        return System.currentTimeMillis() - start;
    }

    public static void main(final String[] args) throws InterruptedException, InvocationTargetException {

        final Point p = new Point(100, 100);

        final DrawPanel contents = new DrawPanel(p.x, p.y);

        contents.setPreferredSize(new Dimension(200, 200));

        final JFrame frame = new JFrame("Printed!");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(contents);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);

        final ComponentColorSampler<Component> sampler = new ComponentColorSampler<>(contents);

        final Supplier<Color> clipped = () -> getColorAtClipped(contents, p),
                              relocation = () -> getColorAtRelocation(contents, p),
                              translation = () -> getColorAtTranslation(contents, p),
                              samplerSampler = () -> sampler.sample(p.x, p.y);

        System.out.println("#### Validity checks...");
        for (int i = 0; i < 3; ++i) {
            System.out.println("Batch " + (i + 1) + ':');
            System.out.println("> Clipped: " + checkValid(contents, clipped) + '.');
            System.out.println("> Relocation: " + checkValid(contents, relocation) + '.');
            System.out.println("> Translation: " + checkValid(contents, translation) + '.');
            System.out.println("> Sampler: " + checkValid(contents, samplerSampler) + '.');
        }

        System.out.println("#### Timings...");
        for (int i = 0; i < 3; ++i) {
            System.out.println("Batch " + (i + 1) + ':');
            System.out.println("> Clipped: " + checkTime(clipped) + "ms.");
            System.out.println("> Relocation: " + checkTime(relocation) + "ms.");
            System.out.println("> Translation: " + checkTime(translation) + "ms.");
            System.out.println("> Sampler: " + checkTime(samplerSampler) + "ms.");
        }

        System.out.println("#### Done.");
    }
}

结果:

程序输出:

#### Validity checks...
Batch 1:
> Clipped: true.
> Relocation: true.
> Translation: true.
> Sampler: true.
Batch 2:
> Clipped: true.
> Relocation: true.
> Translation: true.
> Sampler: true.
Batch 3:
> Clipped: true.
> Relocation: true.
> Translation: true.
> Sampler: true.
#### Timings...
Batch 1:
> Clipped: 34668ms.
> Relocation: 22737ms.
> Translation: 5416ms.
> Sampler: 1152ms.
Batch 2:
> Clipped: 38521ms.
> Relocation: 22805ms.
> Translation: 5451ms.
> Sampler: 1156ms.
Batch 3:
> Clipped: 38275ms.
> Relocation: 22864ms.
> Translation: 5415ms.
> Sampler: 1163ms.
#### Done.

因此,对于一百万个样本,第一种方法大约需要37秒,第二种方法大约需要22秒,第三种方法大约需要5秒,最后一种方法恰好超过1秒(对于一百万个样本).因此, ComponentColorSampler 是这些测试中最快的实现方式(每毫秒约865个样本),并且可以在任何 Component 上使用.有效性检查只是为了在某种程度上验证所采样的颜色是否具有正确的值.

So the first approach is about 37 seconds for a million samples, the second approach is about 22, the third 5 and finally the last approach is just above 1 second (for a million samples). So ComponentColorSampler is the fastest implementation in these tests (about 865 samples per millisecond) and works on any Component. Validity checks just stand for somewhat verifying that the sampled color has the correct value.

注意:这些测试不是Swing/线程安全的,但指出了正确使用它们(例如在事件调度线程上执行采样)的性能.

Note: The tests are not Swing/thread safe but indicate what would be the performance if you used them properly (for example executing the samplings on the Event Dispatch Thread).

这篇关于Java Swing:如何获取JFrame像素的颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆