Który format obrazu jest bardziej wydajny pod względem pamięci: PNG, JPEG lub GIF?

70

Który format obrazu jest bardziej wydajny w celu oszczędzania pamięci? PNG, JPEG lub GIF?

Tredecies Nocturne
źródło
4
Format pliku nie ma nic wspólnego z teksturami ani usuwaniem obiektów.
Kylotan

Odpowiedzi:

153

„Pamięć” i „wydajność” są często niewłaściwie używanymi terminami, więc dam ci odpowiedź na cztery różne elementy, które mogą wpłynąć na wydajność twojej gry.

Będę nadmiernie upraszczał zbyt wiele rzeczy, aby było krótkie i zwięzłe, ale w tekście poniżej jest mnóstwo niedokładności, więc weź to ze szczyptą soli. Jednak główne pojęcia powinny być zrozumiałe.

Przechowywanie

Jest to rozmiar, jaki zużywają Twoje obrazy w dystrybucji oprogramowania. Im więcej miejsca zajmują zasoby, tym dłużej trwa pobieranie (tak jak w witrynie). Jeśli dystrybuujesz na nośnikach fizycznych, takich jak dyski CD lub DVD, prawdopodobnie będziesz musiał dokonać poważnych optymalizacji w tym zakresie.

Ogólnie JPEG kompresuje najlepiej dla zdjęć i obrazów bez ostrych ramek. Jednak zdjęcia będą miały obniżoną jakość, ponieważ JPEG stosuje kompresję stratną (można wyregulować poziom kompresji / degradację podczas eksportowania obrazów jako JPEG. Więcej informacji na ten temat można znaleźć w dokumentacji oprogramowania do przetwarzania obrazu).

Jednak tak dobry, jak JPEG, nie obsługuje przezroczystości . Jest to bardzo ważne, jeśli chcesz mieć obrazy, które pokazują inne lub jeśli chcesz obrazy o nieregularnych kształtach. GIF to dobry wybór, ale został w dużej mierze zastąpiony przez PNG (istnieje tylko kilka rzeczy, które GIF obsługuje, ale PNG nie są one w dużej mierze nieistotne w programowaniu gier).

PNG obsługuje przezroczystość (i półprzezroczystość), kompresuje dane bez pogorszenia jakości (tj. Używa kompresji bezstratnej) i kompresuje dość dobrze, ale nie tak bardzo jak JPG.

Problem pojawia się, gdy potrzebujesz dobrej kompresji, a także przejrzystości. Jeśli nie masz nic przeciwko nieznacznie zdegradowanym obrazom, możesz użyć programów do kwantyzacji PNG, takich jak pngquant , które możesz przetestować online w TinyPNG . Należy pamiętać, że degradacja obrazu przeprowadzana przez samą kwantyzację jest inna niż w przypadku formatu JPEG (który obejmuje kwantyzację, a także inne agresywne techniki), więc wypróbuj oba sposoby, korzystając z szerokiej gamy ustawień.

Jeśli chcesz agresywnie zminimalizować rozmiar swojej dystrybucji, możesz ręcznie przetworzyć każdy obraz w ten sposób:

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

Wskazówka: można przechowywać niektóre obrazy w jednym formacie, a inne w innym formacie.

Istnieją inne specjalistyczne formaty, takie jak DXT, ETC i PVRTC. Obsługują kompresję, a także mogą być ładowane skompresowane do pamięci, ale są obsługiwane tylko przez określone procesory graficzne, a większość z tych GPU obsługuje tylko jeden z nich, więc jeśli nie znasz dokładnej specyfikacji sprzętu docelowego (godnym uwagi przypadkiem jest iPhone / iPad, który obsługuje tekstury PVRTC), należy unikać tych formatów.

Pamięć programu

Włączyłem go tutaj, ponieważ to jest to, co powszechnie znane jest pod nazwą „pamięć”. Jeśli jednak gra korzysta z akceleracji grafiki (a jeśli tworzysz ją po 1998 r., Najprawdopodobniej tak jest), jedyną rzeczą, która zużyje pamięć, są deskryptory tekstur (zaledwie kilka bajtów na obraz), które są tylko zależy od ilości zdjęć, a nie od ich wielkości lub formatu (ma to kilka zastrzeżeń, ale w większości są nieistotne).

Jeśli Twoja platforma nie ma dedykowanej pamięci wideo, nie jest przyspieszana sprzętowo lub w innych nietypowych przypadkach, następna sekcja dotycząca pamięci VRAM wydarzy się całkowicie lub częściowo w pamięci RAM, ale główne zasady będą takie same.

Pamięć wideo

Tutaj będą przechowywane twoje obrazy po uruchomieniu programu. Ogólnie rzecz biorąc, format, w którym je zapisałeś, nie ma znaczenia, ponieważ wszystkie obrazy są dekompresowane przed załadowaniem ich do pamięci wideo.

Teraz pamięć VRAM zużywana przez obrazy będzie w przybliżeniu odpowiadać width * height * bitdepth każdemu obrazowi załadowanemu do pamięci VRAM. Można tutaj zauważyć kilka rzeczy:

  1. Szerokość i wysokość, w której obrazy są przechowywane w pamięci VRAM, niekoniecznie muszą odpowiadać oryginalnym obrazom. Niektóre procesory graficzne obsługują tylko tekstury o rozmiarach o sile 2, więc obraz 320 x 240 może faktycznie być przechowywany w przestrzeni 512 x 256 w pamięci VRAM, a niewykorzystana pamięć zostanie skutecznie zmarnowana. Czasami nawet nie możesz ładować tekstur o rozmiarach, które nie są potęgami 2 (jak w GLES 1.1).

    Więc jeśli chcesz, aby zminimalizować zużycie VRAM, może chcesz rozważa atlasing swoje obrazy, a ich rozmiary uprawnień 2, które będą miały również tę zaletę, że mniej czynią zmian stanu podczas renderowania. Więcej na ten temat później.

  2. Bitdepth jest bardzo ważny. Zwykle tekstury są ładowane do VRAM w 32-bitowym ARGB lub 32-bitowym XRGB, ale jeśli twój sprzęt może obsługiwać 16-bitowe głębokości i nie masz nic przeciwko niższej głębi bitów, możesz zmniejszyć o połowę ilość pamięci VRAM zużywanej przez każdy obraz , co może być interesujące.

  3. Ale bez względu na to, co robisz, najważniejszym czynnikiem przy rozważaniu ilości pamięci VRAM używanej przez grę jest liczba obrazów w pamięci VRAM w danym momencie. Jest to liczba, którą najprawdopodobniej chcesz utrzymać na jak najniższym poziomie, jeśli chcesz mieć dobrą grę. Ładowanie i rozładowywanie tekstur do pamięci VRAM jest drogie, więc nie możesz po prostu załadować każdego obrazu, gdy tylko będziesz go używać. Musisz znaleźć równowagę między wstępnym ładowaniem obrazów, których najprawdopodobniej użyjesz, a rozładowaniem ich, jeśli masz pewność, że nie będziesz ich już używać. Wykonanie tego prawa nie jest trywialne i musisz pomyśleć o własnej strategii dla konkretnej gry.

Szybkość wykonania

Chociaż nie „pamięć”, jest bardzo związana z wydajnością w grach. Rysowanie obrazów jest drogie i chcesz mieć pewność, że renderowanie przebiega tak szybko, jak to możliwe. Oczywiście tutaj format nie ma znaczenia, ale inne rzeczy mają znaczenie:

  1. Rozmiar obrazu (w rzeczywistości byłby to „rozmiar próbki”): im większy region obrazu, który zamierzasz narysować, tym więcej czasu zajmie jego narysowanie. Renderowanie ogromnego obrazu w małej części ekranu nie jest zbyt skuteczne, dlatego istnieje technika zwana mipmapowaniem , która polega na wymianie pamięci VRAM na szybkość renderowania, poprzez przechowywanie obrazów kilka razy w kilku rozdzielczościach i użycie najmniejszej, która może dać wymagana jakość w danym momencie. Mapowanie mipem można wykonać po załadowaniu obrazów, co wpłynie na szybkość ładowania i użycie pamięci VRAM, lub podczas wstępnego przetwarzania (ręcznie przechowując różne wersje tego samego obrazu lub używając formatu, który natywnie obsługuje mapowanie takie jak DDS), co będzie miało wpływ na przechowywanie i użycie pamięci VRAM, ale będzie miało niewielki wpływ na szybkość ładowania.

  2. Zmiany stanu renderowania. Najprawdopodobniej będziesz chciał narysować na ekranie kilka różnych obrazów jednocześnie. Jednak GPU może używać tylko jednego obrazu źródłowego w danym momencie (to nie jest prawda, ale proszę o wyrozumiałość tutaj). Aktualnie używany obraz do renderowania jest jednym z wielu stanów renderowania i jest drogi. Jeśli więc zamierzasz użyć tego samego obrazu kilka razy (pamiętasz, kiedy wspomniałem o atlasach tekstur ?), Zauważysz ogromny wzrost wydajności, jeśli ponownie użyjesz obrazu tak dużo, jak to możliwe, zanim zmienisz stan renderowania i zaczniesz używać inny obraz (oprócz tego istnieją inne stany renderowania, a dostrajanie kolejności rysowania elementów w celu zminimalizowania zmian stanu renderowania jest bardzo częstym działaniem podczas zwiększania wydajności gry)

Jednak optymalizacja wykorzystania obrazu jest bardzo złożonym tematem, a to, co tu napisałem, jest bardzo szerokim i uproszczonym przeglądem niektórych czynników, które należy wziąć pod uwagę przy pisaniu gry, więc myślę, że zdecydowanie najlepiej jest zachować prostotę, i optymalizuj tylko wtedy, gdy naprawdę tego potrzebujesz. W większości przypadków przedwczesna optymalizacja jest niepotrzebna (a czasem nawet szkodliwa), więc spokojnie.

Panda Piżama
źródło
25
+1. To niezwykle wyczerpująca odpowiedź, która obejmuje bardzo dużo gruntu. Nie jestem pewien, czy rozmiar deskryptorów tekstur wymagał tyle miejsca, ile się dostał, a wzmianka DXT / ETC / PVRTC powinna naprawdę zawierać, że każdy z nich działa tylko na niektórych platformach - nie są otwarte na wiele platform standardy, które można stosować wszędzie, tak jak JPEG, PNG i GIF. Ale ogólnie bardzo pod wrażeniem. To coś więcej niż tylko „drobna adnotacja” na szczycie mojej odpowiedzi! : D
Trevor Powell
9
@PandaPajama: Może nie, ale jest to zaskakująco lepsza odpowiedź, niż na to pytanie zasługuje.
Marcks Thomas
1
+1 i więcej, gdybym mógł. To niesamowita odpowiedź i powinna być standardowym punktem odniesienia dla każdego pytania dotyczącego „wydajności pamięci”, ponieważ tak skutecznie obala wspólny mit, że używanie mniejszej ilości pamięci jest zawsze najlepszym podejściem, a nie tylko dla obrazów. Jedną rzeczą, którą zasugerowałbym dodanie, jest to, że w przypadku nieprzyspieszonego, jeśli podczas rysowania potrzebna jest dekompresja w locie, może to prowadzić do niedopuszczalnego obciążenia wydajności.
Maximus Minimus
2
Chciałbym zasugerować PNGGauntlet . Może dokonywać ogromnych bezstratnych optymalizacji rozmiarów plików PNG, które mogą się sumować, szczególnie gdy masz wiele duszków. Niestety jest to tylko system Windows, ale alternatywy są wymienione na stronie głównej dla innych systemów operacyjnych.
lub
1
@DavidDimalanta Nie mam doświadczenia z libgdx, ale jak widzę z dokumentacji setEnforcePotImages, wyłącza to wymuszanie mocy tekstur 2-wymiarowych w OpenGLES 1.0. To nie jest dobry pomysł, ponieważ nie wszystkie urządzenia obsługują tekstury bez zasilania 2. OpenGLES 2.0 wymaga obsługi tekstur innych niż power-of-2, więc jeśli celujesz w 2.0, możesz używać tekstur o dowolnym rozmiarze. Aby uzyskać więcej informacji, zapoznaj się z dokumentacją libgdx.
Panda Pajama
26

Gdy obraz zostanie załadowany z dysku i sformatowany do renderowania, zużyje tę samą ilość pamięci, niezależnie od tego, czy obraz został zapisany na dysku przy użyciu PNG, JPEG lub GIF.

Ogólna zasada: JPEG jest formatem stratnym i obniża jakość obrazu, aby zmniejszyć obraz na dysku. Z drugiej strony, PNG jest bezstratnym formatem obrazu, dlatego zwykle powoduje zwiększenie rozmiaru pliku na dysku. GIF jest również technicznie formatem bezstratnym, ale obsługuje maksymalnie 256 kolorów na obraz, dlatego obraz w wysokiej rozdzielczości często powoduje znaczną utratę jakości, jeśli jest zapisany jako GIF.

Ale to tylko dla ich reprezentacji na dysku. W pamięci oba rozwiną się do tego samego formatu tekstury, wykorzystując tę ​​samą ilość pamięci, niezależnie od tego, czy zapisałeś je na dysku jako PNG, JPEG czy GIF.

Trevor Powell
źródło
Więc to nie rozszerzenie pliku zmienia rozmiar pamięci, ale rozmiar pliku?
Tredecies Nocturne
Ani. Rozmiar w pamięci zależy od wymiarów i bitdepth obrazu. Kompresja pliku obrazu jest usuwana po załadowaniu obrazu do pamięci i narysowaniu go na ekranie. (Ponieważ procesory graficzne nie mogą renderować plików PNG, JPEG itp. Obrazy są przekształcane w ogólne pikmapy, aby procesory graficzne mogły sobie z nimi poradzić.)
Trevor Powell,
2
To nie jest w 100% prawda. Większość współczesnych procesorów graficznych (w tym osadzonych) obsługuje ładowanie i przechowywanie skompresowanych tekstur w pamięci graficznej, przy czym formaty takie jak DXT, ETC i PVRTC są najczęstsze w świecie osadzonym. Oczywiście, musiałbyś najpierw przechowywać tekstury w tych formatach zamiast PNG / JPG / GIF.
Panda Pajama
6
Pytanie było wyraźnym wyborem między PNG / JPG / GIF, z których żaden nie jest natywnie obsługiwany na żadnym znanym mi procesorze graficznym. Pierwotny pytający miał wystarczająco dużo problemów z rozróżnieniem między wielkością pliku na dysku a miejscem zajmowanym w pamięci RAM, że czułem, że dodanie większej liczby formatów plików tylko pomieszałoby podstawową kwestię. Możesz jednak podać własną odpowiedź.
Trevor Powell,
2
Mój komentarz jest tylko adnotacją. Gdybym miał udzielić odpowiedzi, najprawdopodobniej napisałbym to samo, co ty, plus mój komentarz jako końcowe oświadczenie końcowe. Nie mam nic więcej do dodania, więc uniknę powtórzeń, podając własną odpowiedź.
Panda Pajama
3

To zależy.

JPEG jest najbardziej wydajny dla zdjęć. Nie jest bezstratny, ale artefakty wprowadzone przez kompresję są najmniej widoczne w tym przypadku użycia.

PNG jest bezstratny i najbardziej wydajny w przypadku pikseli z ostrymi liniami i kilkoma kolorami. Obsługuje również przezroczystość alfa.

GIF nie może nic zrobić PNG nie może zrobić nic lepszego, oprócz możliwości przechowywania animacji. Jest to jednak istotne tylko w kontekście aplikacji internetowych. Podczas tworzenia gry zazwyczaj tworzysz animacje za pomocą arkusza sprite.

Zauważ, że kiedy używasz silnika graficznego takiego jak Libgdx, najprawdopodobniej rozpakuje on obrazy zaraz po ich załadowaniu, a następnie zachowa je w pamięci jako nieskompresowane wartości RGBA. Tak więc format obrazu ma znaczenie tylko dla prędkości ładowania i miał miejsce na dysku (lub wykorzystanie przepustowości podczas wysyłania ich przez sieć).

Philipp
źródło
2

Nie wiem dużo o libgdx, ale o formatach obrazów i grafice:

JPEG jest bardzo dobry w przypadku zdjęć ze świata rzeczywistego. Są stratne, ale na zdjęciach nie zobaczysz artefaktów, chyba że zrobisz zdjęcia o ostrych krawędziach z jednolitymi kolorowymi spacjami, np. Tekstem pisanym lub komiksem. Używaj ich do tworzenia dużych grafik w tle.

GIF jest przestarzały, może przechowywać tylko paletę kolorów (do 8 bitów na piksel) z jednym dedykowanym kolorem dla pełnej przejrzystości. Umożliwia małe animacje oparte na ramkach. Kiedyś istniał patent na algorytm pakowania, dzięki czemu nie można go było stosować wszędzie legalnie. Dzięki temu patentowi opracowano PNG.

PNG jest mniej więcej spakowaną bitmapą, która może przechowywać RGB + alfa (do 32 bitów) i inne formaty pikseli. Specjalizuje się w szybkim rozpakowywaniu małych części tego obrazu, co jest wygodne dla bardzo małych i wolnych urządzeń (takich jak 10-letni telefon komórkowy), ale dzisiejsze biblioteki po rozpakowaniu rozpakowują je do bitmap.

Format PNG jest lepszy niż format GIF, szybkość i funkcje, ale jeśli chcesz efektywnie przechowywać mapy bitowe, sugeruję: .PNM.BZ2 ([edycja] Ze względu na inną metodę pakowania, .PNM.BZ2 nie zawsze jest bardziej wydajny niż .PNG. [/ edit])

PNM / PBM / PGM / PAM to zwykłe formaty bitmapowe z nagłówkami KISS w postaci zwykłego tekstu. Użycie gzip na tych plikach da rozmiar pliku podobny do PNG, więc bzip2 jest lepszym rozwiązaniem. Jeśli zamierzasz używać bitmap wewnętrznie w swoim programie, możesz użyć bitmap skompresowanych bzip2 w kontenerze .tar lub .zip. Jeśli nie masz bzip2, używanie PNM w kontenerze zip (zip z maksymalną kompresją) może być podobne do używania PNG. - Tak więc przechowywanie plików PNG w pliku ZIP może mieć tylko niewielką lub żadną korzyść - najprawdopodobniej po prostu wydłuży czas ładowania obrazu.

Poza tym dobrze jest przechowywać kilka małych ikonek / obrazów w jednej mapie bitowej, szczególnie gdy potrzebujesz ich wszystkich w tej samej sytuacji razem.

comonad
źródło
Czy plik PNM jest dostępny i czytelny dla wszystkich systemów operacyjnych smartfonów i komputerów stacjonarnych?
David Dimalanta,
1
@David Dimalanta: Nie wiem, gdzie jest obsługiwany, a gdzie nie. Jeśli chcesz programować za pomocą PNM, rzadko chcesz korzystać z dowolnej biblioteki, ponieważ ten format jest zbyt prosty, aby wybrać dowolny interfejs API. Z tego powodu jest czytelny i zapisywalny we wszystkich istniejących językach programowania, które obsługują odczyt / zapis plików binarnych. Oczywiście możesz używać Netpbm na dowolnym systemie operacyjnym, nie tylko na Uniksie. Z drugiej strony nie wiem, które ogólne biblioteki obrazów nie obsługują tego. Nie jest to format skompresowany, więc i tak rzadko jest używany do przechowywania obrazów na dysku. patrz en.wikipedia.org/wiki/Netpbm_format
comonad
1

Jako format przechowywania JPEG jest prawdopodobnie najlepszym wyborem dla niektórych tekstur, takich jak trawa lub ściany, gdzie utrata informacji jest prawdopodobnie niewykrywalna. Po PNG, gdy potrzebujesz przejrzystości lub gdy nie możesz zapłacić z utratą informacji, na przykład duszki w grze 2D (gracz, wrogowie, skrzynia skarbów), prawdopodobnie chcesz użyć PNG do tych obrazów.

Mówiąc o koszcie pamięci, format używany do przechowywania grafiki gry w systemie plików w ogóle nie jest istotny. Albo jeśli przechowujesz bufory pikseli w VRAM, albo RAM (renderer oprogramowania), prawdopodobnie przechowujesz je w stanie nieskompresowanym, ponieważ gry preferują szybki odczyt pikseli w porównaniu z pamięcią używaną przez każdy bufor pikseli.

Skompresowane dane przechowywane w pamięci nie mają sensu, z wyjątkiem utrzymywania pewnego rodzaju pamięci podręcznej w celu zapisywania odczytów dysku, ale prawdopodobnie musisz odczytać z tej pamięci podręcznej do stanu nieskompresowanego dla obrazów używanych w danym momencie w grze.

Skompresowane dane obrazu mają nieco większy sens, jeśli możliwe jest szybkie dekodowanie sprzętowe. Przynajmniej do normalnego mapowania pamiętam ten http://en.wikipedia.org/wiki/3Dc . Dzięki temu możesz zaoszczędzić trochę pamięci VRAM. Nie znam jeszcze innych przykładów dekodowania sprzętowego.

Wznów: niezależnie od formatów używanych w grze do przechowywania grafiki w trwałym magazynie, musisz ją zdekodować i zachować nieskompresowaną wersję w pamięci dynamicznej, pamięci wideo lub w obu, aby móc szybko renderować je w razie potrzeby.

Wreszcie: jestem facetem od komputera. Kiedy mówię „pamięć”, zawsze mam na myśli pamięć dynamiczną. Kiedy mówię „dysk”, „system plików” lub „trwała pamięć”, zawsze mam na myśli to, co urządzenie używa jako pamięć trwałą, zwykle myślę o dyskach twardych. Kiedy powiedziałeś „wydajność pamięci”, wziąłem to za „pamięć dynamiczną”, a nie „pamięć trwałą”. Ostatnio widzę wiele osób używających słowa „pamięć” w odniesieniu do „trwałego przechowywania” (może to terminologia urządzeń mobilnych?).

Hatoru Hansou
źródło
Czy to możliwe, że to nie JPEG ani PNG wpływa na pamięć, ale na rozmiar pliku?
Tredecies Nocturne
Tak. Wybierz dowolny z omawianych formatów, myśląc o oszczędzaniu miejsca na dysku lub przepustowości. Podczas ładowania obrazów do gry dowolna biblioteka / silnik, który znam, dekoduje je do nieskompresowanych buforów pikseli (myśl w buforach pikseli jako tablicy wartości RGB lub RGBA, gdzie każdy kanał zwykle zajmuje 1 bajt w pamięci RAM / VRAM, jeśli używa 32 bitów na piksele, to zapewne wszyscy robią).
Hatoru Hansou