| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- /**
- * fun 结点:img-scale — 图片等比缩放(宽高同乘同一比例)
- *
- * 入参(inVars 顺序,与 img-cropping 一致:先路径再参数):
- * - imagePath:源图(相对流程目录或绝对路径)
- * - savePath:输出路径
- * - scale:缩放系数。支持:
- * - 0.8 → 长宽各 ×0.8
- * - "80%" → 80%;整数 10~100 视为百分比,如 80 即 80%
- * - 1~10 之间的小数/整数为倍率,如 2 即 2 倍、1.5 即 1.5 倍(整数 10 为 10% 而非 10 倍)
- */
- const path = require('path')
- const fs = require('fs')
- const { spawnSync } = require('child_process')
- const { getPythonExeFromConfig } = require('../../../../python-exe-from-config.js')
- const tagName = 'img-scale'
- const configPath = process.env.STATIC_ROOT
- ? path.join(path.dirname(path.resolve(process.env.STATIC_ROOT)), 'config.js')
- : path.join(__dirname, '..', '..', '..', '..', '..', 'config.js')
- const config = fs.existsSync(configPath) ? require(configPath) : {}
- const projectRoot = (config.projectRoot && fs.existsSync(config.projectRoot))
- ? config.projectRoot
- : path.dirname(path.resolve(configPath))
- const scaleScriptPath = path.join(projectRoot, 'python', 'scripts', 'img-scale-proportional.py')
- function buildAbsolutePath (p, folderPath) {
- if (p == null || p === '') return null
- const s = typeof p === 'string' ? p.trim() : String(p)
- if (!s) return null
- if (path.isAbsolute(s) || /^[A-Za-z]:/.test(s)) return path.normalize(s)
- return folderPath ? path.join(folderPath, s) : path.resolve(projectRoot, s)
- }
- /**
- * @param {{ imagePath: string, savePath: string, scale: string|number, folderPath?: string }} input
- */
- async function executeImgScale ({ imagePath, savePath, scale, folderPath }) {
- if (imagePath == null || String(imagePath).trim() === '') {
- return { success: false, error: 'img-scale 缺少 imagePath(inVars[0])' }
- }
- if (savePath == null || String(savePath).trim() === '') {
- return { success: false, error: 'img-scale 缺少 savePath(inVars[1])' }
- }
- if (scale === undefined || scale === null || scale === '') {
- return { success: false, error: 'img-scale 缺少 scale(inVars[2],如 0.8 或 80%)' }
- }
- const scaleStr = typeof scale === 'number' && Number.isFinite(scale) ? String(scale) : String(scale).trim()
- if (!scaleStr) return { success: false, error: 'img-scale scale 无效' }
- const absIn = buildAbsolutePath(String(imagePath).trim(), folderPath)
- const absOut = buildAbsolutePath(String(savePath).trim(), folderPath)
- if (!absIn || !absOut) return { success: false, error: 'img-scale 路径无效' }
- if (!fs.existsSync(absIn)) return { success: false, error: `img-scale 源文件不存在: ${absIn}` }
- if (!fs.existsSync(scaleScriptPath)) {
- return { success: false, error: `脚本不存在: ${scaleScriptPath}` }
- }
- const pythonExe = getPythonExeFromConfig(config)
- const r = spawnSync(pythonExe, [scaleScriptPath, absIn, absOut, scaleStr], {
- encoding: 'utf-8',
- timeout: 120_000,
- cwd: projectRoot,
- })
- const combined = ((r.stdout || '') + '\n' + (r.stderr || '')).trim()
- if (r.status !== 0) {
- return { success: false, error: combined || 'img-scale 执行失败' }
- }
- let meta = {}
- const lines = (r.stdout || '').split(/\r?\n/).map((l) => l.trim()).filter(Boolean)
- const jsonLine = lines.filter((l) => l.startsWith('{')).pop()
- if (jsonLine) {
- try {
- meta = JSON.parse(jsonLine)
- } catch (_) {}
- }
- if (!meta.success) {
- return { success: false, error: meta.error || combined || 'img-scale 未返回成功' }
- }
- return {
- success: true,
- path: absOut,
- value: absOut,
- result: absOut,
- scaled: {
- scale: meta.scale,
- sourceWidth: meta.sourceWidth,
- sourceHeight: meta.sourceHeight,
- width: meta.width,
- height: meta.height,
- },
- }
- }
- module.exports = { tagName, executeImgScale }
|