Pagi ini, istri saya ada keperluan mengirim sejumlah file melalui WhatsApp. File tersebut berisi banyak foto berukuran besar, bahkan ada yang lebih dari 10 MB per foto. Total ukuran seluruh file mencapai 1,09 GB. Istri saya kemudian mengemasnya menggunakan WinRAR, tetapi setelah dikompres, ukurannya masih sekitar 1 GB. Dengan ukuran sebesar itu, tentu proses pengiriman melalui WhatsApp bisa memakan waktu, apalagi jika koneksi internet sedang tidak bersahabat.
Karena ukurannya masih terlalu besar, istri saya meminta bantuan saya untuk mencari cara agar file tersebut lebih mudah dikirim. Saya berpikir, daripada harus mengompres foto satu per satu menggunakan aplikasi pengolah gambar, lebih baik mencari cara agar semuanya bisa diproses sekaligus. Saya lalu meminta bantuan ChatGPT untuk membuatkan skrip Python yang berfungsi mengompres semua foto di dalam sebuah folder, termasuk foto yang tersimpan di dalam subfolder.
Mengapa Tidak Cukup Menggunakan WinRAR?
WinRAR memang berguna untuk mengemas banyak file menjadi satu arsip. Namun, foto seperti JPEG umumnya sudah menggunakan kompresi. Ketika foto-foto tersebut dikemas kembali menggunakan WinRAR, ukurannya biasanya tidak banyak berkurang.
Itulah yang terjadi pada kumpulan foto tadi. Ukuran awalnya 1,09 GB, tetapi setelah dikemas menggunakan WinRAR, ukurannya masih sekitar 1 GB.
Jika tujuannya mengurangi ukuran kumpulan foto, pendekatan yang lebih tepat adalah mengompres gambar secara langsung. Dengan begitu, ukuran setiap foto bisa diperkecil sebelum dikirim atau dikemas kembali menjadi satu arsip.
Meminta Bantuan ChatGPT Membuat Skrip Python
Saya tidak ingin membuka foto satu per satu, mengompresnya secara manual, lalu menyimpan hasilnya kembali. Jika jumlah fotonya banyak, cara tersebut tentu merepotkan dan membutuhkan waktu.
Akhirnya, saya meminta bantuan ChatGPT untuk membuatkan skrip Python yang bisa mengerjakan semuanya secara otomatis. Skrip tersebut dirancang untuk memindai folder yang berisi foto, termasuk subfolder di dalamnya, kemudian mengompres gambar yang ditemukan.
Saya juga meminta agar hasil kompresi disimpan di folder terpisah dengan struktur yang tetap menyerupai folder aslinya. Jadi, foto yang awalnya berada di dalam folder Liburan, misalnya, akan tetap berada di folder Liburan pada lokasi tujuan.
Dengan cara ini, file asli tidak ditimpa. Saya tetap bisa membandingkan foto sebelum dan sesudah dikompres, sekaligus memastikan susunan file tidak berantakan.
Persiapan Sebelum Menjalankan Skrip
Untuk menjalankan skrip ini, kita membutuhkan Python dan pustaka Pillow yang digunakan untuk memproses gambar.
Jika Python sudah terpasang di komputer, buka Command Prompt atau PowerShell, kemudian jalankan perintah berikut untuk memasang Pillow:
python -m pip install --upgrade Pillow
Setelah proses instalasi selesai, buat file bernama kompres_foto.py, lalu masukkan kode berikut.
Script untuk Mengompres Banyak Foto
from pathlib import Path
from PIL import Image, ImageOps, UnidentifiedImageError
import shutil
import sys
# Sesuaikan lokasi folder dengan komputer Anda.
SOURCE_DIR = Path(r"D:\path\to\source_dir")
OUTPUT_DIR = Path(r"D:\path\to\output_dir")
JPEG_QUALITY = 85
WEBP_QUALITY = 82
PNG_OPTIMIZE = True
SUPPORTED_EXTENSIONS = {
".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tif", ".tiff", ".gif"
}
def format_size(size_bytes: int) -> str:
value = float(size_bytes)
for unit in ("B", "KB", "MB", "GB", "TB"):
if value < 1024 or unit == "TB":
return f"{value:.2f} {unit}"
value /= 1024
return f"{value:.2f} TB"
def copy_original(src: Path, dst: Path) -> None:
dst.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src, dst)
def has_transparency(image: Image.Image) -> bool:
if image.mode in ("RGBA", "LA"):
return image.getchannel("A").getextrema()[0] < 255
if image.mode == "P" and "transparency" in image.info:
return True
return False
def compress_image(src: Path, dst: Path) -> tuple[int, int, str]:
"""
Mengembalikan (ukuran_asli, ukuran_hasil, status).
File tujuan menggunakan nama dan ekstensi yang sama.
"""
original_size = src.stat().st_size
dst.parent.mkdir(parents=True, exist_ok=True)
ext = src.suffix.lower()
# GIF dianjurkan tetap disalin agar animasi dan frame terjaga.
if ext == ".gif":
copy_original(src, dst)
return original_size, dst.stat().st_size, "salin (GIF/animasi)"
try:
with Image.open(src) as opened:
# Memperbaiki orientasi berdasarkan metadata EXIF.
image = ImageOps.exif_transpose(opened)
image.load()
# JPEG
if ext in (".jpg", ".jpeg"):
if image.mode not in ("RGB", "L"):
image = image.convert("RGB")
image.save(
dst,
format="JPEG",
quality=JPEG_QUALITY,
optimize=True,
progressive=True,
exif=opened.info.get("exif", b""),
icc_profile=opened.info.get("icc_profile"),
)
# PNG: lossless optimization agar transparansi tetap terjaga.
elif ext == ".png":
image.save(dst, format="PNG", optimize=PNG_OPTIMIZE)
# WebP
elif ext == ".webp":
image.save(
dst,
format="WEBP",
quality=WEBP_QUALITY,
method=6,
lossless=False,
)
# BMP/TIFF: simpan tetap dengan ekstensi asli menggunakan format
# aslinya; hindari mengganti ekstensi diam-diam.
elif ext == ".bmp":
image.save(dst, format="BMP")
elif ext in (".tif", ".tiff"):
image.save(dst, format="TIFF", compression="tiff_lzw")
else:
copy_original(src, dst)
# Jika hasil lebih besar, gunakan file asli agar tidak merugikan.
compressed_size = dst.stat().st_size
if compressed_size >= original_size:
copy_original(src, dst)
return original_size, dst.stat().st_size, "salin (hasil tidak lebih kecil)"
return original_size, compressed_size, "dikompres"
except (UnidentifiedImageError, OSError, ValueError) as exc:
# File bermasalah/tidak dapat dibaca: tetap salin dan lanjutkan.
copy_original(src, dst)
return original_size, dst.stat().st_size, f"salin (gagal kompres: {exc})"
def main() -> None:
if not SOURCE_DIR.exists():
print(f"Folder sumber tidak ditemukan:\n{SOURCE_DIR}")
sys.exit(1)
if SOURCE_DIR.resolve() == OUTPUT_DIR.resolve():
print("Folder sumber dan tujuan tidak boleh sama.")
sys.exit(1)
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
files = [
path for path in SOURCE_DIR.rglob("*")
if path.is_file() and path.suffix.lower() in SUPPORTED_EXTENSIONS
and OUTPUT_DIR not in path.parents
]
if not files:
print("Tidak ditemukan file gambar yang didukung.")
return
total_before = 0
total_after = 0
compressed_count = 0
copied_count = 0
error_count = 0
print(f"Sumber : {SOURCE_DIR}")
print(f"Tujuan : {OUTPUT_DIR}")
print(f"Jumlah file gambar: {len(files)}\n")
for index, src in enumerate(files, start=1):
relative_path = src.relative_to(SOURCE_DIR)
dst = OUTPUT_DIR / relative_path
before, after, status = compress_image(src, dst)
total_before += before
total_after += after
if status == "dikompres":
compressed_count += 1
else:
copied_count += 1
if "gagal kompres" in status:
error_count += 1
saved = before - after
print(
f"[{index}/{len(files)}] {relative_path} | "
f"{format_size(before)} -> {format_size(after)} | "
f"{status}"
+ (f" | hemat {format_size(saved)}" if saved > 0 else "")
)
saved_total = total_before - total_after
percent = (saved_total / total_before * 100) if total_before else 0
print("\n===== RINGKASAN =====")
print(f"File diproses : {len(files)}")
print(f"Dikompres : {compressed_count}")
print(f"Disalin : {copied_count}")
print(f"Gagal kompres : {error_count}")
print(f"Ukuran awal : {format_size(total_before)}")
print(f"Ukuran hasil : {format_size(total_after)}")
print(f"Penghematan : {format_size(saved_total)} ({percent:.2f}%)")
print(f"\nHasil tersimpan di:\n{OUTPUT_DIR}")
if __name__ == "__main__":
main()
Ada dua bagian yang perlu disesuaikan sebelum skrip dijalankan:
SOURCE_DIR = Path(r"D:\path\to\source_dir")
OUTPUT_DIR = Path(r"D:\path\to\output_dir")
Ganti D:\path\to\source_dir dengan lokasi folder yang berisi foto asli. Kemudian, ganti D:\path\to\output_dir dengan lokasi folder untuk menyimpan hasil kompresi.
Sebagai contoh, jika foto berada di D:\Dokumen\Foto, lokasi sumber bisa diatur menjadi Path(r"D:\Dokumen\Foto"). Folder tujuan sebaiknya berada di lokasi terpisah agar foto asli tetap aman.
Cara Menjalankan Skrip
Simpan file Python tersebut, lalu buka Command Prompt atau PowerShell pada lokasi file berada.
Jika skrip disimpan di folder Downloads, jalankan:
python "$env:USERPROFILE\Downloads\kompres_foto.py"
Skrip akan mulai memproses foto yang ditemukan. Terminal menampilkan nama file serta ukuran sebelum dan sesudah kompresi. Setelah semua selesai, akan muncul ringkasan total ukuran awal, ukuran hasil, dan jumlah ruang yang berhasil dihemat.
Hasil Kompresi Foto
Setelah skrip dijalankan, hasilnya ternyata cukup memuaskan. Sebanyak 94 file foto berhasil diproses tanpa ada file yang gagal dikompres. Ukuran keseluruhan yang semula 1,09 GB berhasil diperkecil menjadi sekitar 180,57 MB.
Berikut ringkasan hasilnya:
| Keterangan | Hasil |
|---|---|
| Jumlah file diproses | 94 |
| Berhasil dikompres | 94 |
| Disalin tanpa kompresi | 0 |
| Gagal dikompres | 0 |
| Ukuran awal | 1,09 GB |
| Ukuran setelah kompresi | 180,57 MB |
| Penghematan ukuran | 936,95 MB |
| Pengurangan ukuran | 83,84% |
kompres-foto-python.JPG

Hasil Kompres
Artinya, ukuran kumpulan foto berhasil dikurangi sekitar 84 persen. Dari yang semula lebih dari 1 GB, kini ukurannya tinggal sekitar 180 MB.
Akhirnya, urusan istri saya untuk mengirim foto pun selesai. Dari yang awalnya berukuran 1,09 GB, kumpulan foto tersebut berhasil diperkecil menjadi sekitar 180 MB. Masalah sederhana di pagi hari ini justru menjadi kesempatan bagi saya untuk mencoba sesuatu yang praktis dengan bantuan ChatGPT. Lumayan, daripada harus mengompres 94 foto satu per satu, lebih baik biarkan skrip Python yang bekerja.
