• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In
Build has been canceled!

jiangxincode / ApkToolBoxGUI / #626

02 Mar 2024 03:25AM UTC coverage: 3.232%. Remained the same
#626

push

jiangxincode
Merge branch 'master' of https://github.com/jiangxincode/ApkToolBoxGUI

240 of 7425 relevant lines covered (3.23%)

0.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/main/java/edu/jiangxin/apktoolbox/convert/color/ColorPickerPanel.java
1
package edu.jiangxin.apktoolbox.convert.color;
2

3
import edu.jiangxin.apktoolbox.swing.extend.EasyPanel;
4
import edu.jiangxin.apktoolbox.utils.Constants;
5
import org.apache.commons.lang3.StringUtils;
6

7
import java.awt.*;
8
import java.awt.event.ActionEvent;
9
import java.awt.geom.Line2D;
10
import java.awt.geom.Rectangle2D;
11

12
import javax.swing.*;
13

14
import java.util.LinkedList;
15
import java.util.Timer;
16
import java.util.TimerTask;
17

18
import java.awt.datatransfer.Clipboard;
19
import java.awt.datatransfer.Transferable;
20
import java.awt.datatransfer.StringSelection;
21

22
public class ColorPickerPanel extends EasyPanel {
×
23

24
    enum ColorMode {
×
25
        RGB, HTML, HEX, HSB
×
26
    }
27

28
    private static final long serialVersionUID = 1L;
29

30
    private static final int TOP_PADDING = 20;
31

32
    private static final int BOTTOM_PADDING = 20;
33

34
    private static final int LEFT_PADDING = 10;
35

36
    private static final int RIGHT_PADDING = 10;
37

38
    private static final int TEXT_AREA_WIDTH = 200;
39

40
    private static final int DEFAULT_HEIGHT_SMALL = 20;
41

42
    private static final int DEFAULT_HEIGHT_BIG = 100;
43

44
    private static final int DEFAULT_WIDTH = 100;
45

46
    private static final int WIDTH = LEFT_PADDING + DEFAULT_WIDTH * 3 + Constants.DEFAULT_X_BORDER * 3 + TEXT_AREA_WIDTH + RIGHT_PADDING;
47

48
    private static final int HEIGHT = TOP_PADDING + DEFAULT_HEIGHT_SMALL * 3 + DEFAULT_HEIGHT_BIG + Constants.DEFAULT_Y_BORDER * 2 + BOTTOM_PADDING;
49

50
    private JPanel colorPanel;
51
    private JLabel coordinateLabel;
52
    private JLabel colorLabel;
53

54
    private Robot robot;
55
    private Point mousePoint; // 光标点
56
    private Image areaImage; // 待放大的图片
57

58
    private int zoomFactor = 2;
×
59

60
    private Point prevPoint = null; // 上一次的光标位置
×
61

62
    private Color currentColor; // 当前的颜色,按键记录才记录163, 184, 204
63

64
    private static ColorMode currentColorMode = ColorMode.RGB; // 当前颜色模式
×
65

66
    private Line2D crossHorizontal; // 交叉线
67
    private Line2D crossVertical;
68

69
    private int colorRecordMax = 5; // 记录的color record个数
×
70
    private LinkedList<Color> colorQueue = new LinkedList<>();
×
71

72
    private JTextField colorCopyTextField;
73

74
    // 边框
75
    private final Rectangle2D colorRect = new Rectangle2D.Double();
×
76
    private final Rectangle2D zoomRect = new Rectangle2D.Double();
×
77
    private final Rectangle2D recordRect = new Rectangle2D.Double();
×
78
    // 颜色记录JLabel数组
79
    private JLabel colorRecordValue[] = new JLabel[colorRecordMax];
×
80
    // hsb 数组
81
    float[] hsbArr;
82

83
    private boolean isLocked = false;
×
84

85
    @Override
86
    public void initUI() {
87
        setLayout(null);
×
88

89
        initFirstColumn();
×
90

91
        initSecondColumn();
×
92

93
        initThirdColumn();
×
94

95
        initFourthColumn();
×
96

97
        final InputMap inputMap = colorPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
×
98
        inputMap.put(KeyStroke.getKeyStroke("alt C"), "record.color");
×
99
        inputMap.put(KeyStroke.getKeyStroke("alt L"), "lock.position");
×
100
        inputMap.put(KeyStroke.getKeyStroke("alt U"), "unlock.position");
×
101

102
        final Action recordColorAction = new RecordColorAction(); // '记录'动作
×
103
        final Action lockPositionAction = new LockPositionAction();
×
104
        final Action unlockPositionAction = new UnlockPositionAction();
×
105

106
        final ActionMap actionMap = colorPanel.getActionMap();
×
107
        actionMap.put("record.color", recordColorAction);
×
108
        actionMap.put("lock.position", lockPositionAction);
×
109
        actionMap.put("unlock.position", unlockPositionAction);
×
110

111
        mouseListener();
×
112
    }
×
113

114
    private void initFirstColumn() {
115
        // 左侧的颜色框和显示的坐标,颜色值
116
        // 添加 panel 组件用来做颜色框
117
        colorPanel = new JPanel();
×
118
        colorPanel.setBounds(LEFT_PADDING, TOP_PADDING, DEFAULT_WIDTH, DEFAULT_HEIGHT_BIG);
×
119
        add(colorPanel);
×
120

121
        coordinateLabel = new JLabel();
×
122
        coordinateLabel.setBounds(LEFT_PADDING, TOP_PADDING + DEFAULT_HEIGHT_BIG + Constants.DEFAULT_Y_BORDER, DEFAULT_WIDTH, DEFAULT_HEIGHT_SMALL);
×
123
        add(coordinateLabel);
×
124

125
        colorLabel = new JLabel();
×
126
        colorLabel.setBounds(LEFT_PADDING, TOP_PADDING + DEFAULT_HEIGHT_BIG + DEFAULT_HEIGHT_SMALL + Constants.DEFAULT_Y_BORDER * 2, DEFAULT_WIDTH, DEFAULT_HEIGHT_SMALL);
×
127
        add(colorLabel);
×
128

129
        JComboBox<String> colorModeCombo = new JComboBox<>();
×
130
        for (ColorMode t : ColorMode.values()) {
×
131
            colorModeCombo.addItem(t.toString());
×
132
        }
133

134
        colorModeCombo.addActionListener(event -> {
×
135
            currentColorMode = ColorMode.valueOf((String) colorModeCombo.getSelectedItem());
×
136
        });
×
137
        colorModeCombo.setBounds(LEFT_PADDING, TOP_PADDING + DEFAULT_HEIGHT_BIG + DEFAULT_HEIGHT_SMALL * 2 + Constants.DEFAULT_Y_BORDER * 3, DEFAULT_WIDTH, DEFAULT_HEIGHT_SMALL);
×
138
        add(colorModeCombo);
×
139
    }
×
140

141
    private void initSecondColumn() {
142
        crossHorizontal = new Line2D.Double(
×
143
                (double) LEFT_PADDING + DEFAULT_WIDTH + Constants.DEFAULT_X_BORDER,
144
                (double) TOP_PADDING + DEFAULT_HEIGHT_BIG / 2.0,
145
                (double) LEFT_PADDING + DEFAULT_WIDTH * 2 + Constants.DEFAULT_X_BORDER,
146
                (double) TOP_PADDING + DEFAULT_HEIGHT_BIG / 2.0);
147
        crossVertical = new Line2D.Double(
×
148
                (double) LEFT_PADDING + DEFAULT_WIDTH + Constants.DEFAULT_X_BORDER + DEFAULT_WIDTH / 2.0,
149
                TOP_PADDING,
150
                (double) LEFT_PADDING + DEFAULT_WIDTH + Constants.DEFAULT_X_BORDER + DEFAULT_WIDTH / 2.0,
151
                (double) TOP_PADDING + DEFAULT_HEIGHT_BIG);
152

153
        colorCopyTextField = new JTextField();
×
154
        colorCopyTextField.setEditable(false);
×
155
        colorCopyTextField.setBounds(LEFT_PADDING + DEFAULT_WIDTH + Constants.DEFAULT_X_BORDER, TOP_PADDING + DEFAULT_HEIGHT_BIG + Constants.DEFAULT_Y_BORDER, DEFAULT_WIDTH, DEFAULT_HEIGHT_SMALL);
×
156
        add(colorCopyTextField);
×
157

158
        JButton colorCopyButton = new JButton("Copy");
×
159
        colorCopyButton.addActionListener(event -> {
×
160
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
×
161
            Transferable trans = new StringSelection(getColorText(currentColor));
×
162
            clipboard.setContents(trans, null);
×
163
        });
×
164
        colorCopyButton.setBounds(LEFT_PADDING + DEFAULT_WIDTH + Constants.DEFAULT_X_BORDER, TOP_PADDING + DEFAULT_HEIGHT_BIG + Constants.DEFAULT_Y_BORDER * 2 + DEFAULT_HEIGHT_SMALL, DEFAULT_WIDTH, DEFAULT_HEIGHT_SMALL);
×
165
        add(colorCopyButton);
×
166
    }
×
167

168
    private void initThirdColumn() {
169
        for (int i = 0; i < colorRecordMax; i++) {
×
170
            colorRecordValue[i] = new JLabel();
×
171
            colorRecordValue[i].setOpaque(true); // 背景不透明
×
172
            colorRecordValue[i].setBounds(LEFT_PADDING + DEFAULT_WIDTH * 2 + Constants.DEFAULT_X_BORDER * 2,
×
173
                    TOP_PADDING + i * DEFAULT_HEIGHT_SMALL, DEFAULT_WIDTH, DEFAULT_HEIGHT_SMALL);
174
            add(colorRecordValue[i]);
×
175
        }
176
        JComboBox<String> magnificationModeCombo = new JComboBox<>();
×
177
        magnificationModeCombo.addItem("Zoom: 100%");
×
178
        magnificationModeCombo.addItem("Zoom: 200%");
×
179
        magnificationModeCombo.addItem("Zoom: 300%");
×
180
        magnificationModeCombo.addItem("Zoom: 400%");
×
181
        magnificationModeCombo.addItem("Zoom: 500%");
×
182
        magnificationModeCombo.addItem("Zoom: 1200%");
×
183
        magnificationModeCombo.addItem("Zoom: 2800%");
×
184
        magnificationModeCombo.setSelectedItem("Zoom: 200%");
×
185
        magnificationModeCombo.addActionListener(event -> {
×
186
            String selectedItem = (String) magnificationModeCombo.getSelectedItem();
×
187
            String tmp = StringUtils.substringBetween(selectedItem, "Zoom: ", "%");
×
188
            zoomFactor = Integer.valueOf(tmp) / 100;
×
189
            logger.info("zoomFactor: " + zoomFactor);
×
190
        });
×
191
        magnificationModeCombo.setBounds(LEFT_PADDING + Constants.DEFAULT_X_BORDER * 2 + DEFAULT_WIDTH * 2, TOP_PADDING + DEFAULT_HEIGHT_BIG + Constants.DEFAULT_Y_BORDER, DEFAULT_WIDTH, DEFAULT_HEIGHT_SMALL);
×
192
        add(magnificationModeCombo);
×
193
    }
×
194

195
    private void initFourthColumn() {
196
        JTextArea textArea = new JTextArea();
×
197
        textArea.setBounds(LEFT_PADDING + DEFAULT_WIDTH * 3 + Constants.DEFAULT_X_BORDER * 3, TOP_PADDING, TEXT_AREA_WIDTH, DEFAULT_HEIGHT_BIG);
×
198
        textArea.append("记录颜色: ALT+C" + System.getProperty("line.separator"));
×
199
        textArea.append("锁定区域: ALT+L" + System.getProperty("line.separator"));
×
200
        textArea.append("取消锁定区域: ALT+U" + System.getProperty("line.separator"));
×
201
        add(textArea);
×
202
    }
×
203

204
    class RecordColorAction extends AbstractAction {
×
205
        private static final long serialVersionUID = 1L;
206

207
        @Override
208
        public void actionPerformed(final ActionEvent event) {
209
            if (robot == null) {
×
210
                logger.error("robot is null");
×
211
                return;
×
212
            }
213
            Color color = robot.getPixelColor(mousePoint.x, mousePoint.y);
×
214
            currentColor = color;
×
215

216
            // 头进尾出,就可以满足绘制到顶部的记录是最新的
217
            colorQueue.offerFirst(color);
×
218
            if (colorQueue.size() > colorRecordMax) {
×
219
                colorQueue.pollLast(); // 删除尾
×
220
            }
221

222
            // 显示颜色值到文本框
223
            colorCopyTextField.setText(getColorText(color));
×
224
            repaint();
×
225
        }
×
226
    }
227

228
    class LockPositionAction extends AbstractAction {
×
229
        private static final long serialVersionUID = 1L;
230

231
        @Override
232
        public void actionPerformed(final ActionEvent event) {
233
            isLocked = true;
×
234
        }
×
235
    }
236

237
    class UnlockPositionAction extends AbstractAction {
×
238
        private static final long serialVersionUID = 1L;
239

240
        @Override
241
        public void actionPerformed(final ActionEvent event) {
242
            isLocked = false;
×
243
        }
×
244
    }
245

246
    /**
247
     * 重置窗口大小
248
     */
249
    public Dimension getPreferredSize() {
250
        return new Dimension(WIDTH, HEIGHT);
×
251
    }
252

253
    private void mouseListener() {
254
        try {
255
            robot = new Robot();
×
256
        } catch (final AWTException e) {
×
257
            logger.error("Create Rebot instance failed");
×
258
        }
×
259

260
        final Timer timer = new Timer();
×
261
        timer.schedule(new TimerTask() {
×
262
            @Override
263
            public void run() {
264
                mouseAction();
×
265
            }
×
266
        }, 100, 100);
267
    }
×
268

269
    /**
270
     * 鼠标事件
271
     * 获取位置和颜色,并显示位置和颜色信息
272
     */
273
    private void mouseAction() {
274
        // 获取光标位置之后,与上次比对,避免重复运行
275
        PointerInfo pointerInfo = MouseInfo.getPointerInfo();
×
276
        if (pointerInfo == null) {
×
277
            logger.warn("pointerInfo is null");
×
278
            return;
×
279
        }
280
        mousePoint = pointerInfo.getLocation();
×
281

282
        if (mousePoint.equals(prevPoint)) {
×
283
            return;
×
284
        } else {
285
            prevPoint = mousePoint;
×
286
        }
287
        if (robot == null) {
×
288
            logger.error("robot is null");
×
289
            return;
×
290
        }
291
        final Color pixel = robot.getPixelColor(mousePoint.x, mousePoint.y);
×
292
        colorPanel.setBackground(pixel);
×
293

294
        coordinateLabel.setText(String.format("[%d, %d]", mousePoint.x, mousePoint.y));
×
295
        colorLabel.setText(getColorText(pixel));
×
296

297
        if (!isLocked) {
×
298
            getMouseArea();
×
299
        }
300
    }
×
301

302
    private String getColorText(final Color color) {
303
        if (color == null) {
×
304
            return "";
×
305
        }
306
        String s = "";
×
307
        switch (currentColorMode) {
×
308
            case RGB:
309
                s = String.format("%d, %d, %d", color.getRed(), color.getGreen(), color.getBlue());
×
310
                break;
×
311
            case HTML:
312
                s = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue());
×
313
                break;
×
314
            case HEX:
315
                s = String.format("0x%02X%02X%02X", color.getRed(), color.getGreen(), color.getBlue());
×
316
                break;
×
317
            case HSB:
318
                hsbArr = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
×
319
                s = String.format("%3.0f%% %3.0f%% %3.0f%%", hsbArr[0] * 100, hsbArr[1] * 100, hsbArr[2] * 100);
×
320
                break;
×
321
            default:
322
                break;
323
        }
324
        return s;
×
325

326
    }
327

328
    protected void getMouseArea() {
329

330
        final int x = mousePoint.x;
×
331
        final int y = mousePoint.y;
×
332

333
        int length = 100 / zoomFactor;
×
334
        final Rectangle r = new Rectangle(x - length / 2, y - length / 2, length, length);
×
335
        if (robot != null) {
×
336
            areaImage = robot.createScreenCapture(r);
×
337
        }
338
        repaint(); // 重绘,调用 paintComponent
×
339
    }
×
340

341
    /**
342
     * 绘制界面
343
     */
344
    public void paintComponent(final Graphics g) {
345
        // 父类的paitComponent需要绘制其他默认的组件,比如左侧颜色框panel以及坐标和颜色值label。如果不执行,则绘制的区域会重叠
346
        super.paintComponent(g);
×
347

348
        // 中间放大镜
349
        final Graphics2D g2 = (Graphics2D) g;
×
350
        //g2.drawImage(areaImage,10,300,null); // 原大小
351
        g2.drawImage(areaImage, LEFT_PADDING + DEFAULT_WIDTH + Constants.DEFAULT_X_BORDER, TOP_PADDING, DEFAULT_WIDTH, DEFAULT_HEIGHT_BIG, null);
×
352
        // 放大镜的十字线
353
        g2.setPaint(Color.RED);
×
354
        g2.draw(crossHorizontal);
×
355
        g2.draw(crossVertical);
×
356

357
        // 右侧颜色历史记录
358
        paintColorRecord(g2);
×
359

360
        // 绘制各组件的边框
361
        paintBorder(g2);
×
362

363
        // 颜色值重新赋值,因为可能有模式的改变
364
        colorCopyTextField.setText(getColorText(currentColor));
×
365

366
    }
×
367

368
    private void paintColorRecord(final Graphics2D g2) {
369
        int i = 0;
×
370

371
        for (Color c : colorQueue) {
×
372
            Color penC = new Color(255 - c.getRed(), 255 - c.getGreen(), 255 - c.getBlue()); // 反色
×
373
            // 字体颜色设置
374
            colorRecordValue[i].setForeground(penC);
×
375
            colorRecordValue[i].setText(getColorText(c));
×
376

377
            colorRecordValue[i].setBackground(c);
×
378

379
            if (++i > colorRecordMax)
×
380
                break;
×
381
        }
×
382
    }
×
383

384
    private void paintBorder(Graphics2D g2) {
385
        g2.setPaint(Color.BLACK);
×
386
        colorRect.setFrameFromDiagonal(
×
387
                (double) LEFT_PADDING - 1,
388
                (double) TOP_PADDING - 1,
389
                (double) LEFT_PADDING + DEFAULT_WIDTH,
390
                (double) TOP_PADDING + DEFAULT_HEIGHT_BIG);
391
        zoomRect.setFrameFromDiagonal(
×
392
                (double) LEFT_PADDING + DEFAULT_WIDTH + Constants.DEFAULT_X_BORDER - 1,
393
                (double) TOP_PADDING - 1,
394
                (double) LEFT_PADDING + DEFAULT_WIDTH * 2 + Constants.DEFAULT_X_BORDER,
395
                (double) TOP_PADDING + DEFAULT_HEIGHT_BIG);
396
        recordRect.setFrameFromDiagonal(
×
397
                (double) LEFT_PADDING + DEFAULT_WIDTH * 2 + Constants.DEFAULT_X_BORDER * 2 - 1,
398
                (double) TOP_PADDING - 1,
399
                (double) LEFT_PADDING + DEFAULT_WIDTH * 3 + Constants.DEFAULT_X_BORDER * 2,
400
                (double) TOP_PADDING + DEFAULT_HEIGHT_BIG);
401
        g2.draw(colorRect);
×
402
        g2.draw(zoomRect);
×
403
        g2.draw(recordRect);
×
404
    }
×
405
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc