const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); const { question, getImageDimensions, detectImageType, getTargetSize, getOutputExtension, IMAGE_TYPES, IMAGE_TYPE_LABELS, } = require('./utils'); // 处理单个图片 function processImage(inputPath, outputPath) { const filename = path.basename(inputPath); const dimensions = getImageDimensions(inputPath); const { type, reason } = detectImageType(inputPath, dimensions); const outputExt = getOutputExtension(type); const newFilename = path.basename(outputPath, path.extname(outputPath)) + outputExt; const finalOutputPath = path.join(path.dirname(outputPath), newFilename); if (fs.existsSync(finalOutputPath)) { console.log(`⏭️ 跳过已存在的文件: ${newFilename}`); return false; } console.log(`\n📸 处理: ${filename}`); console.log(` 类型: ${IMAGE_TYPE_LABELS[type]} (${reason})`); console.log(` 尺寸: ${dimensions.width}x${dimensions.height}`); try { if (type === IMAGE_TYPES.SCREENSHOT) { execSync( `magick "${inputPath}" -gravity center -quality 80 "${finalOutputPath}"`, { stdio: 'inherit' } ); } else { const target = getTargetSize(type, dimensions.width, dimensions.height); console.log(` 目标尺寸: ${target.size}${target.crop ? '' : ' (保持比例)'}`); const resizeArgs = target.crop ? `-gravity center -resize "${target.size}^" -extent "${target.size}"` : `-resize "${target.size}"`; execSync( `magick "${inputPath}" ${resizeArgs} -quality 80 "${finalOutputPath}"`, { stdio: 'inherit' } ); } console.log(` ✅ 图片转换完成 → ${outputExt}`); } catch (error) { console.error(` ❌ 图片转换失败`); throw error; } try { execSync( `exiftool -overwrite_original -gps:all= -artist="奇趣保罗" -CreatorTool= "${finalOutputPath}"`, { stdio: 'inherit' } ); console.log(` ✅ 元数据处理完成`); } catch (error) { console.error(` ❌ 元数据处理失败`); throw error; } return true; } // 格式转换主函数 async function runFormatTool(rl) { console.log('\n🎨 图片格式转换工具'); console.log('='.repeat(50)); console.log('支持类型: iPhone (4:3 JPG) · 索尼相机 (3:2 JPG) · 截图 (WebP) · 小米手机 (4:3 JPG)'); const inputDir = await question(rl, '\n📁 请输入图片所在目录 (留空使用当前目录): '); const sourceDir = inputDir.trim() || process.cwd(); if (!fs.existsSync(sourceDir)) { console.error(`❌ 目录不存在: ${sourceDir}`); return; } const outputDir = await question(rl, '📁 请输入输出目录 (留空使用 output): '); const targetDir = outputDir.trim() || path.join(sourceDir, 'output'); if (!fs.existsSync(targetDir)) { fs.mkdirSync(targetDir, { recursive: true }); console.log(`✅ 已创建输出目录: ${targetDir}`); } const extensions = ['.heic', '.heif', '.png', '.jpg', '.jpeg', '.HEIC', '.HEIF', '.PNG', '.JPG', '.JPEG']; const files = fs.readdirSync(sourceDir).filter(file => { const ext = path.extname(file); const fullPath = path.join(sourceDir, file); const isFile = fs.statSync(fullPath).isFile(); const hasValidExt = extensions.includes(ext); const notModified = !file.includes('MODIFIED') && !file.includes('MERGED'); return isFile && hasValidExt && notModified; }); if (files.length === 0) { console.log('\n⚠️ 未找到符合条件的图片文件'); return; } console.log(`\n📋 找到 ${files.length} 个文件:`); files.forEach((file, index) => { const inputPath = path.join(sourceDir, file); const dimensions = getImageDimensions(inputPath); const { type, reason } = detectImageType(inputPath, dimensions); console.log(` ${index + 1}. ${file} → ${IMAGE_TYPE_LABELS[type]} (${reason})`); }); const confirm = await question(rl, '\n❓ 是否开始处理? (y/n): '); if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') { console.log('❌ 已取消'); return; } console.log('\n🚀 开始处理...\n'); let processed = 0; let skipped = 0; let failed = 0; for (let i = 0; i < files.length; i++) { const file = files[i]; const inputPath = path.join(sourceDir, file); const outputPath = path.join(targetDir, file); console.log(`\n[${i + 1}/${files.length}]`); try { const result = processImage(inputPath, outputPath); if (result) { processed++; } else { skipped++; } } catch (error) { console.error(`❌ 处理失败: ${file}`); failed++; } } console.log('\n' + '='.repeat(50)); console.log('📊 处理完成!'); console.log(` ✅ 成功: ${processed} 个`); console.log(` ⏭️ 跳过: ${skipped} 个`); console.log(` ❌ 失败: ${failed} 个`); console.log(` 📁 输出目录: ${targetDir}`); } module.exports = { runFormatTool };