mirror of
https://github.com/fofolee/uTools-quickcommand.git
synced 2025-06-09 23:16:18 +08:00
新增图片操作分类,支持调整大小、旋转、添加水印、裁剪、格式转换、图片信息、png2ico
This commit is contained in:
parent
f9a1aefff6
commit
4c279e8309
@ -8,6 +8,7 @@ const quickcomposer = {
|
||||
math: require("./quickcomposer/math"),
|
||||
ui: require("./quickcomposer/ui"),
|
||||
audio: require("./quickcomposer/audio"),
|
||||
image: require("./quickcomposer/image"),
|
||||
};
|
||||
|
||||
module.exports = quickcomposer;
|
||||
|
492
plugin/lib/quickcomposer/image/image.js
Normal file
492
plugin/lib/quickcomposer/image/image.js
Normal file
@ -0,0 +1,492 @@
|
||||
const fs = require("fs");
|
||||
const exif = require("exif-reader");
|
||||
|
||||
/**
|
||||
* 加载图片
|
||||
* @param {string} file 图片文件路径
|
||||
* @returns {Promise<HTMLImageElement>} 图片元素
|
||||
*/
|
||||
async function loadImage(file) {
|
||||
if (!fs.existsSync(file)) {
|
||||
throw new Error(`图片文件不存在: ${file}`);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
img.onload = () => resolve(img);
|
||||
img.onerror = reject;
|
||||
img.src = `file://${file}`;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取EXIF信息
|
||||
* @param {string} file 图片文件路径
|
||||
* @returns {Promise<Object>} EXIF信息
|
||||
*/
|
||||
async function readExif(file) {
|
||||
try {
|
||||
const buffer = fs.readFileSync(file);
|
||||
|
||||
// 检查是否是JPEG文件
|
||||
if (buffer[0] !== 0xff || buffer[1] !== 0xd8) {
|
||||
console.warn("不是JPEG文件");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 查找APP1段
|
||||
let offset = 2;
|
||||
while (offset < buffer.length) {
|
||||
if (buffer[offset] === 0xff && buffer[offset + 1] === 0xe1) {
|
||||
// 获取段长度
|
||||
const segmentLength = buffer[offset + 2] * 256 + buffer[offset + 3];
|
||||
|
||||
// 提取EXIF数据
|
||||
const exifData = buffer.slice(offset + 4, offset + 2 + segmentLength);
|
||||
|
||||
// 检查是否是EXIF数据
|
||||
if (exifData.slice(0, 6).toString() === "Exif\0\0") {
|
||||
try {
|
||||
// 提取实际的EXIF数据(跳过Exif\0\0)
|
||||
const metadata = exif(exifData.slice(6));
|
||||
return metadata;
|
||||
} catch (e) {
|
||||
console.warn("解析EXIF数据失败:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
||||
console.warn("未找到EXIF数据");
|
||||
return null;
|
||||
} catch (error) {
|
||||
console.warn("读取EXIF信息失败:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图片颜色信息
|
||||
* @param {HTMLImageElement} img 图片元素
|
||||
* @returns {Object} 颜色信息
|
||||
*/
|
||||
function getColorInfo(img) {
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||
const data = imageData.data;
|
||||
let r = 0,
|
||||
g = 0,
|
||||
b = 0,
|
||||
a = 0;
|
||||
|
||||
// 计算平均颜色
|
||||
for (let i = 0; i < data.length; i += 4) {
|
||||
r += data[i];
|
||||
g += data[i + 1];
|
||||
b += data[i + 2];
|
||||
a += data[i + 3];
|
||||
}
|
||||
|
||||
const pixels = data.length / 4;
|
||||
return {
|
||||
averageColor: {
|
||||
r: Math.round(r / pixels),
|
||||
g: Math.round(g / pixels),
|
||||
b: Math.round(b / pixels),
|
||||
a: Math.round(a / pixels) / 255,
|
||||
},
|
||||
isTransparent: Math.round(a / pixels) < 255,
|
||||
hasAlphaChannel: true, // Canvas总是包含alpha通道
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析图片信息
|
||||
* @param {string} file 图片文件路径
|
||||
* @returns {Promise<Object>} 图片信息
|
||||
*/
|
||||
async function analyze(file) {
|
||||
const img = await loadImage(file);
|
||||
const stats = fs.statSync(file);
|
||||
const ext = file.split(".").pop().toLowerCase();
|
||||
const exifData = await readExif(file);
|
||||
const colorInfo = getColorInfo(img);
|
||||
|
||||
// 计算图片大小的可读格式
|
||||
const formatSize = (bytes) => {
|
||||
if (bytes < 1024) return bytes + " B";
|
||||
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + " KB";
|
||||
return (bytes / (1024 * 1024)).toFixed(2) + " MB";
|
||||
};
|
||||
|
||||
// 获取图片类型
|
||||
const getImageType = (ext) => {
|
||||
const types = {
|
||||
jpg: "JPEG图片",
|
||||
jpeg: "JPEG图片",
|
||||
png: "PNG图片",
|
||||
webp: "WebP图片",
|
||||
gif: "GIF图片",
|
||||
bmp: "BMP图片",
|
||||
};
|
||||
return types[ext] || "未知类型";
|
||||
};
|
||||
|
||||
// 格式化EXIF信息
|
||||
const formatExif = (exif) => {
|
||||
if (!exif) return null;
|
||||
return {
|
||||
相机信息: {
|
||||
制造商: exif.Image?.Make,
|
||||
型号: exif.Image?.Model,
|
||||
软件: exif.Image?.Software,
|
||||
方向: exif.Image?.Orientation,
|
||||
分辨率: {
|
||||
X: exif.Image?.XResolution,
|
||||
Y: exif.Image?.YResolution,
|
||||
单位: exif.Image?.ResolutionUnit,
|
||||
},
|
||||
},
|
||||
拍摄信息: {
|
||||
拍摄时间: exif.Photo?.DateTimeOriginal,
|
||||
曝光时间: exif.Photo?.ExposureTime,
|
||||
光圈值: exif.Photo?.FNumber,
|
||||
ISO感光度: exif.Photo?.ISOSpeedRatings,
|
||||
焦距: exif.Photo?.FocalLength,
|
||||
焦距35mm: exif.Photo?.FocalLengthIn35mmFilm,
|
||||
闪光灯: exif.Photo?.Flash,
|
||||
白平衡: exif.Photo?.WhiteBalance,
|
||||
曝光程序: exif.Photo?.ExposureProgram,
|
||||
曝光补偿: exif.Photo?.ExposureBiasValue,
|
||||
测光模式: exif.Photo?.MeteringMode,
|
||||
亮度值: exif.Photo?.BrightnessValue,
|
||||
场景类型: exif.Photo?.SceneCaptureType,
|
||||
镜头信息: {
|
||||
制造商: exif.Photo?.LensMake,
|
||||
型号: exif.Photo?.LensModel,
|
||||
},
|
||||
},
|
||||
GPS信息: exif.GPSInfo
|
||||
? {
|
||||
纬度: {
|
||||
参考: exif.GPSInfo.GPSLatitudeRef,
|
||||
值: exif.GPSInfo.GPSLatitude,
|
||||
},
|
||||
经度: {
|
||||
参考: exif.GPSInfo.GPSLongitudeRef,
|
||||
值: exif.GPSInfo.GPSLongitude,
|
||||
},
|
||||
海拔: {
|
||||
参考: exif.GPSInfo.GPSAltitudeRef,
|
||||
值: exif.GPSInfo.GPSAltitude,
|
||||
},
|
||||
时间戳: exif.GPSInfo.GPSTimeStamp,
|
||||
日期戳: exif.GPSInfo.GPSDateStamp,
|
||||
方向: {
|
||||
参考: exif.GPSInfo.GPSImgDirectionRef,
|
||||
值: exif.GPSInfo.GPSImgDirection,
|
||||
},
|
||||
}
|
||||
: null,
|
||||
缩略图信息: exif.Thumbnail
|
||||
? {
|
||||
宽度: exif.Thumbnail.ImageWidth,
|
||||
高度: exif.Thumbnail.ImageLength,
|
||||
压缩: exif.Thumbnail.Compression,
|
||||
方向: exif.Thumbnail.Orientation,
|
||||
分辨率: {
|
||||
X: exif.Thumbnail.XResolution,
|
||||
Y: exif.Thumbnail.YResolution,
|
||||
单位: exif.Thumbnail.ResolutionUnit,
|
||||
},
|
||||
}
|
||||
: null,
|
||||
其他信息: {
|
||||
描述: exif.Image?.ImageDescription,
|
||||
作者: exif.Image?.Artist,
|
||||
版权: exif.Image?.Copyright,
|
||||
创建时间: exif.Photo?.DateTimeDigitized,
|
||||
修改时间: exif.Image?.DateTime,
|
||||
色彩空间: exif.Photo?.ColorSpace,
|
||||
图像处理: exif.Photo?.CustomRendered,
|
||||
对比度: exif.Photo?.Contrast,
|
||||
饱和度: exif.Photo?.Saturation,
|
||||
锐度: exif.Photo?.Sharpness,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
// 基本信息
|
||||
width: img.width, // 宽度(像素)
|
||||
height: img.height, // 高度(像素)
|
||||
aspectRatio: img.width / img.height, // 宽高比
|
||||
resolution: img.width * img.height, // 分辨率(总像素)
|
||||
|
||||
// 文件信息
|
||||
type: getImageType(ext), // 图片类型
|
||||
format: ext.toUpperCase(), // 文件格式
|
||||
size: formatSize(stats.size), // 文件大小
|
||||
bytes: stats.size, // 字节数
|
||||
|
||||
// 时间信息
|
||||
createTime: stats.birthtime, // 创建时间
|
||||
modifyTime: stats.mtime, // 修改时间
|
||||
accessTime: stats.atime, // 访问时间
|
||||
|
||||
// 路径信息
|
||||
path: file, // 完整路径
|
||||
filename: file.split("/").pop(), // 文件名
|
||||
|
||||
// 颜色信息
|
||||
colorInfo: {
|
||||
averageColor: colorInfo.averageColor, // 平均颜色
|
||||
isTransparent: colorInfo.isTransparent, // 是否包含透明
|
||||
hasAlphaChannel: colorInfo.hasAlphaChannel, // 是否有Alpha通道
|
||||
},
|
||||
|
||||
// EXIF信息
|
||||
exif: formatExif(exifData),
|
||||
rawExif: exifData, // 原始EXIF数据
|
||||
|
||||
// 其他信息
|
||||
naturalWidth: img.naturalWidth, // 原始宽度
|
||||
naturalHeight: img.naturalHeight, // 原始高度
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 调整图片大小
|
||||
* @param {string} inputFile 输入文件路径
|
||||
* @param {string} outputFile 输出文件路径
|
||||
* @param {number} width 宽度
|
||||
* @param {number} height 高度
|
||||
* @param {boolean} keepAspectRatio 保持宽高比
|
||||
* @param {number} quality 图片质量 (0-1)
|
||||
*/
|
||||
async function resize(
|
||||
inputFile,
|
||||
outputFile,
|
||||
width = null,
|
||||
height = null,
|
||||
keepAspectRatio = true,
|
||||
quality = 0.92
|
||||
) {
|
||||
const img = await loadImage(inputFile);
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
if (keepAspectRatio) {
|
||||
if (width && !height) {
|
||||
height = width * (img.height / img.width);
|
||||
} else if (height && !width) {
|
||||
width = height * (img.width / img.height);
|
||||
}
|
||||
}
|
||||
|
||||
canvas.width = width || img.width;
|
||||
canvas.height = height || img.height;
|
||||
|
||||
// 绘制调整大小后的图片
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
|
||||
// 获取图片数据
|
||||
const format = outputFile.split(".").pop() || "jpeg";
|
||||
const dataURL = canvas.toDataURL(`image/${format}`, quality);
|
||||
|
||||
// 保存文件
|
||||
const base64Data = dataURL.replace(/^data:image\/\w+;base64,/, "");
|
||||
fs.writeFileSync(outputFile, Buffer.from(base64Data, "base64"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转图片
|
||||
* @param {string} inputFile 输入文件路径
|
||||
* @param {string} outputFile 输出文件路径
|
||||
* @param {number} angle 旋转角度
|
||||
* @param {number} quality 图片质量
|
||||
*/
|
||||
async function rotate(inputFile, outputFile, angle = 90, quality = 0.92) {
|
||||
const img = await loadImage(inputFile);
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
const angleRad = (angle * Math.PI) / 180;
|
||||
const sin = Math.abs(Math.sin(angleRad));
|
||||
const cos = Math.abs(Math.cos(angleRad));
|
||||
|
||||
// 计算旋转后的画布大小
|
||||
canvas.width = img.width * cos + img.height * sin;
|
||||
canvas.height = img.width * sin + img.height * cos;
|
||||
|
||||
// 移动到画布中心并旋转
|
||||
ctx.translate(canvas.width / 2, canvas.height / 2);
|
||||
ctx.rotate(angleRad);
|
||||
ctx.drawImage(img, -img.width / 2, -img.height / 2);
|
||||
|
||||
// 保存文件
|
||||
const format = outputFile.split(".").pop() || "jpeg";
|
||||
const dataURL = canvas.toDataURL(`image/${format}`, quality);
|
||||
|
||||
const base64Data = dataURL.replace(/^data:image\/\w+;base64,/, "");
|
||||
fs.writeFileSync(outputFile, Buffer.from(base64Data, "base64"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 裁剪图片
|
||||
* @param {string} inputFile 输入文件路径
|
||||
* @param {string} outputFile 输出文件路径
|
||||
* @param {number} x 起始X坐标
|
||||
* @param {number} y 起始Y坐标
|
||||
* @param {number} width 裁剪宽度
|
||||
* @param {number} height 裁剪高度
|
||||
* @param {number} quality 图片质量
|
||||
*/
|
||||
async function crop(
|
||||
inputFile,
|
||||
outputFile,
|
||||
x = 0,
|
||||
y = 0,
|
||||
width = null,
|
||||
height = null,
|
||||
quality = 0.92
|
||||
) {
|
||||
const img = await loadImage(inputFile);
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
width = width || img.width;
|
||||
height = height || img.height;
|
||||
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
// 绘制裁剪区域
|
||||
ctx.drawImage(img, x, y, width, height, 0, 0, width, height);
|
||||
|
||||
// 保存文件
|
||||
const format = outputFile.split(".").pop() || "jpeg";
|
||||
const dataURL = canvas.toDataURL(`image/${format}`, quality);
|
||||
|
||||
const base64Data = dataURL.replace(/^data:image\/\w+;base64,/, "");
|
||||
fs.writeFileSync(outputFile, Buffer.from(base64Data, "base64"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加水印
|
||||
* @param {string} inputFile 输入文件路径
|
||||
* @param {string} outputFile 输出文件路径
|
||||
* @param {string} text 水印文字
|
||||
* @param {string} font 字体设置
|
||||
* @param {string} color 文字颜色
|
||||
* @param {string} position 位置(topLeft/topRight/bottomLeft/bottomRight/center)
|
||||
* @param {number} margin 边距
|
||||
* @param {number} opacity 不透明度
|
||||
* @param {number} quality 图片质量
|
||||
*/
|
||||
async function watermark(
|
||||
inputFile,
|
||||
outputFile,
|
||||
text = "水印文字",
|
||||
font = "24px Arial",
|
||||
color = "rgba(255, 255, 255, 0.5)",
|
||||
position = "bottomRight",
|
||||
margin = 20,
|
||||
opacity = 0.5,
|
||||
quality = 0.92
|
||||
) {
|
||||
const img = await loadImage(inputFile);
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
// 绘制原图
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
// 设置水印样式
|
||||
ctx.font = font;
|
||||
ctx.fillStyle = color;
|
||||
ctx.globalAlpha = opacity;
|
||||
|
||||
const metrics = ctx.measureText(text);
|
||||
const textWidth = metrics.width;
|
||||
const textHeight = parseInt(ctx.font); // 近似值
|
||||
|
||||
// 计算水印位置
|
||||
let x, y;
|
||||
switch (position) {
|
||||
case "topLeft":
|
||||
x = margin;
|
||||
y = margin + textHeight;
|
||||
break;
|
||||
case "topRight":
|
||||
x = canvas.width - textWidth - margin;
|
||||
y = margin + textHeight;
|
||||
break;
|
||||
case "bottomLeft":
|
||||
x = margin;
|
||||
y = canvas.height - margin;
|
||||
break;
|
||||
case "bottomRight":
|
||||
x = canvas.width - textWidth - margin;
|
||||
y = canvas.height - margin;
|
||||
break;
|
||||
case "center":
|
||||
default:
|
||||
x = (canvas.width - textWidth) / 2;
|
||||
y = (canvas.height + textHeight) / 2;
|
||||
}
|
||||
|
||||
// 绘制水印
|
||||
ctx.fillText(text, x, y);
|
||||
|
||||
// 保存文件
|
||||
const format = outputFile.split(".").pop() || "jpeg";
|
||||
const dataURL = canvas.toDataURL(`image/${format}`, quality);
|
||||
|
||||
const base64Data = dataURL.replace(/^data:image\/\w+;base64,/, "");
|
||||
fs.writeFileSync(outputFile, Buffer.from(base64Data, "base64"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换图片格式
|
||||
* @param {string} inputFile 输入文件路径
|
||||
* @param {string} outputFile 输出文件路径
|
||||
* @param {string} format 输出格式
|
||||
* @param {number} quality 图片质量
|
||||
*/
|
||||
async function convert(inputFile, outputFile, format = "jpeg", quality = 0.92) {
|
||||
const img = await loadImage(inputFile);
|
||||
const canvas = document.createElement("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
// 绘制图片
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
// 保存为新格式
|
||||
const dataURL = canvas.toDataURL(`image/${format}`, quality);
|
||||
|
||||
const base64Data = dataURL.replace(/^data:image\/\w+;base64,/, "");
|
||||
fs.writeFileSync(outputFile, Buffer.from(base64Data, "base64"));
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
analyze,
|
||||
resize,
|
||||
rotate,
|
||||
crop,
|
||||
watermark,
|
||||
convert,
|
||||
};
|
7
plugin/lib/quickcomposer/image/index.js
Normal file
7
plugin/lib/quickcomposer/image/index.js
Normal file
@ -0,0 +1,7 @@
|
||||
const image = require("./image");
|
||||
const png2icon = require("./png2icon");
|
||||
|
||||
module.exports = {
|
||||
...image,
|
||||
...png2icon,
|
||||
};
|
36
plugin/lib/quickcomposer/image/png2icon.js
Normal file
36
plugin/lib/quickcomposer/image/png2icon.js
Normal file
@ -0,0 +1,36 @@
|
||||
const png2icons = require("png2icons");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const pngToIcon = (input, outputDir, type = "ico") => {
|
||||
if (input instanceof Array) {
|
||||
input.forEach((input) => {
|
||||
pngToIcon(input, outputDir, type);
|
||||
});
|
||||
return;
|
||||
}
|
||||
let icon, outputFile, basename;
|
||||
console.log(input);
|
||||
if (input.startsWith("data:image/png;base64,")) {
|
||||
input = Buffer.from(input.split(",")[1], "base64");
|
||||
basename = new Date().getTime().toString();
|
||||
} else {
|
||||
basename = path.basename(input, ".png");
|
||||
input = fs.readFileSync(input);
|
||||
}
|
||||
if (type == "ico") {
|
||||
icon = png2icons.createICO(input, png2icons.BICUBIC, 0, false);
|
||||
outputFile = path.join(outputDir, basename + ".ico");
|
||||
} else {
|
||||
icon = png2icons.createICNS(input, png2icons.BILINEAR, 0);
|
||||
outputFile = path.join(outputDir, basename + ".icns");
|
||||
}
|
||||
if (!icon) return;
|
||||
fs.writeFile(outputFile, icon, (err) => {
|
||||
if (err) throw err;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
pngToIcon,
|
||||
};
|
27
plugin/package-lock.json
generated
27
plugin/package-lock.json
generated
@ -7,8 +7,10 @@
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"crypto-js": "^4.2.0",
|
||||
"exif-reader": "^2.0.1",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"node-forge": "^1.3.1",
|
||||
"png2icons": "^2.0.1",
|
||||
"ses": "^1.10.0",
|
||||
"sm-crypto": "^0.3.13",
|
||||
"tree-kill": "^1.2.2"
|
||||
@ -64,6 +66,12 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/exif-reader": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz",
|
||||
"integrity": "sha512-gCQ/86RiAWSjeSlalj1G99IC6XnxbwkvB91HLqhh8somj/YBtC/2xuplvyjDjlfO7NsmYREPPElu/Syuy/H52g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
@ -145,6 +153,15 @@
|
||||
"node": ">= 6.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/png2icons": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/png2icons/-/png2icons-2.0.1.tgz",
|
||||
"integrity": "sha512-GDEQJr8OG4e6JMp7mABtXFSEpgJa1CCpbQiAR+EjhkHJHnUL9zPPtbOrjsMD8gUbikgv3j7x404b0YJsV3aVFA==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"png2icons": "png2icons-cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
@ -222,6 +239,11 @@
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
||||
},
|
||||
"exif-reader": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/exif-reader/-/exif-reader-2.0.1.tgz",
|
||||
"integrity": "sha512-gCQ/86RiAWSjeSlalj1G99IC6XnxbwkvB91HLqhh8somj/YBtC/2xuplvyjDjlfO7NsmYREPPElu/Syuy/H52g=="
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
@ -268,6 +290,11 @@
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||
"integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
|
||||
},
|
||||
"png2icons": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmmirror.com/png2icons/-/png2icons-2.0.1.tgz",
|
||||
"integrity": "sha512-GDEQJr8OG4e6JMp7mABtXFSEpgJa1CCpbQiAR+EjhkHJHnUL9zPPtbOrjsMD8gUbikgv3j7x404b0YJsV3aVFA=="
|
||||
},
|
||||
"proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
|
@ -2,8 +2,10 @@
|
||||
"dependencies": {
|
||||
"axios": "^1.7.9",
|
||||
"crypto-js": "^4.2.0",
|
||||
"exif-reader": "^2.0.1",
|
||||
"iconv-lite": "^0.6.3",
|
||||
"node-forge": "^1.3.1",
|
||||
"png2icons": "^2.0.1",
|
||||
"ses": "^1.10.0",
|
||||
"sm-crypto": "^0.3.13",
|
||||
"tree-kill": "^1.2.2"
|
||||
|
@ -6,6 +6,8 @@
|
||||
filled
|
||||
:label="label"
|
||||
:placeholder="placeholder"
|
||||
:max="max"
|
||||
:min="min"
|
||||
class="number-input"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
@ -20,7 +22,7 @@
|
||||
icon="keyboard_arrow_up"
|
||||
size="xs"
|
||||
class="number-btn"
|
||||
@click="updateNumber(100)"
|
||||
@click="updateNumber(step)"
|
||||
/>
|
||||
<q-btn
|
||||
flat
|
||||
@ -28,7 +30,7 @@
|
||||
icon="keyboard_arrow_down"
|
||||
size="xs"
|
||||
class="number-btn"
|
||||
@click="updateNumber(-100)"
|
||||
@click="updateNumber(-step)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -64,6 +66,18 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: 1000000000,
|
||||
},
|
||||
min: {
|
||||
type: Number,
|
||||
default: -1000000000,
|
||||
},
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
computed: {
|
||||
@ -75,14 +89,28 @@ export default defineComponent({
|
||||
if (value === null || value === undefined || value === "") {
|
||||
this.$emit("update:modelValue", null);
|
||||
} else {
|
||||
this.$emit("update:modelValue", value);
|
||||
const numValue = Number(value);
|
||||
if (numValue > this.max) {
|
||||
this.$emit("update:modelValue", this.max);
|
||||
} else if (numValue < this.min) {
|
||||
this.$emit("update:modelValue", this.min);
|
||||
} else {
|
||||
this.$emit("update:modelValue", numValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
updateNumber(delta) {
|
||||
this.$emit("update:modelValue", (this.localValue || 0) + delta);
|
||||
const newValue = (this.localValue || 0) + delta;
|
||||
if (newValue > this.max) {
|
||||
this.$emit("update:modelValue", this.max);
|
||||
} else if (newValue < this.min) {
|
||||
this.$emit("update:modelValue", this.min);
|
||||
} else {
|
||||
this.$emit("update:modelValue", newValue);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -63,6 +63,8 @@ export const dataCommands = {
|
||||
key: "start",
|
||||
label: "起始位置",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 1,
|
||||
icon: "first_page",
|
||||
width: 3,
|
||||
},
|
||||
@ -71,6 +73,8 @@ export const dataCommands = {
|
||||
label: "结束位置",
|
||||
type: "numInput",
|
||||
icon: "last_page",
|
||||
min: 0,
|
||||
step: 1,
|
||||
width: 3,
|
||||
},
|
||||
],
|
||||
@ -155,6 +159,7 @@ export const dataCommands = {
|
||||
{
|
||||
label: "起始位置",
|
||||
type: "numInput",
|
||||
step: 1,
|
||||
icon: "first_page",
|
||||
width: 4,
|
||||
},
|
||||
@ -162,6 +167,7 @@ export const dataCommands = {
|
||||
label: "结束位置",
|
||||
type: "numInput",
|
||||
icon: "last_page",
|
||||
step: 1,
|
||||
width: 4,
|
||||
},
|
||||
],
|
||||
|
572
src/js/composer/commands/imageCommands.js
Normal file
572
src/js/composer/commands/imageCommands.js
Normal file
@ -0,0 +1,572 @@
|
||||
import { newVarInputVal } from "js/composer/varInputValManager";
|
||||
|
||||
// 图片格式选项
|
||||
const IMAGE_FORMATS = [
|
||||
{ label: "JPEG", value: "jpeg" },
|
||||
{ label: "PNG", value: "png" },
|
||||
{ label: "WebP", value: "webp" },
|
||||
];
|
||||
|
||||
// 水印位置选项
|
||||
const WATERMARK_POSITIONS = [
|
||||
{ label: "左上角", value: "topLeft" },
|
||||
{ label: "右上角", value: "topRight" },
|
||||
{ label: "左下角", value: "bottomLeft" },
|
||||
{ label: "右下角", value: "bottomRight" },
|
||||
{ label: "居中", value: "center" },
|
||||
];
|
||||
|
||||
export const imageCommands = {
|
||||
label: "图片操作",
|
||||
icon: "image",
|
||||
defaultOpened: false,
|
||||
commands: [
|
||||
{
|
||||
value: "quickcomposer.image.analyze",
|
||||
label: "图片信息",
|
||||
desc: "分析图片基本信息",
|
||||
icon: "analytics",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
key: "file",
|
||||
label: "图片文件",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.image.resize",
|
||||
label: "调整大小",
|
||||
desc: "调整图片尺寸",
|
||||
icon: "aspect_ratio",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
key: "inputFile",
|
||||
label: "输入文件",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "outputFile",
|
||||
label: "输出文件",
|
||||
type: "varInput",
|
||||
icon: "save",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "save",
|
||||
options: {
|
||||
title: "保存图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "width",
|
||||
label: "宽度(像素)",
|
||||
type: "numInput",
|
||||
icon: "compare_arrows",
|
||||
width: 6,
|
||||
min: 1,
|
||||
step: 10,
|
||||
defaultValue: "",
|
||||
},
|
||||
{
|
||||
key: "height",
|
||||
label: "高度(像素)",
|
||||
type: "numInput",
|
||||
icon: "height",
|
||||
width: 6,
|
||||
min: 1,
|
||||
step: 10,
|
||||
defaultValue: "",
|
||||
},
|
||||
{
|
||||
key: "keepAspectRatio",
|
||||
label: "保持宽高比",
|
||||
type: "select",
|
||||
icon: "aspect_ratio",
|
||||
width: 6,
|
||||
defaultValue: "true",
|
||||
options: [
|
||||
{ label: "是", value: "true" },
|
||||
{ label: "否", value: "false" },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "quality",
|
||||
label: "图片质量(0-1)",
|
||||
type: "numInput",
|
||||
icon: "high_quality",
|
||||
width: 6,
|
||||
max: 1,
|
||||
min: 0,
|
||||
step: 0.05,
|
||||
defaultValue: 0.92,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.image.rotate",
|
||||
label: "旋转图片",
|
||||
desc: "旋转图片角度",
|
||||
icon: "rotate_right",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
key: "inputFile",
|
||||
label: "输入文件",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "outputFile",
|
||||
label: "输出文件",
|
||||
type: "varInput",
|
||||
icon: "save",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "save",
|
||||
options: {
|
||||
title: "保存图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "angle",
|
||||
label: "旋转角度",
|
||||
type: "numInput",
|
||||
icon: "rotate_right",
|
||||
width: 6,
|
||||
step: 90,
|
||||
defaultValue: 90,
|
||||
},
|
||||
{
|
||||
key: "quality",
|
||||
label: "图片质量(0-1)",
|
||||
type: "numInput",
|
||||
icon: "high_quality",
|
||||
width: 6,
|
||||
max: 1,
|
||||
min: 0,
|
||||
step: 0.05,
|
||||
defaultValue: 0.92,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.image.crop",
|
||||
label: "裁剪图片",
|
||||
desc: "裁剪图片区域",
|
||||
icon: "crop",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
key: "inputFile",
|
||||
label: "输入文件",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "outputFile",
|
||||
label: "输出文件",
|
||||
type: "varInput",
|
||||
icon: "save",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "save",
|
||||
options: {
|
||||
title: "保存图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "x",
|
||||
label: "起始X坐标",
|
||||
type: "numInput",
|
||||
icon: "arrow_right",
|
||||
width: 6,
|
||||
min: 0,
|
||||
step: 10,
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
key: "y",
|
||||
label: "起始Y坐标",
|
||||
type: "numInput",
|
||||
icon: "arrow_downward",
|
||||
width: 6,
|
||||
min: 0,
|
||||
step: 10,
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
key: "width",
|
||||
label: "裁剪宽度",
|
||||
type: "numInput",
|
||||
icon: "compare_arrows",
|
||||
width: 6,
|
||||
min: 1,
|
||||
step: 10,
|
||||
defaultValue: "",
|
||||
},
|
||||
{
|
||||
key: "height",
|
||||
label: "裁剪高度",
|
||||
type: "numInput",
|
||||
icon: "height",
|
||||
width: 6,
|
||||
min: 1,
|
||||
step: 10,
|
||||
defaultValue: "",
|
||||
},
|
||||
{
|
||||
key: "quality",
|
||||
label: "图片质量(0-1)",
|
||||
type: "numInput",
|
||||
icon: "high_quality",
|
||||
width: 6,
|
||||
max: 1,
|
||||
min: 0,
|
||||
step: 0.05,
|
||||
defaultValue: 0.92,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.image.watermark",
|
||||
label: "添加水印",
|
||||
desc: "添加文字水印",
|
||||
icon: "format_color_text",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
key: "inputFile",
|
||||
label: "输入文件",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "outputFile",
|
||||
label: "输出文件",
|
||||
type: "varInput",
|
||||
icon: "save",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "save",
|
||||
options: {
|
||||
title: "保存图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "text",
|
||||
label: "水印文字",
|
||||
type: "varInput",
|
||||
icon: "text_fields",
|
||||
width: 12,
|
||||
defaultValue: newVarInputVal("var", "水印文字"),
|
||||
},
|
||||
{
|
||||
key: "font",
|
||||
label: "字体设置",
|
||||
type: "varInput",
|
||||
icon: "font_download",
|
||||
width: 6,
|
||||
defaultValue: newVarInputVal("var", "24px Arial"),
|
||||
},
|
||||
{
|
||||
key: "color",
|
||||
label: "文字颜色",
|
||||
type: "varInput",
|
||||
icon: "format_color_text",
|
||||
width: 6,
|
||||
defaultValue: newVarInputVal("var", "rgba(255, 255, 255, 0.5)"),
|
||||
},
|
||||
{
|
||||
key: "position",
|
||||
label: "位置",
|
||||
type: "select",
|
||||
icon: "place",
|
||||
width: 6,
|
||||
defaultValue: "bottomRight",
|
||||
options: WATERMARK_POSITIONS,
|
||||
},
|
||||
{
|
||||
key: "margin",
|
||||
label: "边距",
|
||||
type: "numInput",
|
||||
icon: "space_bar",
|
||||
min: 0,
|
||||
step: 10,
|
||||
width: 6,
|
||||
defaultValue: 20,
|
||||
},
|
||||
{
|
||||
key: "opacity",
|
||||
label: "不透明度(0-1)",
|
||||
type: "numInput",
|
||||
icon: "opacity",
|
||||
max: 1,
|
||||
min: 0,
|
||||
step: 0.05,
|
||||
width: 6,
|
||||
defaultValue: 0.5,
|
||||
},
|
||||
{
|
||||
key: "quality",
|
||||
label: "图片质量(0-1)",
|
||||
type: "numInput",
|
||||
icon: "high_quality",
|
||||
max: 1,
|
||||
min: 0,
|
||||
step: 0.05,
|
||||
width: 6,
|
||||
defaultValue: 0.92,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.image.convert",
|
||||
label: "格式转换",
|
||||
desc: "转换图片格式",
|
||||
icon: "transform",
|
||||
isAsync: true,
|
||||
config: [
|
||||
{
|
||||
key: "inputFile",
|
||||
label: "输入文件",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "outputFile",
|
||||
label: "输出文件",
|
||||
type: "varInput",
|
||||
icon: "save",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "save",
|
||||
options: {
|
||||
title: "保存图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["jpg", "jpeg", "png", "webp"],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "format",
|
||||
label: "输出格式",
|
||||
type: "select",
|
||||
icon: "transform",
|
||||
width: 6,
|
||||
defaultValue: "jpeg",
|
||||
options: IMAGE_FORMATS,
|
||||
},
|
||||
{
|
||||
key: "quality",
|
||||
label: "图片质量(0-1)",
|
||||
type: "numInput",
|
||||
icon: "high_quality",
|
||||
width: 6,
|
||||
max: 1,
|
||||
min: 0,
|
||||
step: 0.05,
|
||||
defaultValue: 0.92,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: "quickcomposer.image.pngToIcon",
|
||||
label: "PNG转图标",
|
||||
desc: "将PNG图片转换为图标",
|
||||
icon: "transform",
|
||||
config: [
|
||||
{
|
||||
key: "inputFile",
|
||||
label: "PNG路径/Base64",
|
||||
type: "varInput",
|
||||
icon: "image",
|
||||
width: 12,
|
||||
options: {
|
||||
dialog: {
|
||||
type: "open",
|
||||
options: {
|
||||
title: "选择图片",
|
||||
filters: [
|
||||
{
|
||||
name: "图片文件",
|
||||
extensions: ["png"],
|
||||
},
|
||||
],
|
||||
properties: ["openFile", "multiSelections"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "outputDir",
|
||||
label: "输出目录",
|
||||
type: "varInput",
|
||||
icon: "save",
|
||||
width: 9,
|
||||
defaultValue: newVarInputVal("str", window.utools.getPath("desktop")),
|
||||
options: {
|
||||
dialog: {
|
||||
type: "save",
|
||||
options: {
|
||||
title: "选择输出目录",
|
||||
defaultPath: ".",
|
||||
properties: ["openDirectory"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "type",
|
||||
label: "输出格式",
|
||||
type: "select",
|
||||
icon: "transform",
|
||||
width: 3,
|
||||
defaultValue: "ico",
|
||||
options: ["ico", "icns"],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
@ -13,13 +13,14 @@ import { userdataCommands } from "./userdataCommands";
|
||||
import { utoolsCommands } from "./utoolsCommand";
|
||||
import { screenCommands } from "./screenCommands";
|
||||
import { audioCommands } from "./audioCommands";
|
||||
console.log(audioCommands);
|
||||
import { imageCommands } from "./imageCommands";
|
||||
|
||||
export const commandCategories = [
|
||||
fileCommands,
|
||||
networkCommands,
|
||||
systemCommands,
|
||||
audioCommands,
|
||||
imageCommands,
|
||||
notifyCommands,
|
||||
utoolsCommands,
|
||||
dataCommands,
|
||||
|
@ -11,6 +11,8 @@ export const otherCommands = {
|
||||
key: "ms",
|
||||
label: "延迟的毫秒数",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 100,
|
||||
icon: "schedule",
|
||||
defaultValue: 500,
|
||||
},
|
||||
|
@ -121,12 +121,16 @@ export const simulateCommands = {
|
||||
label: "X坐标(留空则原地点击)",
|
||||
icon: "drag_handle",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 10,
|
||||
width: 6,
|
||||
},
|
||||
{
|
||||
label: "Y坐标(留空则原地点击)",
|
||||
icon: "drag_handle",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 10,
|
||||
width: 6,
|
||||
},
|
||||
],
|
||||
@ -162,6 +166,8 @@ export const simulateCommands = {
|
||||
icon: "drag_handle",
|
||||
defaultValue: 0,
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 10,
|
||||
width: 6,
|
||||
},
|
||||
{
|
||||
@ -169,6 +175,8 @@ export const simulateCommands = {
|
||||
icon: "drag_handle",
|
||||
defaultValue: 0,
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 10,
|
||||
width: 6,
|
||||
},
|
||||
],
|
||||
|
@ -370,6 +370,8 @@ export const systemCommands = {
|
||||
{
|
||||
label: "进程ID",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 100,
|
||||
icon: "developer_board",
|
||||
width: 7,
|
||||
},
|
||||
|
@ -118,6 +118,8 @@ export const uiCommands = {
|
||||
{
|
||||
label: "显示时间(ms)",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 100,
|
||||
width: 6,
|
||||
placeholder: "0为手动关闭,留空按文本长度调整",
|
||||
},
|
||||
@ -152,6 +154,8 @@ export const uiCommands = {
|
||||
{
|
||||
label: "宽度",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 100,
|
||||
defaultValue: 450,
|
||||
width: 3,
|
||||
placeholder: "对话框宽度",
|
||||
|
@ -26,6 +26,8 @@ export const utoolsCommands = {
|
||||
key: "height",
|
||||
label: "高度",
|
||||
type: "numInput",
|
||||
min: 0,
|
||||
step: 100,
|
||||
icon: "straighten",
|
||||
width: 12,
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user