Welches Bildformat ist speichereffizienter: PNG, JPEG oder GIF?


Antworten:


153

"Gedächtnis" und "Effizienz" sind häufig missbrauchte Begriffe, daher werde ich Ihnen eine Antwort auf vier verschiedene Elemente geben, die sich auf die Leistung Ihres Spiels auswirken können.

Ich werde viel zu viele Dinge zu stark vereinfachen, um sie kurz und prägnant zu halten, aber es gibt Unmengen von Ungenauigkeiten in diesem Text unten, also nimm es mit einer Prise Salz. Die wichtigsten Konzepte sollten jedoch verständlich sein.

Lager

Dies ist die Größe, die Ihre Bilder für Ihre Softwareverteilung benötigen. Je mehr Speicherplatz Ihre Ressourcen belegen, desto länger dauert der Download (wie von Ihrer Website). Wenn Sie auf physischen Medien wie CDs oder DVDs verteilen, müssen Sie an dieser Stelle wahrscheinlich einige gravierende Optimierungen vornehmen.

Im Allgemeinen komprimiert JPEG am besten Fotos und Bilder ohne scharfe Ränder. Ihre Bilder haben jedoch eine schlechtere Qualität, da JPEG verlustbehaftete Komprimierung verwendet (Sie können die Komprimierungsstufe / -verschlechterung beim Exportieren von Bildern als JPEG fein einstellen . Weitere Informationen hierzu finden Sie in der Dokumentation Ihrer Bildbearbeitungssoftware.)

So gut JPEG auch sein mag, es unterstützt keine Transparenz . Dies ist von entscheidender Bedeutung, wenn Sie Bilder haben möchten, die durch andere angezeigt werden, oder wenn Sie Bilder mit unregelmäßigen Formen möchten. GIF ist eine gute Wahl, wurde jedoch von PNG weitgehend abgelöst (es gibt nur wenige Dinge, die von GIF unterstützt werden, die von PNG nicht unterstützt werden, für die Spielprogrammierung sind sie jedoch weitgehend irrelevant).

PNG unterstützt Transparenz (und Semitransparenz), komprimiert Daten ohne Qualitätsverlust (dh es verwendet verlustfreie Komprimierung) und komprimiert ziemlich gut, jedoch nicht so viel wie JPG.

Das Problem tritt auf, wenn Sie eine gute Komprimierung sowie Transparenz benötigen. Wenn Sie nichts gegen leicht verschlechterte Bilder haben, können Sie PNG-Quantisierungsprogramme wie pngquant verwenden , die Sie online bei TinyPNG testen können . Denken Sie daran, dass die Bildverschlechterung, die durch die Quantisierung von selbst durchgeführt wird, sich von der von JPEG unterscheidet (einschließlich Quantisierung und anderer aggressiver Techniken). Versuchen Sie also unbedingt beides mit einer Vielzahl von Einstellungen.

Wenn Sie Ihre Verteilungsgröße aggressiv minimieren möchten, können Sie jedes Bild wie folgt manuell verarbeiten:

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

Tipp: Es ist in Ordnung, einige Bilder in einem Format und andere in einem anderen Format zu speichern.

Es gibt andere spezialisierte Formate wie DXT, ETC und PVRTC. Sie unterstützen die Komprimierung und können auch komprimiert in den Speicher geladen werden. Sie werden jedoch nur von bestimmten GPUs unterstützt, und die meisten dieser GPUs unterstützen nur eine von ihnen. Wenn Sie also nicht die genauen Hardwarespezifikationen Ihrer Zielhardware kennen (dies ist ein bemerkenswerter Fall) Auf dem iPhone / iPad, das PVRTC-Texturen unterstützt, sollten Sie diese Formate meiden.

Programmspeicher

Ich habe es hier aufgenommen, weil dies allgemein als "Erinnerung" bekannt ist. Wenn Ihr Spiel jedoch Grafikbeschleunigung verwendet (und wenn Sie ein Spiel nach 1998 erstellen, ist dies höchstwahrscheinlich der Fall), werden nur Ihre Texturdeskriptoren (nur ein paar Bytes pro Bild) Speicher belegen Dies hängt von der Anzahl der Bilder und nicht von deren Größe oder Format ab (dies weist einige Einschränkungen auf, ist jedoch meistens irrelevant).

Wenn Ihre Plattform keinen dedizierten Videospeicher hat, nicht hardwarebeschleunigt ist oder in anderen seltenen Fällen, wird der nächste Abschnitt in Bezug auf VRAM ganz oder teilweise im RAM ausgeführt, die Hauptprinzipien sind jedoch dieselben.

Videospeicher

Hier werden Ihre Bilder gespeichert, sobald Ihr Programm ausgeführt wird. Im Allgemeinen spielt das Format, in dem Sie sie gespeichert haben, keine Rolle, da alle Bilder vor dem Laden in den Videospeicher dekomprimiert werden.

Der von Ihren Bildern aufgenommene VRAM wird nun ungefähr width * height * bitdepth für jedes in den VRAM geladene Bild verwendet. Hier sind einige Dinge zu beachten:

  1. Die Breite und Höhe, in der Ihre Bilder im VRAM gespeichert werden, müssen nicht mit denen Ihres Originalbilds übereinstimmen. Einige GPUs können nur Texturen mit einer Größe in Zweierpotenzen verarbeiten, sodass Ihr 320x240-Bild möglicherweise tatsächlich in einem 512x256-Bereich im VRAM gespeichert wird und der nicht verwendete Speicher effektiv verschwendet wird. Manchmal dürfen Sie nicht einmal Texturen mit Größen laden, die nicht Potenzen von 2 haben (wie in GLES 1.1).

    Wenn Sie also die VRAM-Nutzung minimieren möchten, sollten Sie erwägen, Ihre Bilder zu atlasieren und mit Zweierpotenzen zu skalieren. Dies hat auch den Vorteil, dass sich beim Rendern weniger Änderungen am Renderstatus ergeben. Dazu später mehr.

  2. Die Bittiefe ist sehr wichtig. Normalerweise werden Texturen in 32-Bit-ARGB oder 32-Bit-XRGB in den VRAM geladen. Wenn Ihre Hardware jedoch 16-Bit-Tiefen unterstützt und es Ihnen nichts ausmacht, eine niedrigere Bit-Tiefe zu haben, können Sie die Hälfte des von jedem Bild verbrauchten VRAMs verwenden , was interessant sein könnte.

  3. Unabhängig davon, was Sie tun, ist die Anzahl der Bilder, die Sie zu einem bestimmten Zeitpunkt im VRAM haben, der wichtigste Faktor, wenn Sie die Menge an VRAM in Ihrem Spiel berücksichtigen . Dies ist die Zahl, die Sie höchstwahrscheinlich so niedrig wie möglich halten möchten, wenn Sie ein Spiel mit guter Leistung wünschen. Das Laden und Entladen von Texturen in VRAM ist teuer, sodass Sie nicht jedes Bild einfach laden können, wenn Sie es verwenden möchten. Sie müssen ein Gleichgewicht zwischen dem Vorabladen der Bilder finden, die Sie höchstwahrscheinlich verwenden werden, und dem Entladen, wenn Sie sicher sind, dass Sie sie nicht mehr verwenden werden. Es ist nicht trivial, dies richtig zu machen, und Sie müssen sich Ihre eigene Strategie für Ihr bestimmtes Spiel überlegen.

Ausführungsgeschwindigkeit

Auch wenn es kein "Gedächtnis" ist, hängt es sehr mit der Leistung in Spielen zusammen. Das Zeichnen von Bildern ist teuer und Sie möchten sicherstellen, dass das Rendern so schnell wie möglich ausgeführt wird. Natürlich spielt hier das Format keine Rolle, aber andere Dinge tun es:

  1. Bildgröße (eigentlich "Abtastgröße"): Je größer der Bereich eines Bildes ist, den Sie zeichnen möchten, desto länger dauert das Zeichnen. Das Rendern eines großen Bilds in einem kleinen Bereich des Bildschirms ist nicht sehr effektiv. Daher gibt es eine Technik namens Mipmapping , bei der VRAM für die Rendergeschwindigkeit ausgetauscht wird , indem Ihre Bilder mehrmals mit verschiedenen Auflösungen gespeichert werden und die kleinste verwendet wird, die es gibt Sie die gewünschte Qualität zu einem bestimmten Zeitpunkt. Mipmapping kann ausgeführt werden, wenn die Bilder geladen werden, was sich auf die Ladegeschwindigkeit und die VRAM-Nutzung auswirkt, oder bei der Vorverarbeitung (indem verschiedene Versionen desselben Bildes manuell gespeichert werden oder ein Format verwendet wird, das Mipmapping von Haus aus unterstützt, z. B. DDS), was sich auf die Speicherung auswirkt und VRAM-Nutzung, hat aber nur geringen Einfluss auf die Ladegeschwindigkeit.

  2. Statusänderungen rendern. Sie möchten höchstwahrscheinlich mehrere verschiedene Bilder gleichzeitig auf dem Bildschirm zeichnen. Die GPU kann jedoch jeweils nur ein einziges Quellbild verwenden (dies ist nicht der Fall, bitte nehmen Sie dies hier mit). Das derzeit zum Rendern verwendete Bild ist einer von vielen Renderzuständen und teuer. Wenn Sie also dasselbe Bild mehrmals verwenden (erinnern Sie sich, als ich Texturatlanten erwähnte ?), Werden Sie einen enormen Leistungsgewinn bemerken, wenn Sie ein Bild so oft wie möglich wiederverwenden, bevor Sie den Render-Status ändern und a verwenden anderes Bild (abgesehen davon gibt es noch andere Render-Zustände, und die Feinabstimmung der Reihenfolge, in der Sie Ihre Inhalte zeichnen, um Änderungen des Render-Zustands zu minimieren, ist eine sehr häufige Aktivität bei der Verbesserung der Leistung eines Spiels.)

Die Optimierung der Bildnutzung ist jedoch ein sehr komplexes Thema, und was ich hier geschrieben habe, ist ein sehr umfassender und vereinfachter Überblick über einige der Faktoren, die Sie beim Schreiben eines Spiels berücksichtigen müssen. Ich denke, es ist auf jeden Fall am besten, wenn Sie es einfach halten. und optimieren Sie nur, wenn Sie es wirklich brauchen. In den meisten Fällen ist eine vorzeitige Optimierung nicht erforderlich (und manchmal sogar nachteilig).


25
+1. Dies ist eine äußerst umfassende Antwort, die sehr viel Boden abdeckt. Ich bin mir nicht sicher, ob die Größe der Textur-Deskriptoren so viel Speicherplatz benötigt wie möglich, und die Erwähnung von DXT / ETC / PVRTC sollte wirklich einschließen, dass jede davon nur auf einigen Plattformen funktioniert - sie sind nicht plattformübergreifend offen Standards, die überall einsetzbar sind, so wie JPEG, PNG und GIF. Aber insgesamt sehr beeindruckt. Dies ist viel mehr als nur eine "kleine Anmerkung" zu meiner Antwort! : D
Trevor Powell

9
@PandaPyjama: Vielleicht nicht, aber es ist eine überraschend bessere Antwort, als diese Frage verdient.
Marcks Thomas

1
+1 und mehr, wenn ich könnte. Dies ist eine großartige Antwort und sollte ein Standardbezugspunkt für jede Frage zur "Speichereffizienz" sein, da sie den verbreiteten Mythos so effektiv entlarvt, dass die Verwendung von weniger Speicher immer der beste Ansatz ist, und nicht nur für Bilder. Ein Punkt, den ich hinzufügen möchte, ist der, dass im nicht beschleunigten Fall, wenn eine sofortige Dekomprimierung beim Zeichnen erforderlich ist, dies einen inakzeptablen Leistungsaufwand bedeuten kann.
Maximus Minimus

2
Ich möchte PNGGauntlet vorschlagen . Es kann massive verlustfreie Optimierungen für PNG-Dateigrößen durchführen, die sich summieren können, insbesondere wenn Sie viele Sprites haben. Es ist leider nur Windows, aber Alternativen für andere Betriebssysteme sind auf der Homepage aufgeführt.
Orlp

1
@DavidDimalanta Ich habe keine Erfahrung mit libgdx, aber wie ich aus der Dokumentation von sehen kann setEnforcePotImages, deaktiviert es die Durchsetzung von Power von Texturen mit 2 Größen für OpenGLES 1.0. Dies ist keine gute Idee, da nicht jede Hardware Nicht-Power-of-2-Texturen unterstützt. OpenGLES 2.0 erfordert die Unterstützung von Nicht-Power-of-2-Texturen. Wenn Sie also auf 2.0 abzielen, können Sie Texturen beliebiger Größe verwenden. Weitere Informationen finden Sie in der libgdx-Dokumentation.
Panda Pyjama

26

Sobald ein Bild von der Festplatte geladen und zum Rendern formatiert wurde, wird dieselbe Speichermenge verwendet, unabhängig davon, ob das Bild mit PNG, JPEG oder GIF auf der Festplatte gespeichert wurde.

Allgemeine Faustregel: JPEG ist ein verlustbehaftetes Format und beeinträchtigt die Bildqualität, um das Bild auf der Festplatte zu verkleinern. PNG hingegen ist ein verlustfreies Bildformat und führt normalerweise zu größeren Dateien auf der Festplatte. GIF ist auch technisch gesehen ein verlustfreies Format, unterstützt jedoch nur maximal 256 Farben pro Bild, sodass ein Bild mit hohen Farben beim Speichern als GIF häufig einen erheblichen Qualitätsverlust erleidet.

Das ist jedoch nur für die Darstellung auf der Festplatte. Im Arbeitsspeicher werden beide in dasselbe Texturformat expandiert, wobei dieselbe Speichermenge verwendet wird, unabhängig davon, ob Sie sie als PNG, als JPEG oder als GIF auf der Festplatte gespeichert haben.


Es ist also nicht die Dateierweiterung, die die Speichergröße ändert, sondern die Dateigröße?
Tredecies Nocturne

Weder. Die Größe im Speicher hängt von den Bildabmessungen und der Bit-Tiefe ab. Jegliche Komprimierung der Bilddatei wird entfernt, wenn das Bild in den Speicher geladen wird, um auf dem Bildschirm angezeigt zu werden. (Da GPUs keine PNGs oder JPEGs oder ähnliches rendern können. Die Bilder werden zu generischen Pixmaps erweitert, damit GPUs mit ihnen umgehen können.)
Trevor Powell

2
Dies ist nicht 100% wahr. Die meisten modernen GPUs (einschließlich eingebetteter GPUs) unterstützen das Laden und Speichern komprimierter Texturen im Grafikspeicher, wobei Formate wie DXT, ETC und PVRTC in der eingebetteten Welt am häufigsten verwendet werden. Natürlich müssten Sie Ihre Texturen in diesen Formaten statt in PNG / JPG / GIF speichern.
Panda Pyjama

6
Die Frage war eine explizite Wahl zwischen PNG / JPG / GIF, von denen keine auf einer mir bekannten GPU nativ unterstützt wird. Der ursprüngliche Fragesteller hatte genug Probleme mit der Unterscheidung zwischen der Dateigröße auf der Festplatte und dem im RAM belegten Speicherplatz, sodass ich der Meinung war, dass das Hinzufügen weiterer Dateiformate das grundlegende Problem nur verwirren würde. Sie können jedoch gerne Ihre eigene Antwort geben.
Trevor Powell

2
Mein Kommentar ist nur eine Anmerkung. Wenn ich eine Antwort geben würde, hätte ich höchstwahrscheinlich das Gleiche wie Sie geschrieben, zuzüglich meines Kommentars als abschließende Erklärung. Ich habe nichts anderes hinzuzufügen, daher vermeide ich Wiederholungen, indem ich meine eigene Antwort gebe.
Panda Pyjama

3

Es hängt davon ab, ob.

JPEG ist für Fotographien am leistungsfähigsten. Es ist nicht verlustfrei, aber die durch die Komprimierung eingebrachten Artefakte sind in diesem Anwendungsfall am wenigsten sichtbar.

PNG ist verlustfrei und für Pixelkunst mit scharfen Linien und wenigen Farben am effizientesten. Es unterstützt auch Alpha-Transparenz.

GIF kann nichts, was PNG nicht besser kann, außer die Möglichkeit, Animationen zu speichern. Dies ist jedoch nur im Zusammenhang mit Webanwendungen relevant. In der Spieleentwicklung erstellen Sie Animationen normalerweise mithilfe eines Spritesheets.

Wenn Sie eine Grafik-Engine wie Libgdx verwenden, werden die Bilder höchstwahrscheinlich direkt nach dem Laden dekomprimiert und als unkomprimierte RGBA-Werte gespeichert. Das Bildformat ist also nur für die Ladegeschwindigkeit von Bedeutung und hat Speicherplatz (oder Bandbreitennutzung, wenn Sie sie über das Netz senden).


2

Ich weiß nicht viel über libgdx, aber über Bildformate und Grafiken:

JPEG ist sehr gut für Fotos aus der realen Welt. Sie sind verlustbehaftet, aber Sie werden keine Artefakte auf Fotos sehen, es sei denn, Sie machen Bilder mit scharfen Kanten und einfarbigen Zwischenräumen, wie zum Beispiel geschriebenen Text oder Comics. Verwenden Sie sie für große Hintergrundgrafiken.

GIF ist veraltet, es können nur Farben mit Paletten (bis zu 8 Bit pro Pixel) mit einer bestimmten Farbe gespeichert werden, um vollständige Transparenz zu gewährleisten. Es erlaubt kleine Animationen basierend auf Frames. Es gab einmal ein Patent für seinen Verpackungsalgorithmus, so dass er nicht überall legal verwendet werden konnte. Aufgrund dieses Patents wurde PNG entwickelt.

PNG ist mehr oder weniger eine gezippte Bitmap, die RGB + Alpha (bis zu 32 Bit) und andere Pixelformate speichern kann. Es ist auf das schnelle Entpacken kleiner Teile dieses Bildes spezialisiert, was für sehr kleine und langsame Geräte (wie ein 10 Jahre altes Mobiltelefon) praktisch ist, aber die heutigen Bibliotheken entpacken sie beim Laden einfach in Bitmaps.

PNG ist in Größe, Geschwindigkeit und Funktionen besser als GIF, aber wenn Sie Bitmaps effizient speichern möchten, würde ich Folgendes vorschlagen: .PNM.BZ2 ([Bearbeiten] Aufgrund der unterschiedlichen Packmethoden ist .PNM.BZ2 nicht immer effizienter als .PNG. [/ edit])

PNM / PBM / PGM / PAM sind einfache Bitmap-Formate mit KISS-Headern im Klartext. Die Verwendung von gzip führt zu einer Dateigröße, die der von PNG ähnelt. Daher ist bzip2 die bessere Lösung. Wenn Sie Bitmaps programmintern verwenden möchten, können Sie bzip2-komprimierte Bitmaps in einem .tar- oder .zip-Container verwenden. Wenn Sie nicht über bzip2 verfügen, ähnelt die Verwendung von PNMs in einem Zip-Container (Zip mit maximaler Komprimierung) möglicherweise der Verwendung von PNGs. - Das Speichern von PNGs in einer ZIP-Datei hat daher möglicherweise nur geringe oder gar keine Vorteile - es würde wahrscheinlich nur die Zeit zum Laden des Bildes verlängern.

Außerdem ist es eine gute Wahl, mehrere kleine Sprites / Bilder in einer Bitmap zu speichern, insbesondere wenn Sie alle in derselben Situation zusammen benötigen.


Ist die PNM-Datei für alle Smartphone- und Desktop-Betriebssysteme verfügbar und lesbar?
David Dimalanta

1
@ David Dimalanta: Ich weiß nicht, wo es unterstützt wird und wo nicht. Wenn Sie mit PNMs programmieren möchten, möchten Sie selten eine Bibliothek verwenden, da dieses Format zu einfach ist, um eine API auszuwählen. Aus diesem Grund kann es mit allen vorhandenen Programmiersprachen gelesen und geschrieben werden, die das Lesen / Schreiben von Binärdateien unterstützen. Natürlich können Sie Netpbm auf jedem Betriebssystem verwenden, nicht nur auf Unix. Andererseits weiß ich nicht, welche allgemeinen Bildbibliotheken dies nicht unterstützen. Da es sich nicht um ein komprimiertes Format handelt, werden Bilder nur selten auf der Festplatte gespeichert. siehe en.wikipedia.org/wiki/Netpbm_format
comonad

1

Als Speicherformat ist JPEG wahrscheinlich die beste Wahl für einige Texturen wie Gras oder Wände, bei denen der Informationsverlust wahrscheinlich nicht nachweisbar ist. Gefolgt von PNG, wenn Sie Transparenz benötigen oder wenn Sie nicht mit Informationsverlust bezahlen können, z. B. Sprites in einem 2D-Spiel (der Spieler, Feinde, eine Schatzkiste), möchten Sie wahrscheinlich PNG für diese Bilder verwenden.

Wenn es um die Speicherkosten geht, ist das Format, in dem die Spielgrafiken im Dateisystem gespeichert werden, überhaupt nicht relevant. Wenn Sie Pixelpuffer im VRAM oder im RAM (Software-Renderer) speichern, werden sie wahrscheinlich unkomprimiert gespeichert, da Spiele das schnelle Lesen von Pixeln im Vergleich zum von jedem Pixelpuffer verwendeten Speicher bevorzugen.

Komprimierte Daten im Speicher zu haben, hat keinen Sinn, es sei denn, Sie verwalten eine Art Cache, um Lesezugriffe auf die Festplatte zu speichern. Wahrscheinlich müssen Sie jedoch für die Bilder, die zu einem bestimmten Zeitpunkt in Ihrem Spiel verwendet werden, aus diesem Cache in einen nicht komprimierten Zustand lesen.

Komprimierte Bilddaten sind etwas sinnvoller, wenn eine schnelle Hardware-Dekodierung möglich wäre. Zumindest für die normale Zuordnung erinnere ich mich an diese http://en.wikipedia.org/wiki/3Dc . Damit können Sie ein wenig VRAM sparen. Andere Beispiele für die Hardware-Dekodierung sind mir noch nicht bekannt.

Fazit: Unabhängig von den Formaten, die in Ihrem Spiel zum Speichern von Grafiken in einem dauerhaften Speicher verwendet werden, müssen Sie diese dekodieren und eine unkomprimierte Version im dynamischen Speicher, im Videospeicher oder in beiden speichern, um sie bei Bedarf schnell rendern zu können.

Endlich: Ich bin ein Desktop-Typ. Wenn ich "Gedächtnis" sage, beziehe ich mich immer auf dynamisches Gedächtnis. Wenn ich "Festplatte", "Dateisystem" oder "persistenter Speicher" sage, beziehe ich mich immer auf das, was Ihr Gerät als persistenten Speicher verwendet, normalerweise denke ich an Festplatten. Wenn Sie "Speichereffizienz" sagten, habe ich es als "dynamischen Speicher" und nicht als "dauerhaften Speicher" bezeichnet. In letzter Zeit verwenden viele Leute das Wort "Speicher", um sich auf "dauerhaften Speicher" zu beziehen (vielleicht die Terminologie von Mobilgeräten?).


Ist es auch möglich, dass es sich nicht um JPEG oder PNG handelt, sondern um die Dateigröße?
Tredecies Nocturne

Ja. Sie können eines der besprochenen Formate auswählen, um Speicherplatz oder Bandbreite zu sparen. Wenn ich Bilder in das Spiel lade, werden sie von jeder mir bekannten Bibliothek / Engine in unkomprimierte Pixelpuffer dekodiert (in Pixelpuffern als ein Array von RGB- oder RGBA-Werten betrachtet, wobei jeder Kanal normalerweise 1 Byte im RAM / VRAM belegt, wenn 32 Bit pro Kanal verwendet werden Pixel, das ist wahrscheinlich, was jeder tut).
Hatoru Hansou
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.