Sıkıştırılan görsel neden büyüyor? Üç gerçek neden
Sıkıştırıcınızda büyük ihtimalle bir sorun yok. Görsel sıkıştırma işe yaramıyorsa, yani çıktı girdiyle aynı boyutta ya da gözle görülür biçimde daha büyük dönüyorsa, neden neredeyse her zaman üç şeyden biridir. Bozuk bir araç bu üçünün arasında yok.
Önce en sık görüleni. Tarayıcının canvas öğesi üzerinden sıkıştıran her araç, PNG’nizin renk türünü atar ve her pikseli yeniden 32 bit RGBA olarak kodlar. Bu sitedeki 83 Open Graph kart PNG’sinin tamamını Chrome 151.0.0.0 içinde canvas.toBlob('image/png') üzerinden geçirdik. 83’ünün hepsi daha büyük döndü. Büyüme medyanı +%76,6, en küçüğü +%35,6, en büyüğü +%237,2 oldu.
İkinci neden: JPEG’iniz zaten sıkıştırılmış. Onu 0,8 kalitesinde beş tur döndürün; dosya boyutu ikinci geçişten sonra yerinden kıpırdamaz, oysa her geçiş görüntüyü biraz daha bozar.
Üçüncüsü: PNG’niz zaten nicelenmiş. İkinci bir geçişin kaldırabileceği renk fazlalığı kalmamış.
Bunların hiçbirini kalite kaydırıcısını aşağı çekerek çözemezsiniz. Çözüm ya farklı bir biçim ya da farklı bir kodlayıcıdır. Aynı 83 PNG’yi 0,8 kalitesinde WebP’ye çevirdiğimizde hepsi küçüldü, medyan −%94,2.
Bu sayılar nasıl üretildi. Playwright ile sürülen Chrome 151.0.0.0, macOS 26.5.2, Node v25.8.2, upng-js 2.1.0, ImageMagick. 83 dosyalık küme, bu sitenin
public/ogdizinindeki PNG’lerin tamamıdır, bir örneklem değildir. 1200×630 ve 800×600 ölçülerindeki dört ek kontrollü dosya da fotoğraf, grafik, palet ve JPEG durumlarını ayrı ayrı kapsıyor.
1. Görsel sıkıştırma işe yaramıyor: otuz saniyelik triyaj
Kendi satırınızı bulun, sonra işaret ettiği bölümü okuyun.
| Ne verdiniz | Ne aldınız | Kök neden | Okuyun |
|---|---|---|---|
| PNG ekran görüntüsü ya da grafik | Orijinalinden büyük | canvas onu 32 bit RGBA olarak yeniden kodladı | Bölüm 2 |
| JPEG fotoğraf | Orijinalinden büyük | PNG olarak kaydedilmiş | Bölüm 2 |
| JPEG fotoğraf | Neredeyse hiç değişmemiş | Boyut platosuna çoktan ulaşmış | Bölüm 3 |
| Bir sıkıştırıcıdan çoktan geçmiş PNG | Değişmemiş ya da azıcık büyümüş | Sıkacak yer kalmamış | Bölüm 4 |
| Herhangi bir görsel | Küçülmüş ama yumuşak ya da rengi kaymış | Nesil kaybı ya da sökülmüş bir ICC profili | Bölüm 3 ve 6 |
Satırlar birbirini dışlamıyor. canvas tabanlı bir PNG dışa aktarıcısına bırakılan bir JPEG fotoğraf ilk iki satıra aynı anda girer; 47.828 baytlık bir dosyanın 809.415 bayta çıkması işte böyle olur.
Teşhisi atlayıp doğrudan daha küçük bir dosya istiyorsanız, resim sıkıştırıcımız canvas turu yerine niceleyen bir PNG kodlayıcı çalıştırır ve sonuç yüklediğiniz dosyadan küçük çıkmadığında kendi çıktısını atar.
2. Birinci neden: tarayıcı canvas’ı her zaman 32 bit RGBA yazar
canvas.toBlob() PNG’nize ne yapıyor
Bir canvas turunda sıkıştırma adımı diye bir şey yok. Bir çözme ve bir yeniden kodlama var; piksel değeri olmayan her şey de aradaki boşlukta düşüyor.
Bir görseli canvas’a çizdiğinizde tarayıcı onu düz bir RGBA arabelleğine çözer: piksel başına dört bayt, palet yok, bit derinliği hilesi yok, meta veri yok. Ardından HTMLCanvasElement.toBlob() bu arabelleği sıfırdan kodlar. PNG belirtimi altı renk türü tanımlar ve bir PNG kodlayıcı, görüntüyü temsil eden en ucuz türü seçmekte serbesttir. Chrome’un canvas kodlayıcısı seçim yapmaz. Her zaman color type 6 üretir.
| Giren renk türü | canvas.toBlob('image/png') ne geri veriyor |
|---|---|
| RGB (color type 2) | RGBA (color type 6) |
| Palet (color type 3) | RGBA (color type 6) |
| JPEG (PNG renk türü yok) | RGBA (color type 6) |
Bunu doğrudan baytlardan okuyabilirsiniz. Bir PNG dosyasının 25. baytı bit derinliği, 26. baytı renk türüdür; ikisi de IHDR chunk’ının içindedir:
xxd -s 24 -l 2 -p suspect.png
# 0806 -> bit derinliği 8, color type 6 (RGBA)
Yukarıdaki üç girdi türünün üçü de depth=8 type=6 verdi. 64 renkli bir palet görüntüsü piksel başına bir bayt ve küçük bir tablo saklar; turdan sonra piksel başına dört bayt saklar ve tablo yok olur. Deflate bunun bir kısmını geri kazandırır, tamamını asla.
Bunu kendi tarayıcınızda şu konsol parçacığıyla yeniden üretin. Bir dosya seçer, tura sokar ve her iki boyutu renk türüyle birlikte yazdırır:
const input = document.createElement('input');
input.type = 'file';
input.accept = 'image/png,image/jpeg';
input.onchange = async () => {
const file = input.files[0];
const bitmap = await createImageBitmap(file);
const canvas = document.createElement('canvas');
canvas.width = bitmap.width;
canvas.height = bitmap.height;
canvas.getContext('2d').drawImage(bitmap, 0, 0);
const blob = await new Promise((r) => canvas.toBlob(r, 'image/png'));
const head = new Uint8Array(await blob.slice(0, 26).arrayBuffer());
console.log(file.name, file.size, '->', blob.size);
console.log('bit depth', head[24], 'color type', head[25]);
};
input.click();
toBlob’un kalite argümanı image/png için yok sayılır. PNG kayıpsızdır, dolayısıyla bir kalite sayısının feda edebileceği bir şey yoktur; canvas tabanlı bir araçta PNG sıkıştırmasını yönetiyormuş gibi duran kaydırıcı hiçbir şeyi yönetmez.
83 dosyayı ölçtük: sıkıştırılan her görsel orijinalinden büyük döndü
Koşunun tamamı aşağıda; hiçbir dosyayı ayıklamadık:
| Ölçüm | Değer |
|---|---|
| Test edilen dosya | 83 (public/og içindeki her PNG, hem RGB hem palet renk türleri) |
| Büyüyen dosya | 83 / 83 (%100) |
| En küçük artış | +%35,6 |
| Medyan artış | +%76,6 |
| En büyük artış | +%237,2 |
Şeklini görebilmeniz için tek bir dosya: aes-decrypt.png 505.516 B’den 898.014 B’ye çıktı, yani +%77,6 artış. Aynı dosya 0,8 kalitesinde WebP olarak kodlandığında 27.188 B, yani −%94,6.
Bu 83 dosyanın ne olduğu sonucun kapsamını belirliyor. Hepsi birer Open Graph kartı: 1200×630, düz zeminler, iri metin, bir avuç marka rengi. İyi bir PNG kodlayıcının rahatça başa çıktığı grafik türü budur; bir canvas turunun onlara bu kadar zarar vermesinin nedeni de budur. Sonuç grafik türü PNG’ler için güçlü; ama bu, dünyadaki her PNG’nin canvas turunda büyüdüğü iddiası değil. Zaten tam RGBA olarak saklanmış fotoğrafik bir PNG’nin kaybedecek çok daha az şeyi vardır.
Sıkıştırılan görseliniz orijinalinden büyükse ve araç bir tarayıcı sekmesinde çalışıyorsa, önce ayarlarınıza değil kodlayıcıya bakın.
PNG olarak kaydedilen bir JPEG neden 16,9 kat büyür
Veri kümesindeki en çarpıcı satır bu. Dört kontrollü dosyanın dördünü de aynı canvas yolundan geçirdik:
| Dosya | Nitelik | Orijinal | canvas PNG | Değişim | JPEG q92 | JPEG q80 | WebP q80 |
|---|---|---|---|---|---|---|---|
og-a.png | Grafik, 2.351 renk, RGB | 306.302 | 607.481 | +%98,3 | 56.459 | 37.695 | 13.852 |
quantized.png | 64 renkli palet | 59.843 | 184.856 | +%208,9 | 78.388 | 44.442 | 16.046 |
photo.png | Fotoğraf, 479.373 renk | 498.639 | 867.763 | +%74,0 | 77.321 | 45.050 | 24.068 |
photo.jpg | JPEG q82 | 47.828 | 809.415 | +%1.592 (16,9×) | 58.762 (+%22,9) | 47.152 | 23.862 |
Son satırın anlamı şu: 47.828 bayt girdi, 809.415 bayt çıktı.
Bu mekanizma, “sıkıştırınca büyüdü” şikâyetlerinin koca bir ailesini açıklıyor. JPEG kayıplı, frekans alanında çalışan bir codec’tir: 8×8 blokları DCT katsayılarına dönüştürür, onları agresif biçimde niceler ve hayatta kalanları saklar. PNG ise kayıpsız, uzamsal bir codec’tir: her pikseli komşularından tahmin eder ve artıkları deflate ile sıkıştırır. Bir JPEG’i çözdüğünüzde, niceleyicinin soktuğu her bozulmayı taşıyan pikseller elinize geçer: kenarların yanında çınlama, yumuşak gradyanlarda bloklaşma, orijinalinde hiç olmayan yerde ince gürültü.
O pikselleri PNG olarak kaydettiğinizde, kayıpsız bir codec’ten bozulmaları kusursuzca saklamasını istemiş olursunuz. O da istediğinizi yapar. JPEG’in dosyayı küçültmek için ürettiği gürültü, artık PNG’yi büyüten şeyin ta kendisidir; çünkü tahmine dayalı kayıpsız bir kodlayıcının sıkıştıramadığı şey tam olarak gürültüdür.
Bir fotoğrafın önünde “PNG olarak kaydet” varsayılanı duran her yerde bu oluyor: ekran görüntüsü araçları, tasarım dışa aktarımları, sohbet istemcileri, bazı yükleme bileşenleri.
Aynı pikseller, arada 3,46 kat, ikisi de kayıpsız
canvas kodlayıcısı zayıf ve bunu ölçebilirsiniz. og-a.png dosyasının piksel arabelleğini alın ve ikisi de tümüyle kayıpsız olan iki yolla kodlayın:
| Kodlayıcı | Çıktı | Renk türü |
|---|---|---|
Chrome canvas toBlob('image/png') | 607.481 B | RGBA (zorunlu yükseltme) |
upng-js encode(..., cnum=0) | 175.491 B | RGB (özgün renk türü korunuyor) |
Birebir aynı pikseller için 3,46×. Kayıpsızlık iddiasını varsaymak yerine doğruladık: upng-js çıktısı cnum=0 ile çözüldüğünde, girdideki RGBA arabelleğiyle bayt bayt aynı bir arabellek dönüyor. O 3,46 katı hiçbir şeyden vazgeçmeden alıyorsunuz.
İkisi de ücretsiz, ikisi de aynı şeyi vadeden iki çevrimiçi sıkıştırıcı neden karşılaştırılamayacak sonuçlar veriyor? Çünkü “tarayıcıda sıkıştır” ifadesi bambaşka iki uygulamayı anlatıyor. Biri pikselleri canvas.toBlob’a devrediyor ve ne dönerse onu size gönderiyor. Diğeri gerçek bir PNG kodlayıcı taşıyor ve renk türünü kendisi belirliyor. Girdi aynı, tarayıcı aynı, sonuçlar arasında 3,46 kat var.
3. İkinci neden: JPEG’inizin verecek bir şeyi kalmamış
Beş tur yeniden sıkıştırma ve yerinden kıpırdamayan boyut
Zaten 82 kalitesinde kaydedilmiş olan photo.jpg dosyasını alın ve her nesli bir sonrakine besleyecek şekilde 0,8 kalitesinde art arda beş kez yeniden sıkıştırın:
| Nesil | Bayt | Bir öncekine göre |
|---|---|---|
| 0 (orijinal, q82) | 47.828 | — |
| 1 | 47.152 | −%1,4 |
| 2 | 47.164 | +%0,0 |
| 3 | 47.156 | −%0,0 |
| 4 | 47.156 | %0,0 |
| 5 | 47.156 | %0,0 |
İlk geçiş size %1,4 kazandırıyor. 2. nesilden itibaren dosya boyutu ±12 baytlık bir bandın içine kilitleniyor; 4 ve 5. nesiller de boyut olarak 3. nesille birebir aynı.
Girdi bir JPEG olduğunda “sıkıştırma işe yaramıyor” tam olarak böyle görünür. Araç çalıştı. Kodlayıcı çalıştı. Geriye atılacak hiçbir şey kalmamıştı, çünkü 80 kalitesindeki niceleme tabloları, 82 kalitesinin koruduğu katsayıları kabaca zaten sıfırlıyordu. Bir katsayı bir kez gittiyse ikinci kez atılamaz.
Bunun olup bittiğini kendi makinenizde izleyebilirsiniz:
cp photo.jpg gen0.jpg
for i in 1 2 3 4 5; do
magick "gen$((i-1)).jpg" -quality 80 "gen$i.jpg"
done
stat -f%z gen0.jpg gen1.jpg gen2.jpg gen3.jpg gen4.jpg gen5.jpg
Linux’ta bunun yerine stat -c%s kullanın. Tam bayt sayıları, ImageMagick derlemenizin hangi kodlayıcıya bağlandığına göre değişir; yukarıdaki tablonun rakamı rakamına çıkmasını beklemeyin. Bakmanız gereken şekil: anlamlı tek bir düşüş, ardından düz bir çizgi.
Kalite sayısını yukarı çekmek sıkıştırma değildir
- bölümdeki
photo.jpgsatırına bir daha bakın. 82 kalitesindeki o orijinali 92 kalitesinde yeniden sıkıştırmak 58.762 bayt üretti: +%22,9.
Kalite parametresini “küçük”ten “büyük”e uzanan, istedikleri yere ayarlayabilecekleri bir kadran sanan insanları bu şaşırtıyor. O bir mutlak kalite hedefi değildir. Bir niceleme tablosu seçer; çözülmüş bir görüntüyü, kendisini üreten tablodan daha ince bir tablodan yeniden geçirmek ise mevcut bozulmaları daha hassas saklar ve üstüne bir tur daha kayıp ekler. Sonuç hem daha büyük bir dosya hem daha kötü bir görüntü.
Buradan çıkan kural: bir JPEG’i, kaydedildiği ayarın üzerindeki bir kalite değeriyle asla yeniden sıkıştırmayın. O değerin ne olduğunu bilmiyorsanız hiç sıkıştırmayın. Kaynağa geri dönün.
Nesil kaybı: göremediğiniz JPEG yeniden sıkıştırma kalite kaybı
Plato tablosunun içinde bir tuzak var. Boyut 2. nesilden sonra değişmeyi bıraktı, ama görüntü değişmeye devam etti. Her geçiş görüntüyü piksellere çözer, yeniden dönüştürür ve yeniden niceler. Bir nesilde sınırda kalmayı başaran katsayılar, bir sonrakinde sınırın öbür tarafına itilir.
Hasar, aradığınız yerde ortaya çıkmaz. Küçük resim boyutunda 5. nesille 1. nesil birbirinden ayırt edilemez. %100’e yakınlaştırın ve JPEG’in ilk elden çuvalladığı yerlere bakın: düz zeminlere dayanan keskin kenarlar, metin ve bloklaşmanın gözle görülür 8×8 karolar hâlinde belirdiği yumuşak gradyanlar. Her dağıtımda yeniden sıkıştıran bir derleme pipeline’ında bu, aylarca sessizce birikir.
Burada dosya boyutlarını ölçtük, algısal kaliteyi değil; dolayısıyla beş nesil için size bir PSNR ya da SSIM değeri aktaracak değiliz. Öyle bir ölçüm yapmadık. Boyut verisi şunu gösteriyor: 2. nesilden itibaren maliyetin tamamı kalite tarafında ve fayda sıfır.
Renk kaymaları, aynı tetikleyiciye dayanan ayrı bir arızadır. canvas hiç meta veri taşımaz, bu yüzden bir toBlob turu EXIF bloğunu ve onunla birlikte ICC profilini de düşürür. Display P3 ya da Adobe RGB etiketiyle giren bir görsel etiketsiz çıkar; görüntüleyiciler de bunu sRGB sayar. Piksel değerleri yerinden oynamadı. Onları yorumlama talimatı oynadı.
4. Üçüncü neden: PNG dosya boyutu küçülmüyor, çünkü zaten nicelenmiş
PNG’niz bir kez bir sıkıştırıcıdan geçtiyse, ikinci geçişin çalışacağı bir şey kalmaz. quantized.png satırı tam da bu: 64 renkli bir palete indirgenmiş 59.843 baytlık bir dosya, üç ayrı yoldan geçirildi:
| Yol | Sonuç | Orijinale göre |
|---|---|---|
Kayıpsız yeniden kodlama (upng cnum=0) | 61.377 | +%2,6 |
| 256 renge niceleme | 61.366 | +%2,5 |
| 64 renge niceleme | 61.366 | +%2,5 |
Her yol orijinalinden büyük çıktı. Çok değil ama büyük; buna zaten 64 rengi olan bir dosyayı 64 renge nicelemek de dahil.
PNG sıkıştırması fazlalığı atarak çalışır: tekrar eden renkler, tahmin edilebilir komşular, küçük bir palet. Önceki geçiş bunların hepsini zaten toplamıştır. Geriye kalan neredeyse sıkıştırılamazdır; o minik artış da kodlayıcının kendi ek yüküdür: biraz farklı bir palet sıralaması, tarama satırı başına farklı filtre seçimleri, azıcık daha şanssız bir deflate.
Zaten optimize edilmiş bir PNG’de “%0 tasarruf” doğru sonuçtur, arıza değil. Küçük bir artış bildirip sonra sizin orijinal dosyanızı koruyan bir araç doğru davranıyordur. Büyük dosyayı yine de elinize tutuşturan bir araç davranmıyordur.
5. PNG’de kazanç nicelemeden gelir
Kayıpsız yeniden kodlamaya karşı 256 renk ve 64 renk
Üç dosyayı üç stratejiyle ölçtük:
| Dosya | Orijinal | Kayıpsız (cnum=0) | 256 renk | 64 renk |
|---|---|---|---|---|
og-a.png | 306.302 | 175.491 (−%42,7) | 110.772 (−%63,8) | 76.230 (−%75,1) |
photo.png | 498.639 | 587.863 (+%17,9) | 109.284 (−%78,1) | 61.397 (−%87,7) |
quantized.png | 59.843 | 61.377 (+%2,6) | 61.366 (+%2,5) | 61.366 (+%2,5) |
Kayıpsız yeniden kodlama elinizdeki en zayıf araçtır. Grafikte %42,7 kazandırdı, fotoğrafta %17,9 geri aldı ve zaten nicelenmiş dosyada %2,6 kaybettirdi. Fotoğrafik içerik, yetkin bir kayıpsız PNG kodlayıcısını bile alt eder; çünkü bulunacak bir palet yoktur ve komşu pikseller birbirini iyi tahmin etmez.
Küçülmenin büyük kısmını niceleme sağlıyor ve arada yakın bir fark yok: aynı grafikte 256 renk nicelemesi %63,8 verirken kayıpsız yol %42,7’de kalıyor, 64 renkte ise %75,1. Komut satırında:
magick logo.png -colors 64 PNG8:logo-64.png
magick logo.png -colors 256 PNG8:logo-256.png
PNG8: öneki palet PNG’si yazmaya zorlar. O olmadan ImageMagick renkleri azaltıp yine de truecolor bir dosya yazabilir ve bu da faydanın çoğunu çöpe atar.
Bir palet ne zaman güvenli, ne zaman bantlaşma görürsünüz
Niceleme kayıplıdır. Her pikseli sınırlı bir paletteki en yakın girdiye eşler; dolayısıyla soru şu: içeriğinizde bunun görünür olmasına yetecek kadar farklı renk var mı?
Güvenli: simgeler, logolar, arayüz ekran görüntüleri, düz çizimler, şemalar, geniş tek renk alanları ve keskin kenarları olan her şey. Bunlarda tipik olarak en fazla birkaç yüz farklı renk bulunur; 256 girişli bir palet neredeyse bedavadır, 64 bile çoğu zaman ayakta kalır.
Riskli: fotoğraflar, yumuşak gradyanlar, yumuşak gölgeler ve yarı saydam katmanlar. Bir gradyanı 64 basamağa indirmek gözle görülür bantlar üretir; dithering ise bu bantları gürültüyle takas eder ve o gürültü dosya boyutunun bir kısmını size geri ödetir. Bir gradyanın üzerindeki kısmi saydamlık ise hepsinin en zorudur.
Saydamlığın ne kadarının hayatta kalacağı nicelemenin kendisine değil kodlayıcıya bağlı. ImageMagick’in PNG8: biçimi ikili saydamlık yazar: bir piksel ya tümüyle opaktır ya da tümüyle şeffaftır, yumuşatılmış bir kenar da sert döner. Adanmış bir PNG niceleyicisi ise tam alfa kanalını, onunla birlikte de yumuşak kenarı korur. Görselinizde gölge ya da yumuşatılmış kenarlar varsa, karar vermeden önce ikisini karşılaştırın.
Sonucu küçük resimde değil %100’de kontrol edin. Bantlaşma, küçültülmüş bir önizlemenin güvenilir biçimde gizlediği tek bozulmadır.
6. Çözüm: yeniden sıkıştırmak yerine biçim değiştirin
Biçim karar tablosu
| İçerik | Ne kullanmalı | Neden |
|---|---|---|
| Fotoğraflar | WebP ya da azami uyumluluk için JPEG | Fotoğrafların ihtiyacı olan şey kayıplı frekans kodlamasıdır |
| Ekran görüntüleri, arayüz grafikleri | Nicelenmiş PNG ya da WebP | Düz renkler, keskin kenarlar, küçük paletler |
| Simgeler ve logolar | Vektörü elinizdeyse SVG, değilse nicelenmiş PNG | Vektörlerin çözünürlük sorunu yoktur |
| Saydamlık gereken her şey | WebP ya da PNG | İkisi de tam alfa kanalı taşır |
| Animasyon | WebP | GIF yerine tek bir biçim |
| Piksel düzeyinde arşivleme | PNG, kayıpsız | Kayıpsızlığın gereklilik olduğu tek durum |
Bu, bilerek kısa tutulmuş sürüm. Modern biçimler arasındaki kodlama verimliliği ve tarayıcı desteği ayrı bir yazının konusu: WebP vs AVIF vs JPEG.
WebP aynı 83 dosyaya ne yaptı
canvas PNG yolunda %100 oranında büyüyen 83 dosyalık kümeyi bunun yerine 0,8 kalitesinde WebP’ye çevirdik: 83 dosyanın 83’ü küçüldü, medyan −%94,2. Daha önce andığımız tek dosya, aes-decrypt.png, 505.516 B’den 27.188 B’ye indi, −%94,6.
Kontrollü dosyalar da aynı yönde. og-a.png: PNG olarak 306.302, WebP q80 olarak 13.852. photo.png: PNG olarak 498.639, WebP q80 olarak 24.068. photo.jpg: JPEG olarak 47.828, WebP q80 olarak 23.862.
Bu son karşılaştırmada bir uyarı payı var: 0,8 kalitesindeki WebP kayıplıdır, yani PNG ile eşit şartlarda yarışmıyor; ayrıca mevcut bir JPEG’i WebP’ye yeniden kodlamak yine size bir nesil kaybettirir. Karşılaştırmanız gereken şey, varsayımsal kusursuz bir orijinal değil, yayına almak üzere olduğunuz dosya.
PNG’yi yine de ne zaman korumalısınız
Kayıpsızlık bazen tercih değil gerekliliktir. Tasarım pipeline’ına geri dönüp yeniden düzenlenecek varlıklar, piksel karşılaştırma testlerinde kullanılan ekran görüntüleri, tek bir kayan rengin görsel farkı bozduğu arayüz kesitleri ve niceleme bozulmalarının üst üste bineceği, sonradan bindirilecek her şey için PNG’de kalın. Bu durumlarda, içerik izin veriyorsa düzgün bir niceleyen kodlayıcı çalıştırın; izin vermiyorsa dosya boyutunu kabul edin.
Sıkıştırmayla hiç ilgisi olmayan bir başka “büyüme” türü
Görselleri data URI olarak gömüyorsanız, CSS ya da HTML’inizdeki boyut diskteki boyut değildir. Base64 her 3 baytı 4 karakter olarak kodlar, üstüne bir de padding gelir; yani metin, herhangi bir aktarım sıkıştırmasından önce, taşıdığı baytlardan aritmetik olarak +%33 büyüktür. Kusursuz optimize edilmiş bir görsel bile gömdüğünüz anda üçte bir büyür. Bu takasın ne zaman değdiğini data URI ile gömme rehberimiz anlatıyor.
7. Uygulama: tarayıcı, komut satırı, derleme pipeline’ı
Tarayıcıda
Tarayıcı tabanlı bir araç seçerken şuna bakın: PNG canvas’tan geçiyor mu? Resim sıkıştırıcımızda geçmiyor. PNG girdisi bir renk paletine nicelenir ve alfa kanalı bozulmadan gerçek bir PNG olarak geri yazılır; böylece saydamlık ve yumuşak kenarlar korunur. Kalite kaydırıcısı da PNG’nin zaten yok sayacağı bir toBlob argümanına değil, palet boyutuna karşılık gelir. Kalite 100, kayıpsız bir yeniden kodlamaya karşılık gelir. JPEG ve WebP ise canvas’tan geçer; orada kalite parametresi gerçektir ve beklediğiniz işi görür.
Bir davranış hata gibi görünebilir: sıkıştırılmış sonuç yüklediğiniz dosyadan küçük değilse, araç kendi çıktısını atar ve sizin orijinal baytlarınızı korur. Zaten optimize edilmiş bir PNG’de “%0 tasarruf” görürsünüz. Bu, 4. bölümün tasarlandığı gibi çalışmasıdır.
Her şey tarayıcınızda olup biter; hiçbir dosya sunucuya gitmez.
Komut satırında
cwebp, libwebp ile birlikte gelir ve bir biçim değişikliğinin sorununuzu çözüp çözmediğini sınamanın en hızlı yoludur:
# Kayıplı WebP, kalite 0-100
cwebp -q 80 photo.png -o photo.webp
# Kayıpsız WebP, sıkıştırma çabası 0-9
cwebp -z 9 logo.png -o logo.webp
ImageMagick 7, dönüştürme ve niceleme durumlarını kapsıyor:
# Seçtiğiniz bir kalitede PNG'den JPEG'e
magick photo.png -quality 80 photo.jpg
# 64 renkli palet PNG'sine niceleme
magick logo.png -colors 64 PNG8:logo-64.png
# EXIF ve diğer meta verileri at
magick photo.jpg -strip photo-clean.jpg
macOS’ta sips zaten kuruludur ve hiçbir bağımlılık istemez:
# JPEG'e dönüştür; formatOptions 0-100 ya da low/normal/high/best alır
sips -s format jpeg -s formatOptions 80 photo.png --out photo.jpg
# En uzun kenar 1200 px olacak şekilde yeniden boyutlandır, en boy oranı korunur
sips -Z 1200 photo.jpg --out photo-1200.jpg
# Ölçüleri geri oku
sips -g pixelWidth -g pixelHeight photo-1200.jpg
Sıkıştırmadan önce küçültün. Kodlayıcılar piksellerin üzerinde çalışır ve en ucuz piksel, var olmayan pikseldir.
Derleme pipeline’ında
Sıkıştırma otomatikleşip derlemeye girdiğinde karar, işin nerede ve hangi kitaplıkla yürüdüğüne kayar; dengeler de buna göre değişir: tarayıcı tabanlı ve Node.js tabanlı görsel sıkıştırma bu karşılaştırmayı ele alıyor. Bu yazıdan oraya taşınan tek kural: her derlemede özgün kaynak dosyadan sıkıştırın, asla bir önceki derlemenin çıktısından değil. Bir pipeline’ın, dosya boyutları gayet istikrarlı görünürken kendini nesil kaybı eğrisinden aşağı yürütmesi işte böyle olur.
8. Ölçümlerin desteklemediği beş inanç
“İki kez sıkıştırmak dosyayı küçültür.” 1. nesil %1,4 kazandırdı. 2’den 5’e kadar olan nesiller ±12 bayt içinde kaldı, bu sırada görüntü bozulmaya devam etti. İkinci geçiş katıksız maliyettir.
“PNG kayıpsızdır, dolayısıyla daha iyi biçimdir.” Kayıpsızlık bir özelliktir, erdem değil. Test fotoğrafımız PNG olarak 498.639 bayt, WebP q80 olarak 24.068 bayt. Yalnızca ekranda görüntülenecek bir fotoğrafı bit düzeyinde kusursuz saklamak hiçbir şey kazandırmaz, dosyanın da çoğuna mal olur.
“Kalite 100 güvenli seçimdir.” 82 kalitesindeki bir JPEG’i 92 kalitesinde yeniden sıkıştırmak +%22,9 ve daha kötü bir görüntü üretti. Orijinalin kalite ayarının üzerinde bu sayı “daha güvenli” anlamına gelmeyi bırakır, “daha büyük” anlamına gelmeye başlar.
“Dosya büyük, çünkü çözünürlük yüksek.” Çözünürlüğün payı var, ama aynı çözünürlükte biçimin payı daha büyük. og-a.png her iki durumda da 1200×630: canvas PNG olarak 607.481 bayt, WebP q80 olarak 13.852 bayt. Piksel sayısı birebir aynı.
“Çevrimiçi sıkıştırıcıların hepsi aynıdır.” Aynı pikseller, aynı tarayıcı, ikisi de kayıpsız: canvas’tan 607.481 bayt, upng-js’ten 175.491 bayt. Kendilerini birebir aynı biçimde tanıtan iki araç arasında 3,46 katlık bir açıklık.
9. SSS
Sıkıştırdığım görsel neden orijinalinden büyük?
Çünkü araç onu sıkıştırmak yerine yeniden kodladı. Tarayıcı canvas’ının çıktısı her zaman 32 bit RGBA PNG’dir; bu da paletleri atar ve piksel başına dört bayt saklar. 83 gerçek PNG üzerinde yaptığımız testte 83’ü de büyüdü, medyan artış +%76,6 oldu. Bunun yerine WebP ya da JPEG’e dönüştürün.
PNG’mi sıkıştırdığımda neden küçülmüyor?
PNG kayıpsızdır, dolayısıyla kalite kaydırıcısının feda edebileceği bir şey yoktur. Gerçek küçülme renk sayısını kısmaktan gelir ve dosya zaten nicelenmişse kısılacak bir şey kalmamıştır. 64 renkli test PNG’miz ikinci kez 64 renge nicelendiğinde +%2,5 olarak döndü.
Bir JPEG’i iki kez sıkıştırmak kalite kaybettirir mi?
Evet ve karşılığında neredeyse hiçbir şey almazsınız. 0,8 kalitesinde beş tur: ilk geçişte 47.828 bayt 47.152’ye indi, sonraki dördünde 12 bayt içinde kilitli kaldı. Boyut yerinde saydı, oysa her geçiş görüntüyü yeniden niceledi. Orijinallerinizi saklayın.
Dosyayı küçültmek için PNG mi JPEG mi kullanmalıyım?
Fotoğraflar için istisnasız JPEG ya da WebP. Test fotoğrafımız PNG olarak 498.639 bayt, JPEG q80 olarak 45.050 bayt ve WebP q80 olarak 24.068 bayt ölçüldü. PNG’yi, küçük bir paletin sıkıştırma işini gördüğü düz grafiklere, keskin metne ve saydamlığa saklayın.
Görselim sıkıştırmadan sonra neden bulanıklaştı?
İki ayrı neden var. Düşük kalite ayarlarındaki kayıplı kodlayıcılar kenarların ve metnin çevresinde gözle görülür bloklaşma üretir. Tekrarlanan geçişler ise dosya boyutu değişmeyi bıraktığında bile nesil kaybı ekler. Görüntü yumuşamak yerine renk kaydırdıysa, canvas turu ICC profilinizi düşürmüştür; çünkü canvas hiç meta veri taşımaz.
Bir görseli kalite kaybetmeden sıkıştırabilir miyim?
Evet, ama çok daha azını bekleyin. Kayıpsız yeniden kodlama yalnızca aynı pikselleri daha verimli yazar: grafiğimizde 306.302 bayttan 175.491 bayta indi ve çözüldüğünde bayt bayt aynı olduğu doğrulandı. Aynı yaklaşım bir fotoğrafta ters yöne gitti, +%17,9. Gözle görülür kayıp olmadan gerçek tasarruf için 80 kalitesinde WebP kullanın.
PNG’m sadece bir ekran görüntüsüyken neden bu kadar büyük?
Ekran yakalamaları tam RGBA PNG olarak, yani sıkıştırmadan önce piksel başına dört bayt olarak saklanır; Retina bir ekran da her boyutta piksel sayısını ikiye katlar. Düz içerik palet azaltmaya iyi yanıt verir: Open Graph kart grafiğimiz 256 renkte %63,8, 64 renkte %75,1 düştü.
Yeniden boyutlandırmak dosya boyutunu sıkıştırmaktan daha çok azaltır mı?
Genellikle evet ve ikisi birbirini besler. Her iki boyutu yarıya indirmek, kodlayıcı işe başlamadan önce piksellerin dörtte üçünü ortadan kaldırır; dosya boyutu da kabaca piksel sayısını izler. Önce gerçekten gösterdiğiniz ölçülere küçültün, sonra bir kez sıkıştırın. Küçük resim yuvasına bırakılan tam çözünürlüklü bir kamera dosyası her iki geçişi de israf eder.