diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..53124f5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "files.trimTrailingWhitespace": true +} \ No newline at end of file diff --git a/photo-toolkit.sh b/photo-toolkit.sh new file mode 100755 index 0000000..2345677 --- /dev/null +++ b/photo-toolkit.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +# 图片工具箱启动脚本 +# 快速启动 photo-toolkit + +cd "$(dirname "$0")/photo-toolkit" +node index.js diff --git a/photo-toolkit/format.js b/photo-toolkit/format.js index c980c80..2df2d4c 100644 --- a/photo-toolkit/format.js +++ b/photo-toolkit/format.js @@ -36,10 +36,13 @@ function processImage(inputPath, outputPath) { { stdio: 'inherit' } ); } else { - const newSize = getTargetSize(type, dimensions.width, dimensions.height); - console.log(` 目标尺寸: ${newSize}`); + 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}" -gravity center -resize "${newSize}^" -extent "${newSize}" -quality 80 "${finalOutputPath}"`, + `magick "${inputPath}" ${resizeArgs} -quality 80 "${finalOutputPath}"`, { stdio: 'inherit' } ); } @@ -67,7 +70,7 @@ function processImage(inputPath, outputPath) { async function runFormatTool(rl) { console.log('\n🎨 图片格式转换工具'); console.log('='.repeat(50)); - console.log('支持类型: iPhone (4:3 JPG) · 索尼相机 (3:2 JPG) · 截图 (WebP)'); + 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(); diff --git a/photo-toolkit/utils.js b/photo-toolkit/utils.js index 2f7624a..81ea778 100644 --- a/photo-toolkit/utils.js +++ b/photo-toolkit/utils.js @@ -5,12 +5,14 @@ const readline = require('readline'); const IMAGE_TYPES = { IPHONE: 'iphone', SONY: 'sony', + XIAOMI: 'xiaomi', SCREENSHOT: 'screenshot', }; const IMAGE_TYPE_LABELS = { [IMAGE_TYPES.IPHONE]: '📱 iPhone (4:3)', [IMAGE_TYPES.SONY]: '📷 索尼相机 (3:2)', + [IMAGE_TYPES.XIAOMI]: '📱 小米手机 (4:3)', [IMAGE_TYPES.SCREENSHOT]: '🖼️ 截图 → WebP', }; @@ -72,14 +74,22 @@ function detectImageType(filePath, dimensions) { const makeUpper = make.toUpperCase(); const modelUpper = model.toUpperCase(); + // 我的 iPhone if (makeUpper === 'APPLE' || modelUpper.includes('IPHONE')) { return { type: IMAGE_TYPES.IPHONE, reason: `EXIF: ${make} ${model}`.trim() }; } + // 老妈小米 11 青春版 + if (makeUpper === 'XIAOMI' || modelUpper.includes('M2101K9C')) { + return { type: IMAGE_TYPES.XIAOMI, reason: `EXIF: ${make} ${model}`.trim() }; + } + + // 索尼相机 if (makeUpper.includes('SONY') || modelUpper.includes('ILCE') || modelUpper.startsWith('DSC-')) { return { type: IMAGE_TYPES.SONY, reason: `EXIF: ${make} ${model}`.trim() }; } + // iPhone if (['.heic', '.heif'].includes(ext)) { return { type: IMAGE_TYPES.IPHONE, reason: 'HEIC/HEIF 格式' }; } @@ -90,18 +100,19 @@ function detectImageType(filePath, dimensions) { } // 根据类型和方向获取目标尺寸,截图为 null(不裁剪) +// 索尼返回 ImageMagick 缩放规格(如 2250x),按原图宽高比缩放、不裁剪 function getTargetSize(type, width, height) { const landscape = width >= height; switch (type) { case IMAGE_TYPES.IPHONE: - return landscape ? '2000x1500' : '1500x2000'; + return { size: landscape ? '2000x1500' : '1500x2000', crop: true }; case IMAGE_TYPES.SONY: - return landscape ? '2250x1500' : '1500x2250'; + return { size: landscape ? '2250x' : 'x2250', crop: false }; case IMAGE_TYPES.SCREENSHOT: return null; default: - return landscape ? '2250x1500' : '1500x2250'; + return { size: landscape ? '2250x1500' : '1500x2250', crop: true }; } }