Quale formato di immagine è più efficiente in termini di memoria: PNG, JPEG o GIF?


Risposte:


153

"Memoria" ed "efficienza" sono termini comunemente usati in modo improprio, quindi ti darò una risposta per quattro diversi elementi che possono influenzare le prestazioni del tuo gioco.

Semplificherò eccessivamente troppe cose per renderlo breve e conciso, ma ci sono tonnellate di inesattezze in questo testo qui sotto, quindi prendilo con un pizzico di sale. Tuttavia, i concetti principali dovrebbero essere comprensibili.

Conservazione

Questa è la dimensione utilizzata dalle immagini per la distribuzione del software. Più spazio consumano le risorse, più lungo sarà il download (come nel tuo sito Web). Se stai distribuendo su supporti fisici, come CD o DVD, probabilmente dovrai fare delle ottimizzazioni serie in questo senso.

In generale, JPEG comprime il meglio per fotografie e immagini senza bordi nitidi. Tuttavia, le immagini avranno una qualità degradata perché JPEG utilizza una compressione con perdita (è possibile ottimizzare il livello di compressione / degradazione quando si esportano immagini come JPEG. Per ulteriori informazioni, consultare la documentazione del software di imaging).

Tuttavia, per quanto JPEG possa essere, non supporta la trasparenza . Questo è fondamentale se vuoi avere immagini che mostrano attraverso altri, o se vuoi immagini con forme irregolari. GIF è una buona scelta, ma è stata ampiamente sostituita da PNG (ci sono solo alcune cose che GIF supporta PNG che non lo fa, ma sono in gran parte irrilevanti nella programmazione del gioco).

PNG supporta la trasparenza (e la semitrasparenza), comprime i dati senza peggiorare la qualità (ovvero utilizza la compressione senza perdita di dati) e comprime abbastanza bene, ma non tanto quanto JPG.

Il problema sorge quando è necessaria una buona compressione e trasparenza. Se non ti dispiace le immagini leggermente degradate, puoi usare programmi di quantizzazione PNG come pngquant , che puoi testare online su TinyPNG . Tieni presente che il degrado dell'immagine eseguito dalla quantizzazione da solo è diverso da quello del JPEG (che include la quantizzazione e altre tecniche aggressive), quindi assicurati di provare entrambi, con un'ampia varietà di impostazioni.

Se si desidera ridurre al minimo le dimensioni della distribuzione in modo aggressivo, è possibile elaborare manualmente ogni immagine in questo modo:

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

Suggerimento: è possibile archiviare alcune immagini in un formato e altre in un altro formato.

Esistono altri formati specializzati come DXT, ETC e PVRTC. Supportano la compressione e possono anche essere caricati compressi in memoria, ma sono supportati solo da GPU specifiche e la maggior parte di queste GPU ne supporta solo una, quindi a meno che non si conoscano le specifiche hardware esatte dell'hardware di destinazione (un caso notevole è iPhone / iPad, che supporta le trame PVRTC), dovresti evitare questi formati.

Memoria di programma

L'ho incluso qui, perché questo è ciò che è comunemente noto alla "memoria". Tuttavia, se il tuo gioco utilizza l'accelerazione grafica (e se stai realizzando un gioco dopo il 1998, molto probabilmente lo sei), l'unica cosa che consumerà memoria sono i descrittori di trama (solo pochi byte per immagine), che è solo influenzato dalla quantità di immagini e non dalla loro dimensione o formato (questo ha alcuni avvertimenti, ma sono per lo più irrilevanti).

Se la tua piattaforma non ha memoria video dedicata, non è accelerata dall'hardware o altri casi non comuni, la sezione successiva relativa alla VRAM avverrà completamente o parzialmente nella RAM, ma i principi principali saranno gli stessi.

Memoria video

È qui che verranno archiviate le immagini una volta che il programma è in esecuzione. In generale, il formato in cui sono state memorizzate non farà alcuna differenza qui, poiché tutte le immagini vengono decompresse prima di caricarle nella memoria video.

Ora, la VRAM consumata dalle tue immagini sarà approssimativamente width * height * bitdepth per ogni immagine caricata in VRAM. Ci sono un paio di cose da notare qui:

  1. La larghezza e l'altezza in cui sono memorizzate le immagini in VRAM non corrisponderanno necessariamente a quelle dell'immagine originale. Alcune GPU possono gestire solo trame con dimensioni in potenze di 2, quindi l'immagine 320x240 può effettivamente essere memorizzata in uno spazio 512x256 in VRAM, con la memoria inutilizzata effettivamente sprecata. Alcune volte non ti è nemmeno permesso caricare trame con dimensioni che non sono potenze di 2 (come in GLES 1.1).

    Quindi, se si desidera ridurre al minimo l'utilizzo della VRAM, è possibile prendere in considerazione la possibilità di atlante delle immagini e di dimensionarle con potenze di 2, che avranno anche il vantaggio di un minor numero di modifiche allo stato di rendering durante il rendering. Più su questo più tardi.

  2. Il bitdepth è molto importante. Di solito le trame vengono caricate in VRAM in ARGB a 32 bit o XRGB a 32 bit, ma se il tuo hardware può supportare profondità a 16 bit e non ti dispiace avere una profondità di bit inferiore, puoi metà della quantità di VRAM consumata da ogni immagine , che potrebbe essere qualcosa di interessante da considerare.

  3. Ma non importa quello che fai, il fattore più importante quando si considera la quantità di VRAM utilizzata dal tuo gioco, è la quantità di immagini che hai in VRAM in un determinato momento. Questo è il numero che molto probabilmente vorresti mantenere il più basso possibile se vuoi un gioco con buone prestazioni. Caricare e scaricare trame in VRAM è costoso, quindi non puoi semplicemente caricare ogni immagine ogni volta che la userai. Devi trovare un equilibrio tra il precaricamento delle immagini che molto probabilmente utilizzerai e scaricarle quando sei sicuro di non usarle più. Fare questo nel modo giusto non è banale e devi pensare alla tua strategia per il tuo gioco particolare.

Velocità di esecuzione

Anche se non "memoria", è molto correlato alle prestazioni nei giochi. Il disegno delle immagini è costoso e si desidera assicurarsi che il rendering venga eseguito il più rapidamente possibile. Naturalmente, qui, il formato non ha importanza, ma altre cose fanno:

  1. Dimensione dell'immagine (in realtà, sarebbe "dimensione di campionamento"): più grande è la regione di un'immagine che disegnerai, più tempo ci vorrà per disegnarla. Il rendering di un'immagine enorme in una piccola sezione dello schermo non è molto efficace, quindi esiste una tecnica chiamata mipmapping , che consiste nel scambiare VRAM per la velocità di rendering, memorizzando le tue immagini più volte a diverse risoluzioni e utilizzando la più piccola che può dare la qualità richiesta in qualsiasi momento. Il mipmapping può essere eseguito quando le immagini vengono caricate, il che influirà sulla velocità di caricamento e sull'utilizzo della VRAM o durante la preelaborazione (memorizzando manualmente versioni diverse della stessa immagine o utilizzando un formato che supporta nativamente il mipmapping come DDS), che influirà sulla memorizzazione e l'utilizzo della VRAM, ma avrà un impatto limitato sulla velocità di caricamento.

  2. Rendering dello stato cambia. Molto probabilmente vorrai disegnare diverse immagini sullo schermo contemporaneamente. Tuttavia, la GPU può utilizzare una sola immagine sorgente in qualsiasi momento (questo non è vero, ma per favore abbi pazienza con me qui). L'immagine attualmente utilizzata per il rendering è uno dei tanti stati di rendering ed è costosa. Quindi, se hai intenzione di utilizzare la stessa immagine più volte (ricordi quando ho menzionato atlanti di trama ?), Noterai un enorme miglioramento delle prestazioni se riutilizzi un'immagine il più possibile prima di cambiare lo stato di rendering e iniziare a utilizzare un immagine diversa (ci sono altri stati di rendering oltre a questo, e la messa a punto dell'ordine in cui si disegnano le cose per minimizzare i cambiamenti dello stato di rendering è un'attività molto comune quando si migliora le prestazioni di un gioco)

Tuttavia , l'ottimizzazione dell'utilizzo delle immagini è un argomento molto complesso e quello che ho scritto qui è una panoramica molto ampia e semplificata di alcuni dei fattori che dovresti considerare quando scrivi un gioco, quindi penso che sia decisamente meglio se lo mantieni semplice, e ottimizzare solo quando è necessario. La maggior parte delle volte, l'ottimizzazione prematura è inutile (e talvolta addirittura dannosa), quindi rilassati.


25
+1. Questa è una risposta estremamente completa che copre moltissimo terreno. Non sono sicuro che la dimensione dei descrittori di trama richieda lo stesso spazio necessario e la menzione DXT / ETC / PVRTC dovrebbe davvero includere che ognuno di questi funziona solo su alcune piattaforme: non sono aperti multipiattaforma standard utilizzabili ovunque, come lo sono JPEG, PNG e GIF. Ma nel complesso, sono rimasto molto colpito. Questo è molto più di una semplice "annotazione minore" in cima alla mia risposta! : D
Trevor Powell,

9
@PandaPajama: Forse no, ma è una risposta sorprendentemente migliore di quella che merita questa domanda.
Marcks Thomas,

1
+1 e altro se potessi. Questa è una risposta fantastica, e dovrebbe essere un punto di riferimento standard per qualsiasi domanda su "efficienza della memoria" in quanto elimina in modo così efficace il mito comune che l'uso di meno memoria è sempre l'approccio migliore, e non solo per le immagini. Un elemento che suggerirei di aggiungere è che nel caso non accelerato, se è necessaria una decompressione al volo durante il disegno, ciò può comportare un sovraccarico di prestazioni inaccettabile.
Massimo Massimo

2
Vorrei suggerire PNGGauntlet . Può fare enormi ottimizzazioni senza perdite per le dimensioni dei file PNG, che possono sommarsi, specialmente quando hai molti sprite. Purtroppo è solo Windows, ma le alternative sono elencate nella homepage per altri sistemi operativi.
orlp

1
@DavidDimalanta Non ho esperienza con libgdx, ma come posso vedere dalla documentazione di setEnforcePotImages, disabilita l'applicazione del potere di trame di 2 dimensioni per OpenGLES 1.0. Questa non è una buona idea, poiché non tutto l'hardware supporta trame non di potenza di 2. OpenGLES 2.0 richiede il supporto per trame non power-of-2, quindi se hai come target 2.0, puoi usare trame di qualsiasi dimensione. Per ulteriori informazioni, consultare la documentazione di libgdx.
Panda Pajama,

26

Una volta che un'immagine viene caricata dal disco e formattata per il rendering, utilizzerà la stessa quantità di memoria indipendentemente dal fatto che l'immagine sia stata salvata sul disco usando PNG, JPEG o GIF.

Regola generale: JPEG è un formato con perdita di dati e degraderà la qualità dell'immagine al fine di ridurla sul disco. PNG, d'altra parte, è un formato di immagine senza perdita di dati, e quindi di solito si tradurrà in file di dimensioni maggiori su disco. Anche la GIF è tecnicamente un formato senza perdita di dati, ma supporta solo un massimo di 256 colori per immagine, quindi un'immagine di colore elevato spesso comporta una perdita di qualità elevata se salvata come GIF.

Questo è solo per la loro rappresentazione su disco, però. In memoria, entrambi si espanderanno nello stesso formato di trama, utilizzando la stessa quantità di memoria, indipendentemente dal fatto che siano stati salvati su disco come PNG, JPEG o GIF.


Quindi non è l'estensione del file che varia la dimensione della memoria ma la dimensione del file?
Tredecies Nocturne,

Nessuno dei due. La dimensione in memoria si basa sulle dimensioni dell'immagine e sulla profondità di bit. Qualsiasi compressione sul file immagine viene rimossa quando l'immagine viene caricata in memoria per essere disegnata sullo schermo. (Poiché le GPU non possono eseguire il rendering di PNG o JPEG o ecc. Le immagini vengono espanse in pixmap generiche in modo che le GPU possano gestirle.)
Trevor Powell,

2
Questo non è vero al 100%. La maggior parte delle GPU moderne (comprese quelle incorporate) supporta il caricamento e l'archiviazione di trame compresse nella memoria grafica, con formati come DXT, ETC e PVRTC che sono i più comuni nel mondo embedded. Ovviamente, dovresti memorizzare le tue trame in questi formati in primo luogo anziché in PNG / JPG / GIF.
Panda Pajama,

6
La domanda era una scelta esplicita tra PNG / JPG / GIF, nessuna delle quali è supportata nativamente su qualsiasi GPU di cui sono a conoscenza. Il richiedente originale stava avendo abbastanza problemi con la distinzione tra dimensione del file sul disco e spazio occupato nella RAM che ho pensato che l'aggiunta di più formati di file avrebbe solo confuso il problema fondamentale. Sentiti libero di fornire la tua risposta, però.
Trevor Powell,

2
Il mio commento è solo un'annotazione. Se dovessi fornire una risposta, molto probabilmente avrei scritto lo stesso di te, più il mio commento come una dichiarazione finale di chiusura. Non ho altro da aggiungere, quindi eviterò la ripetizione fornendo la mia risposta.
Panda Pajama,

3

Dipende.

Jpeg è più efficiente per le fotografie. Non è senza perdita di dati, ma i manufatti introdotti dalla compressione sono meno visibili in questo caso d'uso.

PNG è senza perdite ed è più efficiente per la pixel art con linee nitide e pochi colori. Supporta anche la trasparenza alfa.

GIF non può fare nulla PNG non può fare di meglio, tranne per la sua capacità di memorizzare animazioni. Ma questo è rilevante solo nel contesto delle applicazioni web. Nello sviluppo del gioco di solito crei animazioni usando uno spritesheet.

Nota che quando usi un motore grafico come Libgdx molto probabilmente decomprimerà le immagini subito dopo averle caricate e poi le manterrà in memoria come valori RGBA non compressi. Quindi il formato dell'immagine è importante solo per la velocità di caricamento e ha spazio su disco (o utilizzo della larghezza di banda quando li invii in rete).


2

Non so molto di libgdx, ma di formati di immagine e grafica:

JPEG è molto buono in caso di foto del mondo reale. Sono a perdita, ma non vedrai artefatti sulle foto a meno che non scatti foto di spigoli vivi con spazi a tinta unita, come ad esempio testo scritto o fumetti. Usali per la grafica di sfondo di grandi dimensioni.

La GIF è obsoleta, può memorizzare solo colori palettizzati (fino a 8 bit per pixel) con un colore dedicato per una trasparenza completa. Permette piccole animazioni basate su frame. Una volta c'era un brevetto sul suo algoritmo di imballaggio in modo che non potesse essere usato ovunque legalmente. A causa di quel brevetto, fu sviluppato PNG.

PNG è più o meno una bitmap zippata in grado di memorizzare RGB + alfa (fino a 32 bit) e altri formati di pixel. È specializzato per la decompressione rapida di piccole parti di quell'immagine, il che è conveniente per dispositivi molto piccoli e lenti (come un cellulare di 10 anni), ma le librerie di oggi li scompattano in bitmap quando caricate.

PNG è meglio di GIF per dimensioni, velocità e funzionalità, ma se si desidera archiviare bitmap in modo efficiente, suggerirei: .PNM.BZ2 ([modifica] A causa del diverso metodo di imballaggio, .PNM.BZ2 non è sempre più efficiente di .PNG. [/ modifica])

PNM / PBM / PGM / PAM sono formati bitmap semplici con intestazioni KISS in testo normale. Usando gzip su questi si otterrà una dimensione del file simile a PNG, quindi bzip2 è la soluzione migliore per questo. Se utilizzerai bitmap internamente nel tuo programma, potresti voler utilizzare bitmap compresse bzip2 in un contenitore .tar o .zip. Se non si dispone di bzip2, l'utilizzo dei PNM in un contenitore zip (zip con la massima compressione) potrebbe essere simile all'utilizzo dei PNG. - Quindi, la memorizzazione di PNG in un file ZIP potrebbe avere solo piccoli o nessun vantaggio - molto probabilmente aumenterebbe il tempo per caricare l'immagine.

Oltre a ciò, è una buona scelta archiviare diversi piccoli sprite / immagini in una bitmap, specialmente quando sono necessari tutti insieme nella stessa situazione.


Il file PNM è disponibile e leggibile per tutti i sistemi operativi degli smartphone e dei computer desktop?
David Dimalanta,

1
@David Dimalanta: non so dove sia supportato e dove non lo sia. Se vuoi programmare con PNM, raramente vuoi usare qualsiasi libreria, perché quel formato è troppo semplice per scegliere qualsiasi API. Per questo motivo, è leggibile e scrivibile con tutti i linguaggi di programmazione esistenti che supportano la lettura / scrittura di file binari. Ovviamente potresti usare Netpbm su qualsiasi sistema operativo, non solo su Unix. D'altra parte, non so quali librerie di immagini generali non supportano questo. Non è un formato compresso, quindi viene raramente utilizzato per archiviare immagini su disco comunque. vedi en.wikipedia.org/wiki/Netpbm_format
comonad

1

Poiché il formato di archiviazione JPEG è probabilmente la scelta migliore per alcune texture come erba o muri, dove la perdita di informazioni è probabilmente non rilevabile. Seguito da PNG quando hai bisogno di trasparenza o quando non puoi pagare con perdita di informazioni, ad esempio sprite in un gioco 2D (il giocatore, i nemici, un forziere), probabilmente vuoi usare PNG per quelle immagini.

Quando si parla di costi di memoria, il formato utilizzato per archiviare la grafica di gioco nel file system non è affatto rilevante. O se memorizzi i buffer di pixel in VRAM o RAM (renderer software), probabilmente li hai memorizzati non compressi, perché i giochi favoriscono la lettura veloce dei pixel rispetto alla memoria utilizzata da ciascun buffer di pixel.

Avere dati compressi archiviati in memoria non ha senso se non si mantiene un qualche tipo di cache per salvare le letture del disco, ma probabilmente è necessario leggere da quella cache in uno stato non compresso per le immagini in uso in un determinato momento del gioco.

I dati di immagine compressi hanno un po 'più senso se fosse possibile una decodifica hardware rapida. Almeno per la normale mappatura, ricordo questo http://en.wikipedia.org/wiki/3Dc . Con ciò puoi salvare un po 'di VRAM. Non sono ancora a conoscenza di altri esempi di decodifica hardware.

In sintesi: qualunque sia il formato utilizzato per il tuo gioco per archiviare la grafica in memoria persistente, dovrai decodificarla e mantenere una versione non compressa nella memoria dinamica, nella memoria video o in entrambe, per renderle rapidamente quando necessario.

Finalmente: sono un ragazzo desktop. Quando dico "memoria" mi riferisco sempre alla memoria dinamica. Quando dico "disco", "file system" o "archiviazione persistente" mi riferisco sempre a qualunque cosa il tuo dispositivo usi come memoria persistente, di solito penso ai dischi rigidi. Quando hai detto "efficienza della memoria" l'ho preso per "memoria dinamica" e non "memoria persistente". Ultimamente vedo molte persone che usano la parola "memoria" per riferirsi a "memoria persistente" (forse quella terminologia dei dispositivi mobili?).


È anche possibile che non sia il JPEG né il PNG a influire sulla memoria ma sulla dimensione del file?
Tredecies Nocturne,

Sì. Sceglierai uno qualsiasi dei formati discussi pensando allo spazio su disco o alla larghezza di banda. Quando si caricano le immagini nel gioco, qualsiasi libreria / motore che conosco li decodificherà in buffer di pixel non compressi (si pensi ai buffer di pixel come a una matrice di valori RGB o RGBA, dove ogni canale occupa normalmente 1 byte in RAM / VRAM se si usano 32 bit per pixel, è probabilmente quello che fanno tutti).
Hatoru Hansou,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.