Format gambar mana yang lebih hemat memori: PNG, JPEG, atau GIF?

70

Format gambar mana yang lebih efisien untuk menghemat memori? PNG, JPEG, atau GIF?

Tredecies Nocturne
sumber
4
Format file tidak ada hubungannya dengan tekstur atau membuang objek.
Kylotan

Jawaban:

153

"Memori" dan "efisiensi" adalah istilah yang sering disalahgunakan, jadi saya akan memberi Anda jawaban untuk empat elemen berbeda yang dapat memengaruhi kinerja gim Anda.

Saya akan terlalu menyederhanakan terlalu banyak hal untuk membuatnya singkat dan ringkas, tetapi ada banyak ketidakakuratan dalam teks di bawah ini, jadi bawa dengan sejumput garam. Namun, konsep utama harus dapat dimengerti.

Penyimpanan

Ini adalah ukuran yang dikonsumsi gambar Anda pada distribusi perangkat lunak Anda. Semakin banyak ruang yang digunakan sumber daya Anda, semakin lama unduhan (seperti dari situs web Anda). Jika Anda mendistribusikan di media fisik, seperti CD atau DVD, Anda mungkin harus melakukan beberapa optimasi serius di bagian depan ini.

Secara umum, JPEG mengkompres yang terbaik untuk foto dan gambar tanpa batas yang tajam. Namun, gambar Anda akan mengalami penurunan kualitas karena JPEG menggunakan kompresi lossy (Anda dapat mengatur tingkat / degradasi kompresi saat mengekspor gambar sebagai JPEG. Lihat dokumentasi perangkat lunak pencitraan Anda untuk informasi lebih lanjut tentang ini).

Namun, sebagus JPEG mungkin, itu tidak mendukung transparansi . Ini sangat penting jika Anda ingin memiliki gambar yang ditampilkan melalui orang lain, atau jika Anda ingin gambar dengan bentuk tidak teratur. GIF adalah pilihan yang baik, tetapi sebagian besar telah digantikan oleh PNG (hanya ada beberapa hal yang GIF mendukung bahwa PNG tidak, tetapi mereka sebagian besar tidak relevan dalam pemrograman game).

PNG mendukung transparansi (dan semi transparansi), memampatkan data tanpa penurunan kualitas (yaitu menggunakan kompresi lossless), dan memampatkan dengan cukup baik, tetapi tidak sebanyak JPG.

Masalah muncul ketika Anda membutuhkan kompresi yang baik, serta transparansi. Jika Anda tidak keberatan dengan gambar yang sedikit terdegradasi, Anda dapat menggunakan program kuantisasi PNG seperti pngquant , yang dapat Anda uji online di TinyPNG . Perlu diingat bahwa degradasi gambar yang dilakukan oleh kuantisasi sendiri berbeda dari JPEG (yang mencakup kuantisasi serta teknik agresif lainnya), jadi pastikan untuk mencoba keduanya, dengan berbagai pengaturan.

Jika Anda ingin meminimalkan ukuran distribusi secara agresif, Anda dapat memproses secara manual setiap gambar seperti ini:

if the image has transparency then
    try pngquant on the image
    if the results are not satisfactory then
        revert to the non-quantized image
    end
    store as PNG
else
    try storing it as JPG with different quality settings
    if no single setting yields an image of an acceptable quality then
        try pngquant on the image
        if the results are not satisfactory then
            revert to the non-quantized image
        end
        store as PNG
    else
        store as JPG
    end
end

Tip: tidak apa-apa untuk menyimpan beberapa gambar dalam satu format, dan yang lain dalam format lain.

Ada format khusus lainnya seperti DXT, ETC dan PVRTC. Mereka mendukung kompresi, dan juga dapat dimuat dikompresi ke dalam memori, tetapi mereka hanya didukung oleh GPU tertentu, dan sebagian besar GPU ini hanya mendukung salah satunya, jadi kecuali Anda tahu spesifikasi perangkat keras yang tepat dari perangkat keras target Anda (kasus penting adalah iPhone / iPad, yang mendukung tekstur PVRTC), Anda harus menghindari format ini.

Memori Program

Saya memasukkannya di sini, karena ini adalah yang biasa dikenal dengan "memori". Namun, jika game Anda menggunakan akselerasi grafis (dan jika Anda membuat game setelah 1998, kemungkinan besar Anda adalah), maka satu-satunya hal yang akan mengkonsumsi memori adalah deskriptor tekstur Anda (hanya beberapa byte per gambar), yang hanya dipengaruhi oleh jumlah gambar, dan bukan ukuran atau formatnya (ini memiliki beberapa peringatan, tetapi sebagian besar tidak relevan).

Jika platform Anda tidak memiliki memori video khusus, tidak dipercepat perangkat keras, atau kasus tidak umum lainnya, maka bagian selanjutnya tentang VRAM akan terjadi sepenuhnya atau sebagian dalam RAM, tetapi prinsip-prinsip utama akan sama.

Memori video

Di sinilah gambar Anda akan disimpan setelah program Anda berjalan. Secara umum, format penyimpanan Anda tidak akan membuat perbedaan di sini, karena semua gambar didekompresi sebelum memuatnya ke dalam memori video.

Sekarang, VRAM yang dikonsumsi oleh gambar Anda kira-kira akan width * height * bitdepth untuk setiap gambar yang dimuat dalam VRAM. Ada beberapa hal yang perlu diperhatikan di sini:

  1. Lebar dan tinggi penyimpanan gambar Anda di VRAM tidak akan sama dengan gambar asli Anda. Beberapa GPU hanya dapat menangani tekstur dengan ukuran dalam kekuatan 2, sehingga gambar 320x240 Anda sebenarnya dapat disimpan dalam ruang 512x256 dalam VRAM, dengan memori yang tidak digunakan terbuang secara efektif. Beberapa kali Anda bahkan tidak diizinkan memuat tekstur dengan ukuran yang bukan kekuatan 2 (seperti di GLES 1.1).

    Jadi jika Anda ingin meminimalkan penggunaan VRAM, Anda mungkin ingin mempertimbangkan untuk menghapus gambar Anda, dan mengukurnya dengan kekuatan 2, yang juga akan memiliki keuntungan lebih sedikit perubahan status render saat rendering. Lebih lanjut tentang ini nanti.

  2. Bitdepth sangat penting. Biasanya tekstur dimuat ke VRAM dalam 32-bit ARGB atau 32-bit XRGB, tetapi jika perangkat keras Anda dapat mendukung kedalaman 16-bit, dan Anda tidak keberatan memiliki bitdepth yang lebih rendah, Anda dapat setengah jumlah VRAM yang dikonsumsi oleh setiap gambar , yang mungkin sesuatu yang menarik untuk dipertimbangkan.

  3. Namun apa pun yang Anda lakukan, faktor terpenting ketika mempertimbangkan jumlah VRAM yang digunakan game Anda, adalah jumlah gambar yang Anda miliki di VRAM pada waktu tertentu. Ini adalah angka yang kemungkinan besar ingin Anda tetap serendah mungkin jika Anda ingin permainan yang berkinerja baik. Memuat dan menurunkan tekstur ke dalam VRAM itu mahal, jadi Anda tidak bisa hanya memuat setiap gambar kapan pun Anda akan menggunakannya. Anda harus menemukan keseimbangan antara preloading gambar yang kemungkinan besar akan Anda gunakan, dan keluarkan ketika Anda yakin Anda tidak akan menggunakannya lagi. Melakukan ini dengan benar bukanlah hal yang sepele, dan Anda harus memikirkan strategi Anda sendiri untuk gim khusus Anda.

Kecepatan eksekusi

Meskipun bukan "memori", ini sangat terkait dengan kinerja dalam game. Menggambar gambar itu mahal, dan Anda ingin memastikan rendering Anda berjalan secepat mungkin. Tentu saja, di sini, format tidak masalah, tetapi hal-hal lain berlaku:

  1. Ukuran gambar (sebenarnya, itu akan menjadi "ukuran sampel"): semakin besar wilayah gambar yang akan Anda gambar, semakin banyak waktu yang dibutuhkan untuk menggambarnya. Rendering gambar besar di bagian kecil layar tidak terlalu efektif, sehingga ada teknik yang disebut mipmapping , yang terdiri dari perdagangan VRAM untuk kecepatan rendering, dengan menyimpan gambar Anda beberapa kali di beberapa resolusi dan menggunakan yang terkecil yang dapat memberikan Anda kualitas yang diperlukan pada waktu tertentu. Pemetaan dapat dilakukan ketika gambar dimuat, yang akan berdampak pada kecepatan pemuatan dan penggunaan VRAM, atau pada preprocessing (dengan secara manual menyimpan versi berbeda dari gambar yang sama, atau menggunakan format yang mendukung pemetaan asli seperti DDS), yang akan berdampak pada penyimpanan dan penggunaan VRAM, tetapi akan berdampak kecil pada kecepatan pemuatan.

  2. Status render berubah. Anda kemungkinan besar ingin menggambar beberapa gambar berbeda di layar secara bersamaan. Namun, GPU hanya dapat menggunakan gambar sumber tunggal pada waktu tertentu (ini tidak benar, tapi tolong tahan dengan saya di sini). Gambar yang saat ini digunakan untuk rendering adalah salah satu dari banyak negara render , dan harganya mahal. Jadi jika Anda akan menggunakan gambar yang sama beberapa kali (ingat ketika saya menyebutkan atlas tekstur ?), Anda akan melihat peningkatan kinerja yang sangat besar jika Anda menggunakan kembali gambar sebanyak yang Anda bisa sebelum Anda mengubah status render dan mulai menggunakan gambar yang berbeda (ada negara render lain yang terpisah dari ini, dan menyesuaikan urutan di mana Anda menggambar barang-barang Anda untuk meminimalkan perubahan keadaan render adalah aktivitas yang sangat umum ketika meningkatkan kinerja permainan)

Namun , pengoptimalan penggunaan gambar adalah topik yang sangat kompleks, dan apa yang saya tulis di sini adalah gambaran yang sangat luas dan disederhanakan dari beberapa faktor yang harus Anda pertimbangkan saat menulis gim, jadi saya pikir itu yang terbaik jika Anda membuatnya sederhana, dan hanya mengoptimalkan setiap kali Anda benar-benar perlu melakukannya. Sebagian besar waktu, pengoptimalan prematur tidak perlu (dan kadang-kadang bahkan merugikan), jadi tenang saja.

Piyama Panda
sumber
25
+1. Ini adalah jawaban yang sangat komprehensif yang mencakup banyak alasan. Saya tidak yakin bahwa ukuran deskriptor tekstur membutuhkan ruang yang cukup banyak, dan penyebut DXT / ETC / PVRTC harus benar-benar mencakup bahwa masing-masing hanya berfungsi pada beberapa platform - mereka tidak terbuka lintas-platform standar yang dapat digunakan di mana-mana, seperti JPEG, PNG, dan GIF. Namun secara keseluruhan, sangat terkesan. Ini jauh lebih dari sekadar "anotasi minor" di atas jawaban saya! : D
Trevor Powell
9
@ Pamanda Pajama: Mungkin tidak, tapi jawaban yang mengejutkan lebih baik dari pertanyaan ini.
Marcks Thomas
1
+1, dan lebih banyak lagi jika saya bisa. Ini adalah jawaban yang luar biasa, dan harus menjadi acuan standar untuk setiap pertanyaan tentang "efisiensi memori" karena sangat efektif menghilangkan mitos umum bahwa menggunakan lebih sedikit memori selalu merupakan pendekatan terbaik, dan bukan hanya untuk gambar. Satu hal yang saya sarankan tambahkan adalah bahwa dalam kasus non-akselerasi, jika ada dekompresi saat dibutuhkan diperlukan saat menggambar itu bisa berarti overhead kinerja yang tidak dapat diterima.
Maximus Minimus
2
Saya ingin menyarankan PNGGauntlet . Ini dapat melakukan optimasi lossless besar-besaran untuk ukuran file PNG, yang dapat bertambah, terutama ketika Anda memiliki banyak sprite. Sayangnya hanya Windows, tetapi alternatif terdaftar di beranda untuk OS lain.
orlp
1
@DavidDimalanta Saya tidak punya pengalaman dengan libgdx, tapi seperti yang saya lihat dari dokumentasi setEnforcePotImages, itu menonaktifkan penegakan kekuatan 2 ukuran tekstur untuk OpenGLES 1.0. Ini bukan ide yang baik, karena tidak semua perangkat keras mendukung tekstur non-power-of-2. OpenGLES 2.0 membutuhkan dukungan untuk tekstur non-power-of-2, jadi jika Anda menargetkan 2.0, Anda dapat menggunakan tekstur dari berbagai ukuran. Untuk informasi lebih lanjut lihat dokumentasi libgdx.
Panda Pajama
26

Setelah gambar dimuat dari disk dan diformat untuk rendering, itu akan menggunakan jumlah memori yang sama terlepas dari apakah gambar itu disimpan ke disk menggunakan PNG, JPEG, atau GIF.

Aturan umum: JPEG adalah format lossy, dan akan menurunkan kualitas gambar untuk membuat gambar lebih kecil pada disk. PNG, di sisi lain, adalah format gambar lossless, dan biasanya akan menghasilkan ukuran file yang lebih besar pada disk. GIF juga secara teknis merupakan format lossless, tetapi hanya mendukung maksimum 256 warna per gambar, sehingga gambar berwarna tinggi akan sering mengalami kehilangan kualitas yang besar jika disimpan sebagai GIF.

Itu hanya untuk representasi on-disk mereka. Dalam memori, keduanya akan berkembang ke format tekstur yang sama, menggunakan jumlah memori yang sama, terlepas dari apakah Anda menyimpannya ke disk sebagai PNG, atau sebagai JPEG, atau sebagai GIF.

Trevor Powell
sumber
Jadi bukankah ekstensi file yang memvariasikan ukuran memori tetapi ukuran file?
Tredecies Nocturne
Tidak juga. Ukuran dalam memori didasarkan pada dimensi gambar dan bitdepth. Kompresi pada file gambar dihapus ketika gambar dimuat ke dalam memori untuk ditarik ke layar. (Karena GPU tidak dapat membuat PNG atau JPEG, dll. Gambar diperluas menjadi piksel umum sehingga GPU dapat menghadapinya.)
Trevor Powell
2
Ini tidak 100% benar. Sebagian besar GPU modern (termasuk yang tertanam) mendukung pemuatan dan penyimpanan tekstur terkompresi dalam memori grafis, dengan format seperti DXT, ETC dan PVRTC menjadi yang paling umum di dunia tertanam. Tentu saja, Anda harus menyimpan tekstur Anda dalam format ini di tempat pertama, bukan PNG / JPG / GIF.
Piyama Panda
6
Pertanyaannya adalah pilihan eksplisit antara PNG / JPG / GIF, tidak ada yang didukung secara native pada GPU apa pun yang saya ketahui. Penanya asli mengalami cukup banyak masalah dengan perbedaan antara ukuran file pada disk dan ruang yang digunakan dalam RAM yang saya rasa menambahkan lebih banyak format file hanya akan membingungkan masalah mendasar. Jangan ragu untuk memberikan jawaban Anda sendiri.
Trevor Powell
2
Komentar saya hanyalah anotasi. Jika saya memberikan jawaban, kemungkinan besar saya akan menulis sama seperti yang Anda lakukan, ditambah komentar saya sebagai pernyataan penutup akhir. Saya tidak punya apa-apa untuk ditambahkan, jadi saya akan menghindari pengulangan dengan memberikan jawaban saya sendiri.
Piyama Panda
3

Tergantung.

Jpeg paling efisien untuk foto. Ini bukan lossless, tetapi artefak yang diperkenalkan oleh kompresi paling tidak terlihat dalam kasus penggunaan ini.

PNG adalah lossless dan paling efisien untuk pixel-art dengan garis-garis tajam dan beberapa warna. Ini juga mendukung transparansi alpha.

GIF tidak bisa melakukan apa pun PNG tidak bisa berbuat lebih baik, kecuali kemampuannya untuk menyimpan animasi. Tetapi ini hanya relevan dalam konteks aplikasi web. Dalam pengembangan game, Anda biasanya membuat animasi dengan menggunakan spritesheet.

Perhatikan bahwa ketika Anda menggunakan mesin grafis seperti Libgdx, itu kemungkinan besar akan mengompres gambar setelah memuatnya dan kemudian menyimpannya dalam memori sebagai nilai-nilai RGBA yang tidak terkompresi. Jadi format gambar hanya penting untuk kecepatan memuat dan memiliki ruang drive (atau penggunaan bandwidth saat Anda mengirimnya melalui internet).

Philipp
sumber
2

Saya tidak tahu banyak tentang libgdx, tetapi tentang format gambar dan grafik:

JPEG sangat bagus dalam hal foto dunia nyata. Mereka merugi tetapi Anda tidak akan melihat artefak pada foto kecuali jika Anda mengambil gambar tepi tajam dengan ruang berwarna polos, seperti misalnya teks atau komik tertulis. Gunakan mereka untuk grafik latar belakang yang besar.

GIF sudah usang, ia hanya dapat menyimpan warna yang dipalpasi (hingga 8 bit per piksel) dengan satu warna khusus untuk transparansi lengkap. Ini memungkinkan animasi kecil berdasarkan bingkai. Pernah ada paten pada algoritma pengemasannya sehingga tidak bisa digunakan di mana-mana secara legal. Karena paten itu, PNG dikembangkan.

PNG kurang lebih merupakan bitmap zip yang dapat menyimpan RGB + alpha (hingga 32bit) dan format piksel lainnya. Ini adalah khusus untuk membuka ritsleting cepat dari bagian-bagian kecil dari gambar itu, yang nyaman untuk perangkat yang sangat kecil dan lambat (seperti ponsel 10 tahun), tetapi perpustakaan saat ini hanya membongkar mereka ke bitmap ketika dimuat.

PNG lebih baik daripada GIF dalam ukuran dan kecepatan serta fitur, tetapi jika Anda ingin menyimpan bitmap secara efisien, saya sarankan: .PNM.BZ2 ([sunting] Karena metode pengemasan yang berbeda, .PNM.BZ2 tidak selalu lebih efisien dari .PNG. [/ edit])

PNM / PBM / PGM / PAM adalah format bitmap biasa dengan header KISS dalam teks biasa. Menggunakan gzip pada mereka akan menghasilkan ukuran file yang mirip dengan PNG, jadi bzip2 adalah solusi yang lebih baik untuk itu. Jika Anda akan menggunakan bitmap secara internal dalam program Anda, Anda mungkin ingin menggunakan bitmap bzip2 terkompresi dalam wadah .tar atau .zip. Jika Anda tidak memiliki bzip2, menggunakan PNM dalam wadah zip (zip dengan kompresi maksimum) mungkin mirip dengan menggunakan PNG. - Jadi, menyimpan PNG dalam file ZIP mungkin hanya memiliki manfaat kecil atau tidak sama sekali - kemungkinan besar hanya akan menambah waktu untuk memuat gambar.

Selain itu, itu adalah pilihan yang baik untuk menyimpan beberapa sprite / gambar kecil dalam satu bitmap, terutama ketika Anda membutuhkan semuanya dalam situasi yang sama.

comonad
sumber
Apakah file PNM tersedia dan dapat dibaca oleh semua OS smartphone dan OS komputer desktop?
David Dimalanta
1
@ David Dimalanta: Saya tidak tahu di mana itu didukung dan di mana tidak. Jika Anda ingin memprogram dengan PNM, maka Anda jarang ingin menggunakan pustaka apa pun, karena format itu terlalu mudah untuk memilih API apa pun. Karena itu, dapat dibaca dan ditulis dengan semua bahasa pemrograman yang ada yang mendukung membaca / menulis file biner. Tentu saja Anda bisa menggunakan Netpbm di OS apa pun, tidak hanya Unix. Di sisi lain, saya tidak tahu perpustakaan gambar umum mana yang tidak mendukung ini. Ini bukan format terkompresi, jadi jarang digunakan untuk menyimpan gambar pada disk. lihat en.wikipedia.org/wiki/Netpbm_format
comonad
1

Karena format penyimpanan, JPEG mungkin merupakan pilihan terbaik untuk beberapa tekstur seperti rumput atau dinding, di mana hilangnya informasi mungkin tidak terdeteksi. Diikuti oleh PNG ketika Anda membutuhkan transparansi atau ketika Anda tidak dapat membayar dengan kehilangan informasi, misalnya sprite dalam game 2D (pemain, musuh, peti harta karun), Anda mungkin ingin menggunakan PNG untuk gambar itu.

Ketika berbicara tentang biaya memori, format yang digunakan untuk menyimpan grafik game dalam sistem file tidak relevan sama sekali. Baik jika Anda menyimpan penyangga piksel dalam VRAM, atau RAM (peranti lunak peranti lunak), Anda mungkin menyimpan penyimpannya tanpa kompresi, karena gim mendukung pembacaan cepat piksel dan memori yang digunakan oleh setiap penyangga piksel.

Memiliki data terkompresi yang disimpan dalam memori tidak masuk akal kecuali Anda mempertahankan beberapa jenis cache untuk menyimpan membaca disk, tetapi Anda mungkin harus membaca dari cache itu ke keadaan tidak terkompresi untuk gambar yang digunakan pada waktu tertentu dalam gim Anda.

Data gambar yang dikompresi memiliki lebih banyak akal jika decoding perangkat keras yang cepat dimungkinkan. Setidaknya untuk pemetaan normal, saya ingat ini http://en.wikipedia.org/wiki/3Dc . Dengan itu Anda dapat menyimpan beberapa VRAM. Saya belum mengetahui contoh lain dari decoding perangkat keras.

Dalam resume: apa pun format yang digunakan untuk gim Anda untuk menyimpan grafik dalam penyimpanan yang persisten, Anda harus memecahkan kode itu dan mempertahankan versi yang tidak terkompresi dalam memori dinamis, memori video, atau keduanya, agar dapat dengan cepat merendernya saat diperlukan.

Akhirnya: Saya seorang pria desktop. Ketika saya mengatakan "memori" saya selalu mengacu pada memori dinamis. Ketika saya mengatakan "disk", "sistem file" atau "penyimpanan persisten", saya selalu merujuk pada apa pun yang digunakan perangkat Anda sebagai penyimpanan persisten, biasanya saya pikir dalam hard disk. Ketika Anda mengatakan "efisiensi memori" saya mengambilnya untuk "memori dinamis" bukan "penyimpanan persisten". Akhir-akhir ini, saya melihat banyak orang menggunakan kata "memori" untuk merujuk ke "penyimpanan persisten" (mungkin itu terminologi perangkat seluler?).

Hatoru Hansou
sumber
Apakah mungkin juga bahwa itu bukan JPEG atau PNG yang memengaruhi memori tetapi ukuran file?
Tredecies Nocturne
Iya. Anda akan memilih salah satu format yang dibahas berpikir dalam menghemat ruang disk atau bandwidth. Saat memuat gambar ke dalam gim, setiap perpustakaan / mesin yang saya tahu akan mendekodekannya ke buffer piksel yang tidak terkompresi (pikirkan buffer piksel sebagai array nilai RGB atau RGBA, di mana setiap saluran biasanya menempati 1 Byte dalam RAM / VRAM jika menggunakan 32 bit per piksel, itulah yang mungkin dilakukan semua orang).
Hatoru Hansou