Ngăn WordPress nén ảnh của bạn ở mức 82%
WordPress mã hóa lại mọi ảnh JPEG mà nó tạo ra ở chất lượng 82 trên thang điểm 0–100. Giá trị mặc định đó nằm trong WP_Image_Editor::get_default_quality() và áp dụng cho
Đã đăng
WordPress mã hóa lại mọi ảnh JPEG mà nó tạo ra ở chất lượng 82 trên thang điểm 0–100. Giá trị mặc định đó nằm trong WP_Image_Editor::get_default_quality() và áp dụng cho mọi ảnh con mà WordPress cắt ra từ ảnh bạn up lên — thumbnail, medium, medium_large, large, và mọi kích thước bổ sung mà theme của bạn đăng ký. Với ảnh chụp, 82 là mức cân bằng hợp lý giữa dung lượng file và nhiễu. Nhưng với ảnh chụp màn hình, ảnh chụp giao diện, biểu đồ, logo, và bất cứ thứ gì có chữ sắc nét hay màu phẳng, thì 82 phá hình thấy rõ: bạn sẽ thấy nhiễu lấm tấm bò quanh từng chữ cái và hiện tượng dải màu trên các vùng chuyển sắc mượt.
Để thay đổi mức này, bạn thêm một filter rồi regenerate lại thumbnail. Còn để fix riêng cho ảnh chụp màn hình, câu trả lời tốt hơn thường là đừng đưa cho WordPress một file JPEG ngay từ đầu.
Con số 82 thực ra đến từ đâu
WordPress hạ giá trị JPEG mặc định từ 90 xuống 82 từ phiên bản 4.5 (2016) như một cách tối ưu dung lượng trang. Giá trị này được trả về bởi get_default_quality() trong wp-includes/class-wp-image-editor.php và được đọc mỗi khi editor đang hoạt động — WP_Image_Editor_Imagick nếu hosting của bạn có Imagick, còn không thì WP_Image_Editor_GD — ghi ra một file đã resize.
Chi tiết quan trọng: 82 được áp dụng cho từng ảnh con, chứ không phải một lần duy nhất. Up lên một tấm ảnh, và WordPress chạy nó qua bộ mã hóa nhiều lần, lượng tử hóa lại ở chất lượng 82 mỗi lần. Bản thân file gốc bạn up lên thì được giữ nguyên nếu nó nằm dưới ngưỡng big-image (2560px ở cạnh dài). Nếu nó vượt ngưỡng đó, WordPress tạo ra một file -scaled.jpg đã mã hóa lại ở chất lượng 82 và phục vụ file đó làm kích thước “full”. Vì vậy câu “ảnh full-resolution của tôi nhìn ổn nhưng phiên bản trên trang lại bị nhòe” hầu như luôn là do srcset chọn một ảnh con chất lượng 82 hoặc file -scaled.
Cách thay đổi chất lượng
Chỉ có một filter cần hook vào. wp_editor_set_quality là filter hiện đại, chuẩn mực — nó kích hoạt cho cả JPEG và WebP và nhận vào kiểu MIME nên bạn có thể rẽ nhánh:
add_filter( 'wp_editor_set_quality', function ( $quality, $mime_type ) {
if ( 'image/jpeg' === $mime_type ) {
return 92; // up from 82
}
return $quality;
}, 10, 2 );
Đặt đoạn này vào một mu-plugin nhỏ (wp-content/mu-plugins/) hoặc một plugin riêng cho site. Đặt vào functions.php cũng được, nhưng bạn sẽ mất thiết lập này ngay khi đổi theme.
Bạn cũng sẽ thấy người ta khuyên dùng filter cũ hơn là jpeg_quality. Nó vẫn còn hoạt động (WordPress áp dụng nó ngay sau wp_editor_set_quality, chỉ cho JPEG), nhưng chẳng có lý do gì để hook cả hai — wp_editor_set_quality bao trùm mọi thứ mà filter cũ làm được và còn hơn thế.
Một điều ai cũng quên: filter này chỉ ảnh hưởng đến những ảnh được mã hóa sau khi nó được kích hoạt. Mọi thumbnail đã nằm sẵn trong wp-content/uploads đều đã được ghi ở mức 82 và sẽ giữ nguyên 82. Hãy regenerate chúng:
wp media regenerate --yes
Nếu bạn không dùng WP-CLI, plugin Regenerate Thumbnails làm đúng việc đó thông qua trang admin.
Trước khi chốt một con số, bạn nên xem thử một mức chất lượng cụ thể thực sự làm gì với ảnh của bạn thay vì đoán mò. Công cụ chất lượng JPEG cho WordPress của chúng tôi mã hóa lại một ảnh mẫu ngay trên trình duyệt ở mọi mức chất lượng để bạn thấy nhiễu xuất hiện — nó cho thấy sự khác biệt giữa 82, 90, và 100 trên một ảnh chụp màn hình một cách rõ ràng mà một con số trong file config không bao giờ làm được.
Cách fix tốt hơn cho ảnh chụp màn hình và đồ họa phẳng
Nâng con số JPEG chỉ là chữa triệu chứng. Vấn đề thực sự với ảnh chụp màn hình là JPEG là codec sai cho chúng. Nén DCT của JPEG được tinh chỉnh cho các vùng chuyển sắc kiểu ảnh chụp; nó sụp đổ ở các cạnh đen-trên-trắng sắc cạnh của chữ và giao diện, và đó chính là lý do tại sao chất lượng 82 nhìn tệ hơn nhiều trên ảnh chụp màn hình so với trên một tấm ảnh chụp bãi biển.
Hãy up một file PNG thay vào đó. WordPress giữ các ảnh con của PNG dưới dạng PNG, và PNG là không mất dữ liệu — filter chất lượng không đụng vào nó, nên không có nhiễu ở bất kỳ kích thước nào, chỉ có việc resample sạch sẽ. Với một ảnh chụp màn hình, một file PNG được tối ưu tốt thường còn nhỏ hơn cả một file JPEG chất lượng cao của cùng tấm ảnh, vì màu phẳng nén rất tốt trong PNG và rất tệ trong JPEG.
Nếu bạn muốn file nhỏ hơn của một định dạng mất dữ liệu mà không bị hư cạnh như JPEG, thì WebP là điểm trung gian — nhưng bạn vẫn kiểm soát chất lượng của nó qua chính filter wp_editor_set_quality đã nêu ở trên, rẽ nhánh theo image/webp.
Những điều không nên làm
Đừng đặt chất lượng lên 100 cho toàn bộ. Đây là câu trả lời được vote nhiều nhất trong nửa số thread trên các diễn đàn, và nó sai. JPEG chất lượng 100 không phải là không mất dữ liệu — nó vẫn lượng tử hóa — nhưng nó làm phình to mọi tấm ảnh chụp trên site của bạn lên đáng kể mà chẳng được lợi gì thấy được, kéo tụt LCP và Core Web Vitals. Hãy nâng con số cho định dạng thực sự cần, hoặc đổi định dạng cho đồ họa; đừng phá nén trên toàn site.
Đừng sửa class-wp-image-editor.php. Thay đổi giá trị trả về của get_default_quality() trong core sẽ có tác dụng cho đến lần wp core update tiếp theo âm thầm ghi đè lên nó. Hãy dùng filter.
Đừng tắt các kích thước ảnh để “tránh nén”. Tắt việc tạo thumbnail không ngăn được việc mã hóa lại — nó làm hỏng srcset responsive, khiến trình duyệt tải về ảnh full-size trên điện thoại. Vấn đề khác, hậu quả còn tệ hơn.
Đừng cho rằng up lại sẽ fix được ảnh cũ. Nếu bạn đặt filter nhưng bỏ qua bước regenerate, mọi ảnh con cũ vẫn ở chất lượng 82. Filter chỉ có tác dụng về sau.
Đừng đổ lỗi cho file -scaled nếu ảnh của bạn dưới 2560px — nhánh đó không bao giờ chạy với chúng. Nếu bạn đang gặp phải nó và muốn phục vụ ảnh gốc chưa bị đụng vào, thì đó là một thiết lập riêng; xem tắt ảnh scaled.
Vẫn còn kẹt?
Nếu một kích thước cụ thể vẫn nhìn sai sau khi regenerate, hãy xác nhận trang thực sự đang phục vụ file nào — mở ảnh trong tab mới và kiểm tra xem tên file có kết thúc bằng hậu tố kích thước (-1024x768.jpg) hay -scaled.jpg không. Công cụ kiểm tra kích thước ảnh hiển thị mọi ảnh con mà WordPress tạo ra từ một lần up, để bạn thấy chính xác kích thước nào mà srcset đang đưa cho trình duyệt và ngừng debug nhầm file.