xw-devtool-cli 1.0.27 → 1.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/README_EN.md +1 -0
- package/package.json +1 -1
- package/src/commands/pixelDistance.js +167 -0
- package/src/index.js +5 -0
- package/src/locales/en.js +5 -0
- package/src/locales/zh.js +5 -0
package/README.md
CHANGED
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
> 2. 由于涉及跨进程通信,按下空格后可能存在轻微延时,请耐心等待结果。
|
|
22
22
|
> 3. 取色模式下会显示全屏十字辅助线,按 **回车键** 退出模式。
|
|
23
23
|
- **占位图生成**:快速生成指定尺寸、颜色、文字的占位图片 (Placeholder Image)。
|
|
24
|
-
- **全屏十字辅助线**:显示跟随鼠标的全屏红色十字线,用于屏幕对齐和定位。
|
|
24
|
+
- **全屏十字辅助线**:显示跟随鼠标的全屏红色十字线,用于屏幕对齐和定位。
|
|
25
|
+
- **屏幕测距**:点击屏幕上任意两点,测量其像素距离。
|
|
25
26
|
- **Mock 数据生成**:
|
|
26
27
|
- 支持生成:英文段落 (Lorem Ipsum)、中文字符、中国居民身份证号、电子邮箱、URL、订单号、手机号、座机号。
|
|
27
28
|
- 支持批量生成。
|
package/README_EN.md
CHANGED
|
@@ -17,6 +17,7 @@ Key features include: Base64 encoding/decoding, image format conversion, image <
|
|
|
17
17
|
- **Color Picker**: Pick a single pixel color or area average from an image; supports px/% coordinates; shows preview bar and auto-copies Hex/Hex8.
|
|
18
18
|
- **Screen Picker**: Pick color directly from the screen at the mouse position; move the cursor and press Enter to sample; supports alpha preview.
|
|
19
19
|
- **Screen Crosshair**: Display a full-screen red crosshair following the mouse for alignment.
|
|
20
|
+
- **Pixel Distance**: Measure pixel distance between two points on the screen.
|
|
20
21
|
- **Mock Data**:
|
|
21
22
|
- Generate: Lorem Ipsum, Chinese characters, ID cards, Emails, URLs, Order IDs, Phone numbers.
|
|
22
23
|
- Supports batch generation.
|
package/package.json
CHANGED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import i18next from '../i18n.js';
|
|
3
|
+
|
|
4
|
+
export async function pixelDistanceHandler() {
|
|
5
|
+
if (process.platform !== 'win32') {
|
|
6
|
+
console.log(i18next.t('pixelDistance.notSupported'));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
console.log(i18next.t('pixelDistance.startPrompt'));
|
|
11
|
+
|
|
12
|
+
const overlayScript = `
|
|
13
|
+
Add-Type -AssemblyName System.Windows.Forms;
|
|
14
|
+
Add-Type -AssemblyName System.Drawing;
|
|
15
|
+
|
|
16
|
+
Add-Type -TypeDefinition @'
|
|
17
|
+
using System;
|
|
18
|
+
using System.Drawing;
|
|
19
|
+
using System.Windows.Forms;
|
|
20
|
+
using System.Runtime.InteropServices;
|
|
21
|
+
|
|
22
|
+
public class DistanceForm : Form {
|
|
23
|
+
private Point p1 = Point.Empty;
|
|
24
|
+
private Point p2 = Point.Empty;
|
|
25
|
+
private bool p1Set = false;
|
|
26
|
+
private bool p2Set = false;
|
|
27
|
+
private Bitmap screenCapture;
|
|
28
|
+
|
|
29
|
+
public DistanceForm() {
|
|
30
|
+
this.FormBorderStyle = FormBorderStyle.None;
|
|
31
|
+
this.TopMost = true;
|
|
32
|
+
this.Cursor = Cursors.Cross;
|
|
33
|
+
this.DoubleBuffered = true;
|
|
34
|
+
|
|
35
|
+
// Calculate total bounds
|
|
36
|
+
Rectangle totalBounds = Rectangle.Empty;
|
|
37
|
+
foreach(Screen s in Screen.AllScreens) {
|
|
38
|
+
totalBounds = Rectangle.Union(totalBounds, s.Bounds);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.StartPosition = FormStartPosition.Manual;
|
|
42
|
+
this.Bounds = totalBounds;
|
|
43
|
+
|
|
44
|
+
// Capture screen
|
|
45
|
+
screenCapture = new Bitmap(totalBounds.Width, totalBounds.Height);
|
|
46
|
+
using (Graphics g = Graphics.FromImage(screenCapture)) {
|
|
47
|
+
g.CopyFromScreen(totalBounds.Location, Point.Empty, totalBounds.Size);
|
|
48
|
+
}
|
|
49
|
+
this.BackgroundImage = screenCapture;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private Point GetSnappedPoint(Point current) {
|
|
53
|
+
if (!p1Set) return current;
|
|
54
|
+
|
|
55
|
+
Point snapped = current;
|
|
56
|
+
int threshold = 5; // Snap threshold in pixels
|
|
57
|
+
|
|
58
|
+
// Check horizontal snap (same Y)
|
|
59
|
+
if (Math.Abs(current.Y - p1.Y) < threshold) {
|
|
60
|
+
snapped.Y = p1.Y;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Check vertical snap (same X)
|
|
64
|
+
if (Math.Abs(current.X - p1.X) < threshold) {
|
|
65
|
+
snapped.X = p1.X;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return snapped;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
protected override void OnMouseDown(MouseEventArgs e) {
|
|
72
|
+
if (e.Button == MouseButtons.Right) {
|
|
73
|
+
// Reset
|
|
74
|
+
p1Set = false;
|
|
75
|
+
p2Set = false;
|
|
76
|
+
this.Invalidate();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (e.Button == MouseButtons.Left) {
|
|
81
|
+
if (!p1Set) {
|
|
82
|
+
p1 = e.Location;
|
|
83
|
+
p1Set = true;
|
|
84
|
+
} else if (!p2Set) {
|
|
85
|
+
p2 = GetSnappedPoint(e.Location);
|
|
86
|
+
p2Set = true;
|
|
87
|
+
} else {
|
|
88
|
+
// Start over from new point
|
|
89
|
+
p1 = e.Location;
|
|
90
|
+
p1Set = true;
|
|
91
|
+
p2Set = false;
|
|
92
|
+
}
|
|
93
|
+
this.Invalidate();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
protected override void OnMouseMove(MouseEventArgs e) {
|
|
98
|
+
if (p1Set && !p2Set) {
|
|
99
|
+
this.Invalidate();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
protected override void OnPaint(PaintEventArgs e) {
|
|
104
|
+
Graphics g = e.Graphics;
|
|
105
|
+
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
|
|
106
|
+
|
|
107
|
+
Pen pen = new Pen(Color.Red, 2);
|
|
108
|
+
Brush brush = Brushes.Red;
|
|
109
|
+
Font font = new Font("Segoe UI", 12, FontStyle.Bold);
|
|
110
|
+
Brush textBg = new SolidBrush(Color.FromArgb(180, 0, 0, 0));
|
|
111
|
+
|
|
112
|
+
if (p1Set) {
|
|
113
|
+
Point target = p2Set ? p2 : GetSnappedPoint(this.PointToClient(Cursor.Position));
|
|
114
|
+
|
|
115
|
+
// Draw line
|
|
116
|
+
g.DrawLine(pen, p1, target);
|
|
117
|
+
|
|
118
|
+
// Draw points
|
|
119
|
+
g.FillEllipse(brush, p1.X - 4, p1.Y - 4, 8, 8);
|
|
120
|
+
g.FillEllipse(brush, target.X - 4, target.Y - 4, 8, 8);
|
|
121
|
+
|
|
122
|
+
// Calculate distance
|
|
123
|
+
double dist = Math.Sqrt(Math.Pow(target.X - p1.X, 2) + Math.Pow(target.Y - p1.Y, 2));
|
|
124
|
+
string text = String.Format("{0:F2} px", dist);
|
|
125
|
+
|
|
126
|
+
// Draw text at midpoint
|
|
127
|
+
Point mid = new Point((p1.X + target.X) / 2, (p1.Y + target.Y) / 2);
|
|
128
|
+
SizeF size = g.MeasureString(text, font);
|
|
129
|
+
|
|
130
|
+
// Ensure text doesn't go off screen
|
|
131
|
+
float txtX = mid.X + 10;
|
|
132
|
+
float txtY = mid.Y + 10;
|
|
133
|
+
|
|
134
|
+
g.FillRectangle(textBg, txtX - 2, txtY - 2, size.Width + 4, size.Height + 4);
|
|
135
|
+
g.DrawString(text, font, Brushes.White, txtX, txtY);
|
|
136
|
+
|
|
137
|
+
// Also display coordinates
|
|
138
|
+
string coords = String.Format("P1: {0},{1} P2: {2},{3}", p1.X, p1.Y, target.X, target.Y);
|
|
139
|
+
g.DrawString(coords, font, Brushes.Yellow, 10, 10);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
protected override void OnKeyDown(KeyEventArgs e) {
|
|
144
|
+
if (e.KeyCode == Keys.Escape) {
|
|
145
|
+
Application.Exit();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public static class Entry {
|
|
151
|
+
public static void Main() {
|
|
152
|
+
Application.EnableVisualStyles();
|
|
153
|
+
Application.SetCompatibleTextRenderingDefault(false);
|
|
154
|
+
Application.Run(new DistanceForm());
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
'@ -ReferencedAssemblies System.Windows.Forms,System.Drawing
|
|
158
|
+
|
|
159
|
+
[Entry]::Main()
|
|
160
|
+
`;
|
|
161
|
+
|
|
162
|
+
const proc = spawn('powershell', ['-NoProfile', '-Command', overlayScript], { stdio: 'inherit' });
|
|
163
|
+
|
|
164
|
+
proc.on('close', (code) => {
|
|
165
|
+
// console.log('Exited');
|
|
166
|
+
});
|
|
167
|
+
}
|
package/src/index.js
CHANGED
|
@@ -30,6 +30,7 @@ import { vscodeSnippetHandler } from './commands/vscodeSnippet.js';
|
|
|
30
30
|
import { dominantColorHandler } from './commands/dominantColor.js';
|
|
31
31
|
import { colorPickHandler } from './commands/colorPick.js';
|
|
32
32
|
import { crosshairHandler } from './commands/crosshair.js';
|
|
33
|
+
import { pixelDistanceHandler } from './commands/pixelDistance.js';
|
|
33
34
|
|
|
34
35
|
process.on('SIGINT', () => {
|
|
35
36
|
console.log(`\n${i18next.t('menu.bye')}`);
|
|
@@ -55,6 +56,7 @@ function getFeatures() {
|
|
|
55
56
|
{ name: i18next.t('menu.features.dominantColor'), value: 'dominantColor' },
|
|
56
57
|
{ name: i18next.t('menu.features.colorPick'), value: 'colorPick' },
|
|
57
58
|
{ name: i18next.t('menu.features.crosshair'), value: 'crosshair' },
|
|
59
|
+
{ name: i18next.t('menu.features.pixelDistance'), value: 'pixelDistance' },
|
|
58
60
|
{ name: i18next.t('menu.features.placeholderImg'), value: 'placeholderImg' },
|
|
59
61
|
{ name: i18next.t('menu.features.qrcode'), value: 'qrcode' },
|
|
60
62
|
|
|
@@ -199,6 +201,9 @@ async function handleAction(action) {
|
|
|
199
201
|
case 'crosshair':
|
|
200
202
|
await crosshairHandler();
|
|
201
203
|
break;
|
|
204
|
+
case 'pixelDistance':
|
|
205
|
+
await pixelDistanceHandler();
|
|
206
|
+
break;
|
|
202
207
|
case 'timeFormat':
|
|
203
208
|
await timeFormatHandler();
|
|
204
209
|
break;
|
package/src/locales/en.js
CHANGED
|
@@ -2,6 +2,10 @@ export default {
|
|
|
2
2
|
common: {
|
|
3
3
|
back: 'Back to previous step'
|
|
4
4
|
},
|
|
5
|
+
pixelDistance: {
|
|
6
|
+
notSupported: 'Pixel distance tool not supported on this OS.',
|
|
7
|
+
startPrompt: 'Pixel distance tool started. Click 2 points to measure. Right-click to reset. ESC to exit.'
|
|
8
|
+
},
|
|
5
9
|
menu: {
|
|
6
10
|
title: 'xw-devtool-cli Menu',
|
|
7
11
|
exit: 'Exit',
|
|
@@ -15,6 +19,7 @@ export default {
|
|
|
15
19
|
dominantColor: 'Image Dominant Color',
|
|
16
20
|
colorPick: 'Color Picker',
|
|
17
21
|
crosshair: 'Screen Crosshair',
|
|
22
|
+
pixelDistance: 'Pixel Distance Tool',
|
|
18
23
|
placeholderImg: 'Placeholder Image Generator',
|
|
19
24
|
qrcode: 'QR Code Generator',
|
|
20
25
|
url: 'URL Encode/Decode',
|
package/src/locales/zh.js
CHANGED
|
@@ -6,6 +6,10 @@ export default {
|
|
|
6
6
|
notSupported: '当前系统不支持屏幕辅助线。',
|
|
7
7
|
startPrompt: '屏幕十字辅助线已启动。按任意键退出...'
|
|
8
8
|
},
|
|
9
|
+
pixelDistance: {
|
|
10
|
+
notSupported: '当前系统不支持屏幕测距。',
|
|
11
|
+
startPrompt: '屏幕测距工具已启动。点击两点测量距离。右键重置。ESC 退出。'
|
|
12
|
+
},
|
|
9
13
|
menu: {
|
|
10
14
|
title: 'xw-devtool-cli 菜单',
|
|
11
15
|
exit: '退出',
|
|
@@ -19,6 +23,7 @@ export default {
|
|
|
19
23
|
dominantColor: '图片主色识别',
|
|
20
24
|
colorPick: '颜色吸取',
|
|
21
25
|
crosshair: '全屏十字辅助线',
|
|
26
|
+
pixelDistance: '屏幕测距 (像素)',
|
|
22
27
|
placeholderImg: '占位图生成器',
|
|
23
28
|
qrcode: '二维码生成器',
|
|
24
29
|
url: 'URL 编码/解码',
|