package main
import (
"fmt"
"image"
_ "image/gif"
"image/jpeg"
"log"
"os"
"strconv"
// JPEG 디코딩을 위해 필요합니다.
// PNG, GIF 등 다른 형식을 지원하려면 이 아래에 해당 형식을 _로 import 해야 합니다.
_ "image/jpeg"
_ "image/png"
)
// compressImage는 입력 이미지 파일의 크기를 유지하면서 JPEG 품질을 낮춰 용량을 줄입니다.
func compressImage(inputPath, outputPath string, quality int) error {
// 1. 입력 파일 열기
inputFile, err := os.Open(inputPath)
if err != nil {
return fmt.Errorf("입력 파일 열기 오류: %w", err)
}
defer inputFile.Close()
// 2. 이미지 디코딩 (파일 내용을 image.Image 인터페이스로 변환)
// image.Decode는 파일의 형식을 자동으로 감지합니다.
img, _, err := image.Decode(inputFile)
if err != nil {
return fmt.Errorf("이미지 디코딩 오류: %w", err)
}
// 3. 출력 파일 생성
outputFile, err := os.Create(outputPath)
if err != nil {
return fmt.Errorf("출력 파일 생성 오류: %w", err)
}
defer outputFile.Close()
// 4. JPEG 인코딩 옵션 설정
// Quality는 1(최저 품질/최대 압축)부터 100(최고 품질/최소 압축)까지의 값입니다.
options := &jpeg.Options{
Quality: quality,
}
// 5. 낮은 품질로 이미지 인코딩 (재압축)
// img.Bounds()를 사용하여 이미지 크기를 그대로 유지합니다.
err = jpeg.Encode(outputFile, img, options)
if err != nil {
return fmt.Errorf("JPEG 인코딩 오류: %w", err)
}
fmt.Printf("✅ 이미지 압축 완료: %s -> %s (품질: %d)\n", inputPath, outputPath, quality)
return nil
}
func printUsage(fileName string) {
fmt.Printf("Usage: %s <input image file> [Quality]\n", fileName)
fmt.Printf(" %s input.jpg \n", fileName)
fmt.Printf(" %s input.jpg 75\n", fileName)
}
func main() {
if len(os.Args) < 2 {
printUsage(os.Args[0])
os.Exit(0)
}
if os.Args[1] == "--help" || os.Args[1] == "-h" || os.Args[1] == "/?" {
printUsage(os.Args[0])
os.Exit(0)
}
if os.Args[1] == "--version" || os.Args[1] == "-v" || os.Args[1] == "/v" {
fmt.Printf("Version: 1.0.0\n")
}
inputFileName := os.Args[1]
outputFileName := "resized_" + inputFileName
compressionQuality := 75
if len(os.Args) == 3 && os.Args[2] != "" {
quality, err := strconv.Atoi(os.Args[2])
if err != nil {
log.Fatalf("품질 값 변환 오류: %v", err)
}
compressionQuality = quality
}
if err := compressImage(inputFileName, outputFileName, compressionQuality); err != nil {
log.Fatalf("이미지 압축 실패: %v", err)
}
}