/* * @(#)QuaquaColorPicker.java * * Copyright (c) 2005-2010 Werner Randelshofer, Immensee, Switzerland. * All rights reserved. * * You may not use, copy or modify this file, except in compliance with the * license agreement you entered into with Werner Randelshofer. * For details see accompanying license terms. */ package ch.randelshofer.quaqua.colorchooser; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import javax.swing.*; import javax.swing.colorchooser.*; import java.security.*; /** * QuaquaColorPicker. * * @author Werner Randelshofer * @version $Id: QuaquaColorPicker.java 363 2010-11-21 17:41:04Z wrandelshofer $ */ public class QuaquaColorPicker extends AbstractColorChooserPanel { /** * This frame is constantly moved to the current location of the mouse. * This ensures that we can trap mouse clicks while the picker cursor is * showing. Also, by tying the picker cursor to this frame, we ensure that * the picker cursor (the magnifying glass) is shown. */ private Dialog pickerFrame; private Timer pickerTimer; /** * Holds the image of the picker cursor. */ private BufferedImage cursorImage; /** * Graphics object used for drawing on the cursorImage. */ private Graphics2D cursorGraphics; /** * The picker cursor. */ private Cursor pickerCursor; /** * The hot spot of the cursor. */ private Point hotSpot; /** * Offset from the hot spot of the pickerCursor to the pixel that we want to pick. * We can't pick the color at the hotSpot of the cursor, because this point * is obscured by the pickerFrame. */ private Point pickOffset; /** * The magnifying glass image. */ private BufferedImage magnifierImage; /** * The robot is used for creating screen captures. */ private Robot robot; /** * The graphics device for which we created the robot. */ private GraphicsDevice captureScreen; /** * This is true, if we can't capture from this screen. */ private boolean isBadScreen = false; private Color previousColor = Color.white; private Point previousLoc = new Point(); private Point pickLoc = new Point(); private Point captureOffset = new Point(); private Rectangle captureRect; private final static Color transparentColor = new Color(0, true); private Rectangle zoomRect; private Rectangle glassRect; /** * Creates a new instance. */ public QuaquaColorPicker() { // Try immediately to create a screen capture in order to fail quickly, when // we can't provide a color picker functionality. try { captureScreen = GraphicsEnvironment.getLocalGraphicsEnvironment(). getDefaultScreenDevice(); robot = new Robot(); robot.createScreenCapture(new Rectangle(0, 0, 1, 1)); } catch (AWTException e) { throw new AccessControlException("Unable to capture screen"); } } /** * Gets the picker frame. * If the frame does not yet exist, it is created along with all the other * objects that are needed to make the picker work. */ private Dialog getPickerFrame() { if (pickerFrame == null) { Window owner = SwingUtilities.getWindowAncestor(this); if (owner instanceof Dialog) { pickerFrame = new Dialog((Dialog) owner); } else if (owner instanceof Frame) { pickerFrame = new Dialog((Frame) owner); } else { pickerFrame = new Dialog(new JFrame()); } pickerFrame.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { pickFinish(); } @Override public void mouseExited(MouseEvent evt) { updatePicker(); } }); pickerFrame.addMouseMotionListener(new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent evt) { updatePicker(); } }); pickerFrame.setSize(3, 3); pickerFrame.setUndecorated(true); pickerFrame.setAlwaysOnTop(true); pickerFrame.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_ESCAPE: pickCancel(); break; case KeyEvent.VK_ENTER: pickFinish(); break; } } }); magnifierImage = (BufferedImage) UIManager.get("ColorChooser.colorPickerMagnifier"); glassRect = (Rectangle) UIManager.get("ColorChooser.colorPickerGlassRect"); zoomRect = (Rectangle) UIManager.get("ColorChooser.colorPickerZoomRect"); hotSpot = (Point) UIManager.get("ColorChooser.colorPickerHotSpot");//new Point(29, 29); captureRect = new Rectangle((Rectangle) UIManager.get("ColorChooser.colorPickerCaptureRect")); pickOffset = (Point) UIManager.get("ColorChooser.colorPickerPickOffset"); captureOffset = new Point(captureRect.x, captureRect.y); cursorImage = getGraphicsConfiguration().createCompatibleImage(magnifierImage.getWidth(), magnifierImage.getHeight(), Transparency.TRANSLUCENT); cursorGraphics = cursorImage.createGraphics(); cursorGraphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR); pickerTimer = new Timer(5, new ActionListener() { public void actionPerformed(ActionEvent evt) { updatePicker(); } }); } return pickerFrame; } /** * Updates the color picker. */ protected void updatePicker() { if (pickerFrame != null && pickerFrame.isShowing()) { PointerInfo info = MouseInfo.getPointerInfo(); // Get a robot for the screen GraphicsDevice screen = info.getDevice(); if (captureScreen != screen) { isBadScreen = false; try { robot = new Robot(screen); captureScreen = screen; } catch (AWTException ex) { ex.printStackTrace(); isBadScreen = true; } } Point mouseLoc = info.getLocation(); pickerFrame.setLocation(mouseLoc.x - pickerFrame.getWidth() / 2, mouseLoc.y - pickerFrame.getHeight() / 2); pickLoc.x = mouseLoc.x + pickOffset.x; pickLoc.y = mouseLoc.y + pickOffset.y; if (pickLoc.x >= 0 && pickLoc.y >= 0) { Color c = robot.getPixelColor(pickLoc.x, pickLoc.y); if (!c.equals(previousColor) || !mouseLoc.equals(previousLoc)) { previousColor = c; previousLoc = mouseLoc; captureRect.setLocation(mouseLoc.x + captureOffset.x, mouseLoc.y + captureOffset.y); if (!isBadScreen && captureRect.x >= 0 && captureRect.y >= 0) { // Clear the cursor graphics cursorGraphics.setComposite(AlphaComposite.Src); cursorGraphics.setColor(transparentColor); cursorGraphics.fillRect(0, 0, cursorImage.getWidth(), cursorImage.getHeight()); try { // Fill the area for the zoomed screen capture with the // color on the screen cursorGraphics.setColor(robot.getPixelColor(pickLoc.x, pickLoc.y)); cursorGraphics.fillOval(glassRect.x, glassRect.y, glassRect.width, glassRect.height); // Paint the screen capture with a zoom factor of 5 BufferedImage capture = robot.createScreenCapture(captureRect); cursorGraphics.setComposite(AlphaComposite.SrcIn); cursorGraphics.drawImage(capture, zoomRect.x, zoomRect.y, zoomRect.width, zoomRect.height, this); } catch (Throwable e) { // we can't capture on this screen for some reason isBadScreen = true; } } if (isBadScreen) { // Fill the area for the zoomed screen capture with the // color on the screen cursorGraphics.setComposite(AlphaComposite.SrcOver); cursorGraphics.setColor(robot.getPixelColor(pickLoc.x, pickLoc.y)); cursorGraphics.fillOval(glassRect.x, glassRect.y, glassRect.width, glassRect.height); } // Draw the magnifying glass image cursorGraphics.setComposite(AlphaComposite.SrcOver); cursorGraphics.drawImage(magnifierImage, 0, 0, this); // We need to create a new subImage. This forces that // the color picker uses the new imagery. cursorImage.getSubimage(0, 0, cursorImage.getWidth(), cursorImage.getHeight()); pickerFrame.setCursor(getToolkit().createCustomCursor(cursorImage, hotSpot, "ColorPicker")); } } } } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { pickerButton = new javax.swing.JButton(); setLayout(new java.awt.BorderLayout()); pickerButton.setBorderPainted(false); pickerButton.setMargin(new java.awt.Insets(0, 0, 0, 0)); pickerButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { pickBegin(evt); } }); add(pickerButton, java.awt.BorderLayout.CENTER); }// </editor-fold>//GEN-END:initComponents private void pickBegin(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pickBegin getPickerFrame(); pickerTimer.start(); getPickerFrame().setVisible(true); }//GEN-LAST:event_pickBegin protected void pickFinish() { pickerTimer.stop(); pickerFrame.setVisible(false); PointerInfo info = MouseInfo.getPointerInfo(); Point loc = info.getLocation(); Color c = robot.getPixelColor(loc.x + pickOffset.x, loc.y + pickOffset.y); getColorSelectionModel().setSelectedColor(c); } protected void pickCancel() { pickerTimer.stop(); pickerFrame.setVisible(false); } protected void buildChooser() { initComponents(); pickerButton.setIcon(UIManager.getIcon("ColorChooser.colorPickerIcon")); } public String getDisplayName() { return UIManager.getString("ColorChooser.colorPicker"); } public Icon getLargeDisplayIcon() { return UIManager.getIcon("ColorChooser.colorPickerIcon"); } public Icon getSmallDisplayIcon() { return getLargeDisplayIcon(); } public void updateChooser() { } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton pickerButton; // End of variables declaration//GEN-END:variables }