Serinin dördüncü yazısını bekleyen işlerle bitirmiştik. Listenin ilk maddesi WebP dönüşümüydü: yeni yazıların görselleri 15 Ekim’den beri WebP biçiminde yükleniyordu, ama Ekim’in ilk yedi yazısı hâlâ JPG kullanıyordu. 26 Ekim’de bu işi Claude ile birlikte bitirdik. Dönüştürmeden önce ölçtük ve ölçümler birkaç beklentimizi bozdu. Kaynak PNG dosyaları JPG’lerle neredeyse aynı boyuttaydı. Kayıpsız WebP, kayıplı JPG’den küçük çıktı. Okurun gerçekte gördüğü kazanç ise dosyanın kendisindeki kazançtan epey azdı.
Kapsam: Neden Yalnızca Ekim?
İşe 12 Ekim’de başlamıştık. Önce medya kütüphanesinin tamamını ölçmek istedik: 557 dosya, 154’ü zaten WebP. Her dosyanın boyutunu öğrenmek için sunucuya dosya başına bir istek (HTTP HEAD) gönderdik. Bu ölçüm uzun sürdü, sunucu art arda gelen isteklerle yavaşladı ve işi durdurduk.
Sonra bir karar verdik: eski görsellere dokunmayacaktık. Dönüşüm yalnızca Ekim 2026 görsellerini ve sonraki yazıları kapsayacaktı. Bunu bilerek yaptık, çünkü asıl kazanç başka yerdeydi. Nisan–Eylül arasında yüklenen 33 PNG görselin ortalaması 2 MB, Ekim JPG’lerinin ortalaması ise 130 KB. Ama eski yazılar sosyal medyada ve arama motorlarında çoktan paylaşılmıştı. Yüzlerce dosyayı değiştirmenin riski, bu aşamada kazancından büyük görünüyordu.
Bu kez ölçümü farklı yaptık. WordPress, her medya dosyasının boyutunu ve otomatik ürettiği küçük kopyaların boyutlarını REST API’de zaten saklıyor (media_details). On görselin bütün bilgisini tek bir istekle aldık, sunucuya dosya başına istek atmadık.
Proje bilgisi Yazarlar: Ahmet Aksoy & Claude · Tarih: 26.10.2026 Ortam: Python 3.12.3, Pillow 10.2.0, Ubuntu 24.04 · WordPress 7.1.3 (REST API + uygulama şifresi) Değiştirilen: 7 yazının öne çıkan görseli · Örnek kod: proje 48
İlk Sürpriz: PNG Neredeyse JPG Kadar
Bizim yayın hattımızda öne çıkan görseller Python (Pillow) ile çiziliyor. Önce kayıpsız bir PNG kaydediliyor, siteye bunun JPG kopyası yükleniyor. Yani her JPG’nin elimizde kaynak bir PNG’si vardı. Fotoğraflarda PNG, JPG’nin birkaç katı büyüklükte olur. Bizim görsellerimizde durum farklıydı:
image original JPG WebP q85 WebP q75 lossless
claude-otomasyon-readme-bakimi.png 125406 137019 34.9dB 53334 35.0dB 40126 34.4dB 92716
claude-otomasyon-yayin-hatti.png 135912 131542 35.6dB 48924 35.6dB 36556 34.9dB 100182
dogru-gorunen-kod-yanlis-sonuc.png 133840 136922 34.5dB 52728 34.6dB 39654 34.0dB 97554
eylul-2026-yapay-zeka.png 160839 118599 36.2dB 48280 36.3dB 36270 35.3dB 109242
python-315-yenilikler.png 143438 134572 35.9dB 50318 35.8dB 37260 35.1dB 102720
python-dataclasses.png 140705 130739 34.6dB 50940 34.6dB 38412 34.1dB 100542
python-dekoratorler.png 149146 121580 35.9dB 45878 35.9dB 33948 35.2dB 105990
total JPG (or original): 910973 bytes, WebP q85: 350402 bytes (38%), lossless: 708946 bytes (78%)
İki görselde PNG, JPG’den bile küçük. Nedeni görsellerin türü: düz renk alanları, keskin kenarlı yazılar, birkaç renk. PNG bu tür görüntüleri çok iyi sıkıştırır. JPG ise fotoğraflar için tasarlanmıştır ve keskin kenarlarda hem kalite hem boyut kaybeder.
Kaliteyi Sayıyla Ölçmek
“WebP aynı kalitede daha küçük” demek kolay, ama “aynı kalite” neye göre? Tablodaki dB sütunları bunun için. Her dosyayı kaynak PNG ile piksel piksel karşılaştırdık ve farkı PSNR (tepe sinyal-gürültü oranı) ile ölçtük. PSNR desibel cinsinden verilir: değer ne kadar yüksekse görüntü kaynağa o kadar yakındır, kayıpsız bir kopyada değer sonsuzdur.
Sonuç açık: Ekim JPG’leri kaynağa ortalama 35.4 dB uzaklıkta. Aynı PNG’den quality=85 ile üretilen WebP de 35.4 dB. Yani aynı kalite, ama dosya boyutunun %38’i. Yedi görsel toplamda 911 KB’tan 350 KB’a iniyor. Yeni yazılarda zaten kullandığımız ayar da quality=85, method=6.
Bir yan bulgu: JPG ve WebP’nin “kalite” ayarları aynı ölçek değil. JPG’de 90 ile WebP’de 85 aynı sonucu vermez. Proje 48’deki demo bunu fotoğraf benzeri bir görüntüyle gösteriyor: orada JPG (kalite 90) 49.5 dB, WebP (kalite 85) 42.8 dB çıkıyor. Bu yüzden iki biçimi “kalite ayarı” ile değil, ölçülen sonuçla karşılaştırmak gerekiyor.
Kayıpsız WebP Ne Zaman Kazandırır?
Tablonun son sütunu ikinci sürprizdi. Kayıpsız WebP, yani kaynakla piksel piksel aynı olan kopya, kayıplı JPG’den ortalama %22 küçük (709 KB’a karşı 911 KB). Bu, aklımıza gelen ilk soruyu da cevapladı: görsellerimizi neden JPG olarak yüklüyorduk?
Ama bu sonucu genellemek yanlış olurdu. Proje 48’in demosunda aynı ölçümü iki yapay görüntüyle yaptık:
image original JPG WebP q85 WebP q75 lossless
demo: flat graphic 13059 42850 37.7dB 8556 37.6dB 7242 37.3dB 1822
demo: photo-like 494541 154146 49.5dB 54706 42.8dB 30080 40.7dB 337336
Düz renkli grafikte kayıpsız WebP 1.8 KB, JPG 42.8 KB. Fotoğraf benzeri görüntüde ise kayıpsız WebP 337 KB ile JPG’nin iki katından büyük. Kayıpsız WebP yalnızca grafiklerde kazandırıyor. Biz siteye kayıplı WebP (q85) yüklemeyi seçtik. Kaynağa en yakın sonucu kayıpsız WebP veriyordu, ama dosya boyutu q85’in iki katıydı. Gözle görülür bir fark yokken bu boyutu taşımanın anlamı yoktu.
Kaynaktan Dönüştürmek
Elimizde PNG kaynaklar olmasaydı yayındaki JPG’leri WebP’ye çevirebilirdik. Bunu da ölçtük:
| Kaynak | WebP q85 toplam | Ortalama PSNR |
|---|---|---|
| PNG → WebP | 350 KB | 35.4 dB |
| JPG → WebP | 359 KB | 33.8 dB |
JPG’den yapılan dönüşüm hem %2.6 daha büyük hem de 1.6 dB daha kötü. Nedeni şu: kayıplı bir biçimden başka bir kayıplı biçime geçerken iki kayıp üst üste biniyor. Üstelik ikinci sıkıştırıcı, birincinin bıraktığı bozulmaları da korunması gereken ayrıntı sanıp saklamaya çalışıyor. Kaynak dosyalarınızı saklamanın bir nedeni daha.
Geçiş: Önce Yedek, Sonra Kuru Çalıştırma
Değişikliği yapan betik (gecis.py) yayın hattımızdaki wp_yukle.py aracının istek fonksiyonunu kullanıyor. Her yazı için şunları yapıyor:
- Yazının şu anki öne çıkan görselini ve o görselin bilgilerini (başlık, alt metin, altyazı, açıklama) okuyor.
- Yeni WebP dosyasını medya kütüphanesine yüklüyor ve eski görselin bilgilerini olduğu gibi ona kopyalıyor.
- Yazının
featured_mediaalanını yeni görselle değiştiriyor ve yazının durumunun ve yayın tarihinin değişmediğini kontrol ediyor.
Betik varsayılan olarak hiçbir şeyi değiştirmiyor, yalnızca ne yapacağını yazıyor (kuru çalıştırma). Değişiklik ancak --uygula ile yapılıyor ve o zaman da önce bütün yazı ve görsel bilgileri bir yedek dosyasına yazılıyor. İstekler arasında üç saniye bekleniyor: 12 Ekim’deki yavaşlamayı tekrarlamak istemedik.
Eski JPG dosyalarını silmedik. Bu yazılar sosyal medyada JPG önizlemeleriyle paylaşıldı ve platformlar o görselleri kendi sunucularında saklıyor olsa da, eski bağlantıların bir yerde hâlâ JPG adresini gösterme ihtimali var. Medya kütüphanesinde yedi fazla dosya, kırık bir önizlemeden daha ucuz.
Kuru çalıştırma bir şeyi de doğruladı. 19 Ekim yazısının görseli 12 Ekim’de düzeltilip yeniden yüklenmişti ve WordPress yeni dosyaya -1 eki koymuştu (dogru-gorunen-kod-yanlis-sonuc-1.jpg). Betik bu yazıyı doğru kaynak PNG ile eşleştirdi.
Doğrulama: Okur ve Sosyal Medya Ne Görüyor?
Değişiklikten sonra yedi yazının sayfasını tek tek indirdik ve üç şeye baktık: sayfadaki görsel, bağlantı önizlemesi için kullanılan og:image etiketi ve sunucunun görseli hangi içerik türüyle gönderdiği. Yedisinde de üçü WebP’yi gösteriyordu (image/webp).
Bu kontrolde fark ettiğimiz bir şey: sayfalarımızda og:image etiketi iki kez yer alıyor, yani iki ayrı bileşen önizleme etiketi üretiyor. X (Twitter) için kullanılan twitter:image etiketlerinden biri de görsel adresinin sonuna ?w=640 ekliyor. Hepsi yeni görseli gösteriyordu, çünkü hepsi aynı featured_media alanından besleniyor. Görsel adresini etiketlere elle yazan bir düzenleme ise bunlardan birini kolayca unuturdu.
WebP ile ilgili en çok endişe ettiğimiz konu bağlantı önizlemeleriydi: LinkedIn’in WebP önizlemeyi desteklemediği zaman zaman söyleniyor. 26 Ekim yazısının görseli baştan WebP’ydi ve o gün LinkedIn, X ve Facebook’ta paylaşıldı. Üç platformda da önizleme görseli göründü. Bu tek bir gözlem, ama bizim için endişeyi gidermeye yetti.
Bir yan etki: öne çıkan görseli değiştirmek, yazının “son değiştirilme” tarihini de güncelliyor. Bizim temamızda bu tarih okura gösterilmiyor, yalnızca sayfanın article:modified_time etiketinde görünüyor.
Okurun Gördüğü Kazanç: %38 Değil
Yazının başında okurun gördüğü kazancın dosyanın kendisindeki kazançtan az olduğunu söylemiştik. WordPress her yüklenen görselden dört küçük kopya üretiyor ve sayfalar çoğu zaman bu kopyaları kullanıyor. Ana sayfadaki yazı kartları 300 ve 768 piksel genişliğindeki kopyaları gösteriyor. Tam boyutlu görsel yalnızca yazının kendi sayfasında yükleniyor. Yedi görselin bütün kopyalarını karşılaştırdık:
| Kopya | Genişlik | JPG toplam | WebP toplam | Oran |
|---|---|---|---|---|
| thumbnail | 150 | 43.7 KB | 32.5 KB | %74 |
| medium | 300 | 88.1 KB | 61.7 KB | %70 |
| medium_large | 768 | 358.0 KB | 206.8 KB | %58 |
| large | 1024 | 533.4 KB | 286.6 KB | %54 |
| full | 1200 | 911.0 KB | 350.4 KB | %38 |
Küçük kopyalarda kazanç azalıyor. 150 piksellik bir küçük resim zaten birkaç kilobayt, iki biçim arasındaki fark da o kadar küçük. Ayrıca bu kopyaları WordPress kendi ayarlarıyla üretiyor, bizim quality=85 ayarımız yalnızca tam boyutlu dosyaya uygulanıyor. Yazı sayfasını masaüstünde açan okur %62 daha az görsel verisi indiriyor (telefonda tarayıcı daha küçük bir kopya seçebiliyor). Ana sayfada gezinen okur için kazanç %30–42 arasında.
Çıkardığımız Dersler
- Ölçmenin de bir maliyeti var. 557 dosyayı tek tek sorgulamak sunucuyu yavaşlattı. Aynı bilgi REST API’de zaten vardı ve tek bir istekle alınabiliyordu.
- Kaliteyi ayar değeriyle değil, ölçerek karşılaştırın. JPG 90 ile WebP 85 aynı şey değil. PSNR gibi basit bir ölçü bile iki biçimi adil biçimde karşılaştırmaya yetiyor.
- Görselin türü sonucu belirliyor. Grafikte kayıpsız WebP JPG’den küçük, fotoğrafta iki katı. Başkasının ölçümünü kendi görsellerinize uygulamadan önce kendi görsellerinizi ölçün.
- Kaynak dosyaları saklayın. JPG’den dönüştürmek hem daha büyük hem daha kötü sonuç veriyor.
- Geri dönüş yolunu açık bırakın. Eski görseller silinmedi ve yedek dosyası her yazının eski görsel numarasını tutuyor. Geri dönmek gerekirse yedi yazının
featured_mediaalanını eski değerine çevirmek yetiyor. - Sonucu okurun gözünden kontrol edin. Medya kütüphanesindeki %38, ana sayfadaki okur için %30–42 demek.
Sırada Ne Var?
- Nisan–Eylül görselleri: 2 MB ortalamalı 33 PNG hâlâ duruyor. Bu yazıdaki betik onlara da uygulanabilir. Paylaşılmış önizlemeleri bozmadan nasıl yapılacağına henüz karar vermedik.
- Kod düzeltmeleri: #3’te bulunan kod hatalarının bir kısmını “Tamamlandı” Diyen Kod ve Regex Neyi Kabul Ediyor? yazılarında ele aldık. Sıralama ve veri yapısı projelerindeki hatalar bekliyor.
- Bekçinin günlüğü: Kuyruk bekçisi çalışmaya devam ediyor.
Kaynaklar
- WebP sıkıştırma çalışması — Google
- Pillow: WebP kaydetme seçenekleri
- WordPress REST API: Media
- Claude ile Otomasyon #2: Markdown Dosyasından Zamanlanmış Yazıya
- Claude ile Otomasyon #4: Yayın Kuyruğuna Bekçi Koyduk, Bekçi de Bir Kez Sessizce Çöktü
Ahmet Aksoy & Claude
Not: Bu yazıdaki ölçüm tablolarını üreten aracın kaynak kodunu https://github.com/ahmetax/practical-python-examples deposundaki v312/48_webp_compare klasöründe bulabilirsiniz. python3 main.py <klasör> komutu kendi görsellerinizle aynı tabloyu çıkarır, python3 main.py --demo ise yazıdaki demo tablosunu üretir.



