fork download
  1. #!/bin/bash
  2.  
  3. # ── 收集傳入的圖片路徑 ──────────────────────────────────────
  4. FILES=("$@")
  5.  
  6. if [ ${#FILES[@]} -eq 0 ]; then
  7. # 直接雙擊啟動時,開啟選檔視窗
  8. SELECTED=$(osascript <<'EOF'
  9. set chosen to choose file with prompt "選擇要轉換的圖片(可多選):" of type {"public.png", "public.jpeg"} with multiple selections allowed
  10. set filePaths to ""
  11. repeat with f in chosen
  12.   set filePaths to filePaths & POSIX path of f & linefeed
  13. end repeat
  14. return filePaths
  15. EOF
  16. )
  17. if [ $? -ne 0 ] || [ -z "$SELECTED" ]; then
  18. exit 0
  19. fi
  20. # 將選取的路徑轉成陣列
  21. while IFS= read -r line; do
  22. [ -n "$line" ] && FILES+=("$line")
  23. done <<< "$SELECTED"
  24. fi
  25.  
  26. # ── 用 AppleScript 顯示設定對話框 ──────────────────────────
  27. SETTINGS=$(osascript <<'EOF'
  28. set dialogResult to {}
  29.  
  30. -- 1. 寬度輸入
  31. set widthInput to text returned of (display dialog "輸入輸出寬度(像素):
  32. 留空 = 不限制寬度" default answer "1920" with title "批次圖片轉換工具" buttons {"取消", "下一步"} default button "下一步")
  33. if widthInput is "" then set widthInput to "0"
  34.  
  35. -- 2. 高度輸入
  36. set heightInput to text returned of (display dialog "輸入輸出高度(像素):
  37. 留空 = 不限制高度" default answer "" with title "批次圖片轉換工具" buttons {"取消", "下一步"} default button "下一步")
  38. if heightInput is "" then set heightInput to "0"
  39.  
  40. -- 3. 等比例縮放
  41. set scaleChoice to button returned of (display dialog "縮放方式:
  42. - 等比例:依寬度等比換算高度(推薦)
  43. - 強制尺寸:強制裁切為指定長寬" with title "批次圖片轉換工具" buttons {"強制尺寸", "等比例"} default button "等比例")
  44.  
  45. -- 4. 壓縮品質
  46. set qualityInput to text returned of (display dialog "輸出品質(1–100):
  47. 100 = 最高品質,70 = 一般,50 = 較小檔案" default answer "85" with title "批次圖片轉換工具" buttons {"取消", "下一步"} default button "下一步")
  48.  
  49. -- 5. 輸出格式
  50. set formatChoice to button returned of (display dialog "輸出格式:" with title "批次圖片轉換工具" buttons {"PNG", "JPG"} default button "JPG")
  51.  
  52. -- 6. 輸出目錄
  53. set outputFolder to POSIX path of (choose folder with prompt "選擇輸出目錄:")
  54.  
  55. -- 回傳所有設定(用 | 分隔)
  56. return widthInput & "|" & heightInput & "|" & scaleChoice & "|" & qualityInput & "|" & formatChoice & "|" & outputFolder
  57. EOF
  58. )
  59.  
  60. # 檢查使用者是否取消
  61. if [ $? -ne 0 ]; then
  62. exit 0
  63. fi
  64.  
  65. # ── 解析設定值 ──────────────────────────────────────────────
  66. IFS='|' read -r WIDTH HEIGHT SCALE_MODE QUALITY FORMAT OUTPUT_DIR <<< "$SETTINGS"
  67.  
  68. # 清理路徑結尾斜線
  69. OUTPUT_DIR="${OUTPUT_DIR%/}"
  70.  
  71. # 確保輸出目錄存在
  72. mkdir -p "$OUTPUT_DIR"
  73.  
  74. # 格式轉小寫
  75. FORMAT_LOWER=$(echo "$FORMAT" | tr '[:upper:]' '[:lower:]')
  76. if [ "$FORMAT_LOWER" = "jpg" ]; then
  77. SIPS_FORMAT="jpeg"
  78. EXT="jpg"
  79. else
  80. SIPS_FORMAT="png"
  81. EXT="png"
  82. fi
  83.  
  84. # ── 批次處理每張圖片 ────────────────────────────────────────
  85. SUCCESS=0
  86. FAIL=0
  87. ERRORS=""
  88.  
  89. for FILE in "${FILES[@]}"; do
  90. # 只處理 PNG / JPG
  91. LOWER=$(echo "$FILE" | tr '[:upper:]' '[:lower:]')
  92. if [[ "$LOWER" != *.png && "$LOWER" != *.jpg && "$LOWER" != *.jpeg ]]; then
  93. FAIL=$((FAIL + 1))
  94. ERRORS="$ERRORS\n$(basename "$FILE")(不支援的格式)"
  95. continue
  96. fi
  97.  
  98. # 產生輸出檔名(去除原副檔名,加上新副檔名)
  99. BASENAME=$(basename "$FILE")
  100. NOEXT="${BASENAME%.*}"
  101. OUTFILE="$OUTPUT_DIR/${NOEXT}.${EXT}"
  102.  
  103. # 避免覆蓋同名檔案
  104. COUNTER=1
  105. while [ -f "$OUTFILE" ]; do
  106. OUTFILE="$OUTPUT_DIR/${NOEXT}_${COUNTER}.${EXT}"
  107. COUNTER=$((COUNTER + 1))
  108. done
  109.  
  110. # 先複製到輸出路徑,再用 sips 處理
  111. cp "$FILE" "$OUTFILE"
  112.  
  113. # 建立 sips 指令
  114. SIPS_CMD="sips"
  115.  
  116. # 格式轉換
  117. SIPS_CMD="$SIPS_CMD -s format $SIPS_FORMAT"
  118.  
  119. # 壓縮品質(僅 JPEG 有效,sips 接受整數 0–100)
  120. if [ "$SIPS_FORMAT" = "jpeg" ] && [ -n "$QUALITY" ]; then
  121. SIPS_CMD="$SIPS_CMD -s formatOptions $QUALITY"
  122. fi
  123.  
  124. # 縮放處理
  125. if [ "$SCALE_MODE" = "等比例" ]; then
  126. if [ "$WIDTH" != "0" ] && [ -n "$WIDTH" ]; then
  127. SIPS_CMD="$SIPS_CMD --resampleWidth $WIDTH"
  128. elif [ "$HEIGHT" != "0" ] && [ -n "$HEIGHT" ]; then
  129. SIPS_CMD="$SIPS_CMD --resampleHeight $HEIGHT"
  130. fi
  131. else
  132. # 強制尺寸(需要寬高都有值才執行)
  133. if [ "$WIDTH" != "0" ] && [ "$HEIGHT" != "0" ] && [ -n "$WIDTH" ] && [ -n "$HEIGHT" ]; then
  134. SIPS_CMD="$SIPS_CMD --resampleHeightWidth $HEIGHT $WIDTH"
  135. elif [ "$WIDTH" != "0" ] && [ -n "$WIDTH" ]; then
  136. SIPS_CMD="$SIPS_CMD --resampleWidth $WIDTH"
  137. elif [ "$HEIGHT" != "0" ] && [ -n "$HEIGHT" ]; then
  138. SIPS_CMD="$SIPS_CMD --resampleHeight $HEIGHT"
  139. fi
  140. fi
  141.  
  142. SIPS_CMD="$SIPS_CMD \"$OUTFILE\""
  143.  
  144. # 執行轉換
  145. if eval $SIPS_CMD 2>/dev/null; then
  146. SUCCESS=$((SUCCESS + 1))
  147. else
  148. FAIL=$((FAIL + 1))
  149. ERRORS="$ERRORS\n$(basename "$FILE")(轉換失敗)"
  150. rm -f "$OUTFILE"
  151. fi
  152. done
  153.  
  154. # ── 顯示完成通知 ─────────────────────────────────────────────
  155. SUMMARY="✅ 成功轉換:$SUCCESS\n❌ 失敗:$FAIL 張"
  156. if [ -n "$ERRORS" ]; then
  157. SUMMARY="$SUMMARY\n\n失敗檔案:$ERRORS"
  158. fi
  159.  
  160. BUTTON=$(osascript -e "display dialog \"$SUMMARY\" with title \"批次轉換完成\" buttons {\"開啟輸出目錄\", \"關閉\"} default button \"關閉\"" 2>/dev/null)
  161. if [[ "$BUTTON" == *"開啟輸出目錄"* ]]; then
  162. open "$OUTPUT_DIR"
  163. fi
Success #stdin #stdout #stderr 0.01s 5288KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
./prog.sh: line 16: osascript: command not found