您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Java Swing:如何获取JFrame像素的颜色

Java Swing:如何获取JFrame像素的颜色

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

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

本节中的代码用于测试上述方法性能。如果不正确,请在评论中让我知道,但是请注意,我对每种方法进行了大约300万次采样,以期避免附带的延迟。测试方法的每百万个样本中,我会打印一些时间,然后重新启动该过程以测试另外一百万个,最多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。有效性检查只是为了稍微验证所采样的颜色是否具有正确的值。

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

java 2022/1/1 18:25:38 有618人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶