Groovy 強大的 Java 生態互操作性與腳本簡潔性,使其成為圖片批量處理自動化的利器。本文提供一個生產級縮略圖生成腳本,支援等比縮放、長邊優先適配、小圖不放大、自動輸出命名,可直接用於 CMS 圖片預覽、電商商品縮略圖等場景。
import javax.imageio.ImageIO
import java.io.File
import java.io.IOException
import java.awt.image.BufferedImage
import java.awt.Image
import java.awt.Graphics
/**
* 生成縮略圖
* @param input 源圖片 File
* @param output 目標輸出 File
* @param length 縮略圖長邊最大像素
*/
def createThumbnail(File input, File output, int length) throws IOException {
if (!input.exists()) {
throw new RuntimeException("Input file not exists: ${input.absolutePath}")
}
if (!output.exists()) {
output.createNewFile()
}
BufferedImage srcImage = ImageIO.read(input)
int realWidth = srcImage.getWidth()
int realHeight = srcImage.getHeight()
// 計算目標尺寸:等比縮放,長邊不超過 length
int width, height
if (realWidth < length && realHeight < length) {
// 原圖小於目標尺寸,保持原大小(不放大)
width = realWidth
height = realHeight
} else if ((length * realHeight) / realWidth > length) {
// 高度為長邊,按高度壓縮
width = (length * realWidth) / realHeight
height = length
} else {
// 寬度為長邊,按寬度壓縮
width = length
height = (length * realHeight) / realWidth
}
// 高質量縮放
Image scaled = srcImage.getScaledInstance(width, height, Image.SCALE_SMOOTH)
BufferedImage targetImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB)
Graphics g = targetImage.getGraphics()
g.drawImage(scaled, 0, 0, null)
g.dispose()
// 輸出 JPEG,品質可通過 ImageWriteParam 進一步控制
ImageIO.write(targetImage, "jpeg", output)
}
// ========== 批量處理主程式 ==========
def dir = new File("d:/var/wormser/sample")
dir.eachFile { f ->
def name = f.name
println "Processing: $name"
// 輸出命名:原名_tb.jpg(如 photo.png -> photo_tb.jpg)
def newFileName = name.replaceAll(/^([a-zA-Z0-9_]+)\.([a-zA-Z0-9]+)$/, "\$1_tb.jpg")
def newFile = new File(dir.absolutePath + File.separator + newFileName)
println "Output: $newFileName"
createThumbnail(f, newFile, 160) // 長邊 160px
}
(length * realHeight) / realWidth > length 判斷長邊,等價於比較 realHeight > realWidth 但避免浮點運算。Image.SCALE_SMOOTH:採用雙立方插值算法,比 SCALE_FAST(鄰近插值)質量顯著更好,適合照片類圖片。BufferedImage.TYPE_INT_RGB 畫布,確保輸出為標準 24 位 RGB JPEG,兼容性最佳。正則 /^([a-zA-Z0-9_]+)\.([a-zA-Z0-9]+)$/ 捕獲文件名主體與副檔名,替換為 \$1_tb.jpg 統一輸出 JPEG 格式,便於前端統一處理。實際專案中可擴展為:
\$1_tb.\$2\$1_tb_\${System.currentTimeMillis()}.\$2\$1_tb160.\$2、\$1_tb320.\$2import javax.imageio.*
import java.awt.image.*
import java.awt.*
import java.io.*
def createThumbnailAdvanced(File input, File output, int maxDim, float quality = 0.85f, boolean recursive = false) {
def processFile = { File f ->
if (!f.isFile() || !isImageFile(f)) return
def outName = getOutputName(f, output)
def outFile = new File(output, outName)
createThumbnail(f, outFile, maxDim, quality)
}
if (recursive) {
input.traverse(type: FileType.FILES, processFile)
} else {
input.eachFileMatch(~/.*\.(jpg|jpeg|png|bmp|gif|webp)/i, processFile)
}
}
def isImageFile(File f) {
f.name.toLowerCase().matches(".*\\.(jpg|jpeg|png|bmp|gif|webp)")
}
def getOutputName(File src, File outDir) {
def name = src.name
def base = name[0..name.lastIndexOf('.')-1]
def ext = "jpg" // 統一輸出 jpg,或保留原 ext
"${base}_tb.${ext}"
}
def createThumbnail(File input, File output, int maxDim, float quality) {
BufferedImage src = ImageIO.read(input)
int w = src.width, h = src.height
if (w <= maxDim && h <= maxDim) {
// 直接複製或重編碼
ImageIO.write(src, "jpg", output)
return
}
// 計算尺寸(同前)
// ...
BufferedImage target = new BufferedImage(width, height, hasAlpha(src) ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB)
Graphics2D g2d = target.createGraphics()
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC)
g2d.drawImage(src, 0, 0, width, height, null)
g2d.dispose()
// 品質控制輸出
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next()
ImageWriteParam param = writer.getDefaultWriteParam()
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT)
param.setCompressionQuality(quality)
try (FileImageOutputStream fos = new FileImageOutputStream(output)) {
writer.setOutput(fos)
writer.write(null, new IIOImage(target, null, null), param)
}
}
def hasAlpha(BufferedImage img) {
img.colorModel.hasAlpha()
}
// 使用範例
createThumbnailAdvanced(new File("d:/images"), new File("d:/thumbs"), 300, 0.9f, true)
GROOVY_HOME。groovy thumbnail.groovy 或打包為 groovyc 編譯後用 java -cp ... 執行。crontab / Windows 任務計劃程式定時掃描上傳目錄生成縮略圖。-Xmx512m 避免 OOM,Groovy 啟動腳本可透過 JAVA_OPTS 傳遞。