2026-06-27 · อัปเดต 2026-07-26

การบีบอัดรูปภาพใน Python ด้วย Pillow, WebP และ mozjpeg

บีบอัดรูปภาพ JPEG, PNG และ WebP ใน Python โดยใช้ Pillow, cwebp และ mozjpeg พร้อมด้วยการตั้งค่าคุณภาพ (quality settings), ลูปกำหนดขนาดเป้าหมาย (target-size loops) และสคริปต์แบทช์ที่รวดเร็ว

การบีบอัดรูปภาพใน Python ด้วย Pillow, WebP และ mozjpeg

คำตอบสั้นๆ: วิธีบีบอัดรูปภาพใน Python คืออะไร?

เปิดรูปภาพด้วย Pillow จากนั้นบันทึกโดยใช้ format flags ที่เหมาะสม สำหรับภาพถ่าย ให้บันทึกเป็น JPEG โดยใช้ quality=80, optimize=True, และ progressive=True สำหรับไฟล์สมัยใหม่ที่ต้องการขนาดเล็กที่สุด ให้บันทึกเป็น WebP ด้วย quality=80, method=6 ส่วนกราฟิกแบนและภาพหน้าจอ ให้คงรูปแบบ PNG ไว้และส่งค่า optimize=True

ฟังก์ชันสี่บรรทัดนี้สามารถลดขนาด JPEG จากโทรศัพท์และ DSLR ส่วนใหญ่ได้ถึง 40 ถึง 70 เปอร์เซ็นต์ ส่วนที่เหลือของคู่มือนี้จะเพิ่มเป้าหมายด้านขนาด, WebP, mozjpeg และ batch runner เพื่อให้คุณชี้ไปที่ directory แล้วปล่อยให้มันทำงาน

ต้องเตรียมอะไรบ้างก่อนเริ่ม?

คุณต้องมี Python 3.9 หรือใหม่กว่า และ Pillow ซึ่งเป็นฟอร์กที่ได้รับการดูแลของ PIL Pillow สามารถจัดการกับ JPEG, PNG, และ WebP ได้ทันทีบนแพลตฟอร์มทั่วไปทุกชนิด

สำหรับผลลัพธ์ที่เล็กที่สุด คุณควรมีตัวเข้ารหัสแบบบรรทัดคำสั่งอีกสองตัวที่ Python สามารถเรียกใช้ได้ ได้แก่ cwebp จาก libwebp และ cjpeg จาก mozjpeg

ตรวจสอบว่าแต่ละส่วนใช้ทำอะไรก่อนที่คุณจะเขียนโค้ด:

  • Pillow ใช้สำหรับอ่านและเขียนทุกรูปแบบ และทำหน้าที่ปรับขนาดรูปภาพ
  • cwebp สร้างไฟล์ WebP ที่มีขนาดเล็กที่สุดและเปิดให้มีการปรับแต่งมากกว่า Pillow
  • mozjpeg ทำการเข้ารหัสใหม่ (re-encodes) ไฟล์ JPEG ให้มีขนาดเล็กกว่า libjpeg มาตรฐานที่ Pillow ใช้
  • เครื่องมือช่วยรายงานผล เพื่อให้ทุกครั้งที่รันจะแสดงจำนวนไบต์ที่คุณประหยัดได้

นี่คือตัวช่วยที่ใช้ตลอดคู่มือนี้:

หากคุณต้องการบีบอัดแบบครั้งเดียวและไม่ต้องการติดตั้งอะไรเลย เครื่องมือบีบอัดรูปภาพบนเบราว์เซอร์ เครื่องมือบีบอัดภาพ ก็สามารถทำงานเดียวกันนี้ได้สำหรับไฟล์จำนวนเล็กน้อย

ต้องทำอย่างไรถึงจะบีบอัดไฟล์ JPEG ด้วย Pillow?

ฟลาก (flags) สามตัวที่สำคัญสำหรับ JPEG คือ quality, optimize, และ progressive โดย quality ควบคุมว่า encoder จะทิ้งรายละเอียดไปมากน้อยแค่ไหน การตั้งค่า optimize=True จะรันรอบที่สองเพื่อสร้าง Huffman table ที่มีขนาดเล็กลง ส่วน progressive=True จะจัดเรียงไฟล์ใหม่เพื่อให้แสดงผลจากบนลงล่างด้วยความละเอียดต่ำก่อน ซึ่งจะให้ความรู้สึกว่าเร็วขึ้นในการเชื่อมต่อที่ช้า และโดยปกติแล้วยังช่วยลดขนาดไฟล์ได้อีกเล็กน้อย

แล็ปท็อปบนโต๊ะไม้แสดงโค้ดต้นฉบับที่เปิดในโปรแกรมแก้ไข

ควรเลือกค่าคุณภาพตามสถานที่ที่ภาพจะถูกนำไปใช้ ไม่ใช่ตัวเลขเดียวทั่วโลก:

ค่าคุณภาพ การใช้งานทั่วไป สิ่งที่คาดหวัง
90-95 ภาพฮีโร่, ตัวอย่างงานพิมพ์ ใกล้เคียงต้นฉบับ, ไฟล์มีขนาดใหญ่ขึ้นอย่างเห็นได้ชัด
75-85 รูปภาพบนเว็บส่วนใหญ่ ค่าเริ่มต้นที่ปลอดภัย, ประหยัดพื้นที่มาก
60-70 ภาพย่อและตัวอย่างพรีวิว ความนุ่มลงของรายละเอียดเล็กน้อยที่มองเห็นได้
Below 50 หลีกเลี่ยงสำหรับรูปถ่าย สิ่งแปลกปลอมแบบบล็อกรอบขอบ

ข้อผิดพลาดที่ทำให้คนส่วนใหญ่ติดขัดคือ: JPEG ไม่มี alpha channel หากคุณเปิดภาพหน้าจอ PNG ที่มีความโปร่งใสและบันทึกเป็น JPEG โดยตรง Pillow จะแจ้งข้อผิดพลาดว่า cannot write mode RGBA as JPEG การเรียกใช้ convert("RGB") ในฟังก์ชันก่อนหน้านี้จะทำการทำให้ความโปร่งใสนั้นแบนลงบนพื้นหลังสีทึบก่อน ซึ่งนั่นคือเหตุผลที่มันต้องทำงานก่อนการบันทึกไฟล์ JPEG ทุกครั้ง

การบีบอัด PNG และการแปลงเป็น WebP

PNG เป็นรูปแบบที่ไม่มีการสูญเสียข้อมูล (lossless) ดังนั้นคุณจึงไม่สามารถแลกเปลี่ยนคุณภาพกับขนาดได้เหมือนกับการใช้ JPEG สิ่งที่คุณทำได้คือเรียกใช้ตัวปรับปรุงของ Pillow และสำหรับสิ่งใดก็ตามที่เป็นภาพถ่ายจริง ๆ คุณควรเปลี่ยนรูปแบบโดยสิ้นเชิง

method=6 บอกให้ตัวเข้ารหัส WebP ใช้เวลามากขึ้นในการค้นหาไฟล์ที่มีขนาดเล็กลง แม้ว่าจะช้ากว่าต่อภาพ แต่ก็คุ้มค่าในขั้นตอนการสร้าง (build step) สำหรับภาพถ่ายที่เริ่มต้นเป็น PNG ขนาด 2 MB, WebP ที่คุณภาพ 80 มักจะมีขนาดต่ำกว่า 200 KB ในขณะที่ดูเหมือนกันเมื่อแสดงผลตามปกติ การวัดของ Google เองระบุว่า WebP มีขนาดเล็กกว่า JPEG ที่เทียบเคียงได้ประมาณ 25 ถึง 35 เปอร์เซ็นต์ ตาม WebP documentation

ใช้ตารางนี้เพื่อเลือกรูปแบบแทนการคาดเดา:

เนื้อหาต้นฉบับ รูปแบบที่ดีที่สุด ทำไม
ภาพถ่าย WebP หรือ JPEG การไล่ระดับเรียบบีบอัดได้ดีแบบสูญเสีย
โลโก้ ไอคอน UI เรียบ PNG หรือ WebP lossless ขอบคมชัด
สกรีนช็อตมีข้อความ PNG หรือ WebP lossless หลีกเลี่ยงข้อความพร่าจากพาสสูญเสีย
ภาพที่ต้องการความโปร่งใส WebP หรือ PNG JPEG เก็บอัลฟ่าช่องไม่ได้

หากคุณยังคงตัดสินใจเลือกระหว่างรูปแบบสำหรับเว็บไซต์ทั้งหมด การสรุปใน WebP vs JPEG vs PNG จะครอบคลุมการรองรับของเบราว์เซอร์และการแลกเปลี่ยนข้อดีข้อเสียอย่างละเอียดกว่า

การกำหนดขนาดไฟล์เป้าหมายด้วยการวนซ้ำ

"Make it under 200 KB" เป็นข้อกำหนดทั่วไปจากเครื่องมืออีเมล, marketplace, และขีดจำกัดการอัปโหลดของ CMS คุณไม่สามารถเลือกค่าคุณภาพที่ตรงกับเป้าหมายไบต์ได้ในการลองครั้งแรก เพราะคุณภาพเดียวกันจะให้ขนาดที่แตกต่างกันมากสำหรับภาพที่มีรายละเอียดสูงเทียบกับภาพเรียบๆ ให้วนลูปลดคุณภาพลงจากระดับสูงจนกว่าจะได้ขนาดต่ำกว่าขีดจำกัด:

อาร์กิวเมนต์ floor จะหยุดลูปก่อนที่คุณภาพจะลดลงจนอยู่ในระดับที่ไม่ชัดเจน (smear territory) หากรูปภาพไม่สามารถถึงเป้าหมายที่สูงกว่าค่า floor ได้ ฟังก์ชันก็จะยังคงส่งค่ากลับมาเพื่อให้คุณสามารถบันทึกข้อมูลและปรับขนาดรูปภาพแทนการบีบอัดให้หนักขึ้น สำหรับงบประมาณไบต์ที่กำหนด เช่น 100 KB หรือ 50 KB ลูปเดียวกันนี้ก็ใช้ได้เช่นกัน บทแนะนำใน compress images without losing quality อธิบายว่าเมื่อใดที่การปรับขนาดดีกว่าการลดคุณภาพ

จะทำให้ JPEG มีขนาดเล็กลงด้วย mozjpeg และ cwebp ได้อย่างไร?

Pillow บันทึก JPEG ด้วย libjpeg encoder มาตรฐาน mozgjpeg เป็น drop-in encoder จาก Mozilla ที่สร้างไฟล์ที่มีขนาดเล็กลงในคุณภาพทางสายตาที่เท่ากัน โดยปกติจะลดได้อีก 5 ถึง 15 เปอร์เซ็นต์ เนื่องจาก Pillow ไม่ได้รวมมันไว้ จึงต้องเรียกใช้ binary cjpeg ผ่าน subprocess ส่วน cjpeg ของ mozgjpeg สามารถอ่าน PPM ได้อย่างเชื่อถือ ดังนั้นให้ทำการ flatten รูปภาพด้วย Pillow ก่อน:

สำหรับ WebP การเรียกใช้ cwebp โดยตรงจะให้คุณเข้าถึงตัวควบคุมที่ Pillow ไม่ได้เปิดเผย เช่น -m 6 สำหรับความพยายามสูงสุด และ -sharp_yuv สำหรับขอบสีที่คมชัดยิ่งขึ้น:

นี่คือการเปรียบเทียบตัวเลือกต่างๆ เพื่อให้คุณตัดสินใจได้ว่าจะติดตั้งอะไร:

Tool Best for Trade-off
Pillow สคริปต์ทั่วไป ทุกรูปแบบ ไม่ใช่ JPEG ที่เล็กที่สุด
mozjpeg Progressive JPEG ที่เล็กที่สุด ไบนารีเพิ่ม PPM รอบทริป
cwebp (libwebp) การควบคุม WebP ที่แน่นที่สุด ไบนารีแยกต้องติดตั้ง
pillow-simd ปรับขนาดเร็วกว่าบนเซิร์ฟเวอร์ x86 สร้างและตรึงยากกว่า

โปรเจกต์ mozgjpeg ได้จัดทำเอกสารเกี่ยวกับ encoder และ benchmarks ของมันในที่ mozjpeg repository และรายการตัวเลือกการบันทึกของ Pillow ทั้งหมดอยู่ใน Pillow image file formats reference

จะบีบอัดโฟลเดอร์จำนวนมากให้เร็วได้อย่างไร?

รูปภาพเดียวทำได้ง่าย งานที่แท้จริงคือไดเรกทอรีที่มีหลายร้อยไฟล์ คุณต้องปรับขนาดทุกอย่างให้แคบกว่าความต้องการของเลย์เอาต์ จากนั้นจึงทำการบีบอัด และรันงานข้ามเธรดเพื่อให้โฟลเดอร์ 500 รูปภาพเสร็จสิ้นภายในไม่กี่วินาทีแทนที่จะเป็นนาที

นักพัฒนาที่เวิร์คสเตชันหลายจอ กำลังรันโค้ดขณะใส่หูฟัง

ข้อสังเกตเชิงปฏิบัติบางประการจากการใช้งานจริงในสภาพแวดล้อม Production:

  1. ปรับขนาดก่อนบีบอัด การเสิร์ฟภาพถ่าย 6000 px ให้กับคอลัมน์ 1200 px จะทำให้เสียไบต์ที่การตั้งค่าคุณภาพใด ๆ ก็ไม่สามารถกู้คืนได้
  2. Pillow จะปล่อย GIL ในระหว่างการเข้ารหัส ดังนั้นเธรดจึงช่วยเพิ่มความเร็วได้จริงที่นี่ คุณไม่จำเป็นต้องใช้ multiprocessing สำหรับโฟลเดอร์ส่วนใหญ่
  3. เขียนไปยังไดเรกทอรีเอาต์พุตแยกต่างหาก เพื่อให้แน่ใจว่าการรันที่ผิดพลาดจะไม่เขียนทับไฟล์ต้นฉบับของคุณ
  4. ใช้ Image.LANCZOS สำหรับการลดขนาด (downscaling) เพราะมันช่วยรักษาขอบให้คมชัดกว่าฟิลเตอร์เริ่มต้น
  5. บันทึกไฟล์ทุกไฟล์ด้วยตัวช่วย report และเก็บไฟล์ต้นฉบับไว้จนกว่าคุณจะได้ตรวจสอบตัวอย่างแล้ว

หากงานของคุณเป็นแบบที่ทำซ้ำ ๆ ไม่ใช่ครั้งเดียว รูปแบบใน batch image processing จะครอบคลุมเรื่องคิว (queues), การลองใหม่ (retries) และข้อกำหนดในการตั้งชื่อ สำหรับการรันโดยไม่ต้องใช้โค้ดกับไฟล์ zip, เครื่องมือประมวลผลแบบกลุ่ม และ เครื่องมือแปลงไฟล์ จะจัดการการเปลี่ยนแปลงรูปแบบได้โดยไม่จำเป็นต้องมีสคริปต์

คุณควรเลือกแนวทางไหน?

ให้จับคู่วิธีการให้เข้ากับงาน แทนที่จะใช้เครื่องมือที่หนักที่สุดเสมอไป:

  • รูปภาพ Web ในขั้นตอนการสร้าง (build step): ใช้ Pillow WebP ที่คุณภาพ 80 หรือใช้ cwebp ด้วย -m 6 เมื่อคุณต้องการเพิ่มอีกไม่กี่เปอร์เซ็นต์สุดท้าย
  • งบประมาณไบต์ที่เข้มงวด: ใช้ลูป compress_to_target, และย้อนกลับไปใช้การปรับขนาดเมื่อถึงขีดจำกัดแล้ว
  • ระบบงาน JPEG แบบเก่าที่คุณไม่สามารถเปลี่ยนแปลงได้: ทำการเข้ารหัสผลลัพธ์ใหม่ด้วย mozjpeg เพื่อประหยัดพื้นที่ฟรี
  • ภาพหน้าจอและแผนผัง: ใช้ PNG ที่มี optimize=True, หรือใช้ WebP แบบไม่สูญเสียข้อมูล (lossless) หากเบราว์เซอร์ของคุณรองรับ

สำหรับทฤษฎีเบื้องหลังว่าทำไมการตั้งค่าเหล่านี้ถึงใช้งานได้จริง image compression guide ได้อธิบายเรื่อง lossy เทียบกับ lossless และวิธีที่ quantization tables ส่งผลต่อผลลัพธ์

ข้อผิดพลาดและการแก้ไขทั่วไป

ข้อยกเว้นเพียงไม่กี่ข้อเป็นสาเหตุของการทำงานที่ล้มเหลวส่วนใหญ่:

  • cannot write mode RGBA as JPEG — ให้เรียกใช้ img.convert("RGB") ก่อนบันทึกเป็น JPEG.
  • Image.DecompressionBombError — Pillow ป้องกันรูปภาพขนาดใหญ่มาก; ให้เพิ่มขีดจำกัดเฉพาะสำหรับไฟล์ที่คุณเชื่อถือด้วย Image.MAX_IMAGE_PIXELS = 200_000_000.
  • OSError: broken data stream — ไฟล์ต้นฉบับถูกตัดทอน; ให้ตั้งค่า ImageFile.LOAD_TRUNCATED_IMAGES = True เพื่อกู้คืน จากนั้นดาวน์โหลดซ้ำเมื่อเป็นไปได้.
  • ผลลัพธ์มีขนาดใหญ่กว่าอินพุต — คุณบันทึกไฟล์ JPEG ที่ถูกบีบอัดแล้วซ้ำ; ให้บีบอัดจากต้นฉบับ ไม่ใช่จากการส่งออกครั้งก่อน.
  • สีดูจาง — ไฟล์ต้นฉบับที่เป็น CMYK ถูกบันทึกโดยไม่มีการแปลง; ให้เรียกใช้ convert("RGB") ก่อน.

ข้อสรุปที่สำคัญ

Pillow จัดการการบีบอัดภาพถึง 90 percent ใน Python ด้วยแฟล็ก JPEG สามตัวและ WebP save ให้ใช้ mojpeg และ cwebp เมื่อคุณต้องการไฟล์ที่มีขนาดเล็กที่สุด ห่อทุกอย่างด้วย target-size loop เมื่องบประมาณไบต์คงที่ และรันโฟลเดอร์ผ่านฟังก์ชัน batch แบบ threaded เมื่อปริมาณเพิ่มขึ้น เก็บไฟล์ต้นฉบับของคุณ ปรับขนาดก่อนที่คุณจะบีบอัด และพิมพ์จำนวนที่ประหยัดได้ในการรันทุกครั้ง เพื่อให้คุณทราบเสมอว่า pipeline กำลังทำอะไรอยู่จริง ๆ

ตัวอย่างโค้ดที่เก็บรักษาไว้

from PIL import Image

def compress_jpeg(src, dst, quality=80):
    img = Image.open(src)
    if img.mode in ("RGBA", "P"):
        img = img.convert("RGB")
    img.save(dst, "JPEG", quality=quality, optimize=True, progressive=True)
pip install Pillow
brew install webp mozjpeg   # macOS; Linux: apt install webp, build mozjpeg
import os

def report(src, dst):
    before, after = os.path.getsize(src), os.path.getsize(dst)
    saved = (1 - after / before) * 100
    print(f"{before/1024:.0f} KB -> {after/1024:.0f} KB ({saved:.0f}% smaller)")
def compress_png(src, dst):
    Image.open(src).save(dst, "PNG", optimize=True, compress_level=9)

def to_webp(src, dst, quality=80):
    img = Image.open(src)
    img.save(dst, "WEBP", quality=quality, method=6)
def compress_to_target(src, dst, target_kb=200, q=90, floor=35):
    img = Image.open(src).convert("RGB")
    while q >= floor:
        img.save(dst, "JPEG", quality=q, optimize=True, progressive=True)
        if os.path.getsize(dst) <= target_kb * 1024:
            return q
        q -= 5
    return q
import subprocess

def mozjpeg(src, dst, quality=80):
    Image.open(src).convert("RGB").save("_tmp.ppm")
    subprocess.run(["cjpeg", "-quality", str(quality), "-progressive",
                    "-optimize", "-outfile", dst, "_tmp.ppm"], check=True)
    os.remove("_tmp.ppm")
def cwebp(src, dst, quality=82):
    subprocess.run(["cwebp", "-q", str(quality), "-m", "6",
                    "-sharp_yuv", src, "-o", dst], check=True)
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

def batch(in_dir, out_dir, quality=80, max_width=1920):
    out = Path(out_dir); out.mkdir(parents=True, exist_ok=True)
    files = [p for p in Path(in_dir).iterdir()
             if p.suffix.lower() in {".jpg", ".jpeg", ".png"}]
    def work(p):
        img = Image.open(p)
        if img.width > max_width:
            h = round(img.height * max_width / img.width)
            img = img.resize((max_width, h), Image.LANCZOS)
        img.convert("RGB").save(out / f"{p.stem}.jpg", "JPEG",
                                quality=quality, optimize=True, progressive=True)
    with ThreadPoolExecutor() as pool:
        list(pool.map(work, files))
    return len(files)
from PIL import Image, ImageFile
Image.MAX_IMAGE_PIXELS = 200_000_000
ImageFile.LOAD_TRUNCATED_IMAGES = True

ใช้เครื่องมือฟรีของเราขณะทำตามคู่มือนี้

ภาพปกของ รายการตรวจสอบ Image Optimization: ทุกขั้นตอนสำหรับภาพเว็บที่รวดเร็ว

2026-07-26

รายการตรวจสอบ Image Optimization: ทุกขั้นตอนสำหรับภาพเว็บที่รวดเร็ว

เช็คลิสต์ Image Optimization ที่สมบูรณ์แบบ: ครอบคลุมตั้งแต่การเลือก format, การปรับขนาด (resizing), compression, responsive delivery, lazy loading ไปจนถึงการตั้งค่า CDN ใช้คู่มือนี้ก่อนเผยแพร่ทุกครั้งเพื่อประสิทธิภาพสูงสุด

ภาพปกของ วิธีบีบอัดรูปภาพให้ต่ำกว่า 100KB โดยไม่ทำลายคุณภาพ

2026-07-26

วิธีบีบอัดรูปภาพให้ต่ำกว่า 100KB โดยไม่ทำลายคุณภาพ

ปรับขนาดเป็นความกว้างที่แสดง จากนั้นส่งออกเป็น WebP ขนาดไฟล์ที่วัดได้จริงของภาพถ่ายจากมือถือ ภาพสินค้า และภาพหน้าจอ แสดงสูตรที่จะทำให้แต่ละประเภทอยู่ใต้ 100KB