76
\$\begingroup\$

Which image format is more efficient to save memory? PNG, JPEG, or GIF?

\$\endgroup\$
1
  • 4
    \$\begingroup\$ The format of the file has nothing to do with textures or disposing of objects. \$\endgroup\$
    – Kylotan
    Jan 29, 2013 at 13:00

5 Answers 5

158
\$\begingroup\$

"Memory" and "efficiency" are commonly misused terms, so I'll give you an answer for four different elements that may affect the performance of your game.

I will be oversimplifying way too many things to keep it short and concise, but there are tons of inaccuracies in this text below, so take it with a pinch of salt. However, the main concepts should be understandable.

Storage

This is the size your images consume on your software distribution. The more space your resources consume, the longer the download (as in from your website) will be. If you're distributing on physical media, such as CDs or DVDs, you're probably going to have to do some serious optimizations in this front.

In general, JPEG compresses the best for photographs and images with no sharp borders. However, your images will have degraded quality because JPEG uses lossy compression (you can fine tune the compression level/degradation when exporting images as JPEG. Refer to your imaging software's documentation for more information on this).

However, as good as JPEG may be, it doesn't support transparency. This is crucial if you want to have images that show through others, or if you want images with irregular shapes. GIF is a good choice, but it has been largely superseded by PNG (there's only a few things GIF supports that PNG doesn't, but they're largely irrelevant in game programming).

PNG supports transparency (and semitransparency), compresses data without degradation in quality (i.e. it uses lossless compression), and compresses fairly well, but not as much as JPG.

The problem arises when you need good compression, as well as transparency. If you don't mind slightly degraded images, you can use PNG quantization programs such as pngquant, which you can test online at TinyPNG. Keep in mind that the image degradation performed by quantization on its own is different than that of JPEG (which includes quantization as well as other aggressive techniques), so be sure to try both, with a wide variety of settings.

If you want to aggressively minimize your distribution size, you could manually process every image like this:

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: it is okay to store some images in one format, and others in another format.

There are other specialized formats such as DXT, ETC and PVRTC. They support compression, and can also be loaded compressed into memory, but they are only supported by specific GPUs, and most of these GPUs only support one of them, so unless you know the exact hardware specifications of your target hardware (a notable case is the iPhone/iPad, which supports PVRTC textures), you should avoid these formats.

Program Memory

I included it here, because this is what's commonly known by "memory". However, if your game uses graphics acceleration (and if you're making a game after 1998, you most likely are), then the only thing that will consume memory are your texture descriptors (just a few bytes per image), which is only effected by the amount of images, and not their size or format (this has a few caveats, but are mostly irrelevant).

If your platform does not have dedicated video memory, is not hardware accelerated, or other uncommon cases, then the next section regarding VRAM will happen completely or partially in RAM, but the main principles will be the same.

Video Memory

This is where your images will be stored once your program is running. In general, the format in which you stored them will make no difference here, as all images are decompressed before loading them into video memory.

Now, the VRAM consumed by your images will roughly be width * height * bitdepth for each image loaded in VRAM. There are a couple of things to notice here:

  1. The width and height in which your images are stored in VRAM will not necessarily match the ones of your original image. Some GPUs can only handle textures with sizes in powers of 2, so your 320x240 image may actually be stored in a 512x256 space in VRAM, with the unused memory effectively wasted. Some times you're not even allowed to load textures with sizes that are not powers of 2 (like in GLES 1.1).

    So if you want to minimize VRAM usage, you may want to considering atlasing your images, and sizing them with powers of 2, which will also have the advantage of fewer render state changes when rendering. More on this later.

  2. The bitdepth is very important. Usually textures are loaded into VRAM in 32-bit ARGB or 32-bit XRGB, but if your hardware can support 16-bit depths, and you don't mind having a lower bitdepth, you can half the amount of VRAM consumed by each image, which may be something interesting to consider.

  3. But no matter what you do, the most important factor when considering the amount of VRAM your game uses, is the amount of images you have in VRAM at a given time. This is the number you most likely want to keep as low as possible if you want a good performing game. Loading and unloading textures into VRAM is expensive, so you can't just load each image whenever you're going to use it. You must find a balance between preloading the images you will most likely use, and unload them when you're sure you're not going to use them anymore. Doing this right is not trivial, and you have to think of your own strategy for your particular game.

Execution speed

Even though not "memory", it is very related with performance in games. Drawing images is expensive, and you want to make sure your rendering runs as fast as possible. Of course, in here, format doesn't matter, but other things do:

  1. Image size (actually, it would be "sampling size"): the biggest the region of an image you're going to draw, the more time it will take to draw it. Rendering a huge image in a small section of the screen is not very effective, so there is a technique called mipmapping, which consists of trading VRAM for rendering speed, by storing your images several times at several resolutions and using the smallest one that can give you the required quality at any given time. Mipmapping can be performed when the images are loaded, which will impact loading speed and VRAM usage, or at preprocessing (by manually storing different versions of the same image, or using a format that natively supports mipmapping such as DDS), which will impact storage and VRAM usage, but will have little impact on loading speed.

  2. Render state changes. You will most likely want to draw several different images on the screen at the same time. However, the GPU can only use a single source image at any given time (this is not true, but please bear with me here). The currently used image for rendering is one of many render states, and it is expensive. So if you're going to use the same image several times (remember when I mentioned texture atlases?), you will notice a huge performance gain if you reuse an image as much as you can before you change the render state and start using a different image (there are other render states apart from this, and fine tuning the order in which you draw your stuff to minimize render state changes is a very common activity when enhancing the performance of a game)

However, image usage optimization is a very complex topic, and what I wrote here is a very broad and oversimplified overview of some of the factors you will have to consider when writing a game, so I think it's definitely best if you keep it simple, and only optimize whenever you really need to do so. Most of the times, prematurely optimizing is unnecessary (and sometimes even detrimental), so take it easy.

\$\endgroup\$
38
  • 26
    \$\begingroup\$ +1. This is an extremely comprehensive answer that covers an awful lot of ground. I'm not sure that the size of texture descriptors required quite as much space as it got, and the DXT/ETC/PVRTC mention should really include that each of those only works on some platforms -- they aren't cross-platform open standards which are usable everywhere, the way that JPEG, PNG, and GIF are. But overall, very impressed. This is a lot more than just "a minor annotation" on top of my answer! :D \$\endgroup\$ Jan 29, 2013 at 8:50
  • 9
    \$\begingroup\$ @PandaPajama: Maybe not, but it's a surprisingly better answer than this question deserves. \$\endgroup\$ Jan 29, 2013 at 12:31
  • 1
    \$\begingroup\$ +1, and more if I could. This is an awesome answer, and should be a standard point of reference for any question about "memory efficiency" as it so effectively debunks the common myth that using less memory is always the best approach, and not just for images. One item I would suggest adding is that in the non-accelerated case, if any on-the-fly decompression is needed when drawing it may amount to an unacceptable performance overhead. \$\endgroup\$ Jan 29, 2013 at 14:12
  • 2
    \$\begingroup\$ I would like to suggest PNGGauntlet. It can do massive lossless optimizations for PNG file sizes, that can add up, especially when you have many sprites. It sadly is Windows only, but alternatives are listed on the homepage for other OS's. \$\endgroup\$
    – orlp
    Jan 29, 2013 at 17:53
  • 1
    \$\begingroup\$ @DavidDimalanta I have no experience with libgdx, but as I can see from the documentation of setEnforcePotImages, it disables the enforcement of power of 2 sized textures for OpenGLES 1.0. This is not a good idea, as not all hardware supports non-power-of-2 textures. OpenGLES 2.0 requires support for non-power-of-2 textures, so if you're targeting 2.0, you can use textures of any size. For more information refer to the libgdx documentation. \$\endgroup\$ Jan 30, 2013 at 15:57
30
\$\begingroup\$

Once an image is loaded off the disk and is formatted for rendering, it will use the same amount of memory regardless of whether that image was saved to disk using PNG, JPEG, or GIF.

General rule of thumb: JPEG is a lossy format, and will degrade image quality in order to make the image smaller on disk. PNG, on the other hand, is a lossless image format, and so will typically result in larger file sizes on disk. GIF is also technically a lossless format, but only supports a maximum of 256 colors per image, and so a high-color image will often incur a heavy quality loss if saved as a GIF.

That's only for their on-disk representation, though. In memory, they'll both expand into the same texture format, using the same amount of memory, regardless of whether you saved them to disk as PNG, or as JPEG, or as GIF.

\$\endgroup\$
6
  • \$\begingroup\$ So it's not the file extention that varies the memory size but the file size? \$\endgroup\$ Jan 29, 2013 at 5:55
  • \$\begingroup\$ Neither. The size in memory is based on the image dimensions and bitdepth. Any compression on the image file is removed when the image is loaded into memory to be drawn to the screen. (Because GPUs can't render PNGs or JPEGs or etc. The images are expanded out into generic pixmaps so that GPUs can deal with them.) \$\endgroup\$ Jan 29, 2013 at 6:07
  • 2
    \$\begingroup\$ This is not 100% true. Most modern GPUs (including embedded ones) support loading and storing compressed textures in graphics memory, with formats such as DXT, ETC and PVRTC being the most common in the embedded world. Of course, you would have to store your textures in these formats in the first place instead of PNG/JPG/GIF. \$\endgroup\$ Jan 29, 2013 at 6:47
  • 6
    \$\begingroup\$ The question was an explicit choice between PNG/JPG/GIF, none of which are natively supported on any GPU I'm aware of. The original asker was having enough trouble with the distinction between file size on disk and space taken up in RAM that I felt that adding more file formats would only confuse the fundamental issue. Feel free to provide your own answer, though. \$\endgroup\$ Jan 29, 2013 at 7:01
  • 2
    \$\begingroup\$ My comment is just an annotation. If I were to provide an answer, I would have most likely written the same as you did, plus my comment as a final closing statement. I have nothing else to add, so I'll avoid repetition by providing my own answer. \$\endgroup\$ Jan 29, 2013 at 7:24
3
\$\begingroup\$

It depends.

Jpeg is most efficient for photographs. It isn't lossless, but the artifacts introduced by the compression are least visible in this use-case.

PNG is lossless and most efficient for pixel-art with sharp lines and few colors. It also supports alpha-transparency.

GIF can't do anything PNG can't do better, except for its ability to store animations. But this is only relevant in the context of web applications. In game development you usually create animations by using a spritesheet.

Note that when you use a graphic engine like Libgdx it will most likely uncompress the images just after loading them and then keep them in memory as uncompressed RGBA values. So the image format only matters for loading speed and had drive space (or bandwidth usage when you send them over the net).

\$\endgroup\$
2
\$\begingroup\$

I don't know much about libgdx, but about image formats and graphics:

JPEG is very good in cases of real world photos. They are lossy but you won't see artifacts on photos unless you take pictures of sharp edges with plain coloured spaces, like for example written text or comics. Use them for large background graphics.

GIF is obsolete, it can only store paletted colors (up to 8 bit per pixel) with one dedicated color for complete transparency. It allows small animations based on frames. Once there was a patent on its packing algorithm so that it could not be used everywhere legally. Because of that patent, PNG was developed.

PNG is more or less a zipped bitmap that can store RGB+alpha (up to 32bit) and other pixel formats. It is specialized for speed-unzipping of small parts of that picture, which is convenient for very small and slow devices (like a 10 year old cellphone), but todays libraries just unpack them to bitmaps when loaded.

PNG is better than GIF in size and speed and features, but if you want to store bitmaps efficiently, I'd suggest: .PNM.BZ2 ([edit]Because of the different packing method, .PNM.BZ2 is not always more efficient than .PNG.[/edit])

PNM/PBM/PGM/PAM are plain bitmap formats with K.I.S.S.-headers in plain text. Using gzip on those will result in a file size similar to PNG, so bzip2 is the better solution for that. If you are going to use bitmaps internally in your program, you might want to use bzip2 compressed bitmaps in a .tar or .zip container. If you don't have bzip2, using PNMs in a zip container (zip with maximum compression) might be similar to using PNGs. – So, storing PNGs in a ZIP file might have only small or no benefit – it would most likely just increase the time to load the image.

Besides that, it is a good choice to store several small sprites/pictures in one bitmap, especially when you need them all in the same situation together.

\$\endgroup\$
2
  • \$\begingroup\$ Is PNM file available and readable to all smartphone OS's and desktop computer OS's? \$\endgroup\$ May 10, 2013 at 2:46
  • 1
    \$\begingroup\$ @David Dimalanta: I don't know where it is supported and where it is not. If you want to program with PNMs, then you rarely want to use any library, because that format is too simple to choose any API. Because of that, it is readable and writeable with all existing programming languages that support reading/writing binary files. Of course you could use Netpbm on any OS, not only Unix. On the other hand, I don't know which general image libraries don't support this. It is not a compressed format, so it is rarely used to store images on disk anyway. see en.wikipedia.org/wiki/Netpbm_format \$\endgroup\$
    – comonad
    May 10, 2013 at 13:33
1
\$\begingroup\$

As storage format JPEG is probably the best choice for some textures like grass or walls, where the loss of information is probably undetectable. Followed by PNG when you need transparency or when you cannot pay with loss of information, for example sprites in a 2D game (the player, enemies, a treasury chest), you probably want to use PNG for that images.

When talking about memory cost, the format used to store game graphics in the file system is not relevant at all. Either if you store pixel buffers in VRAM, or RAM (software renderer), you probably have them stored uncompressed, because games favor fast read of pixels vs memory used by each pixel buffer.

Have compressed data stored in memory have no sense except you maintain some kind of cache to save disk reads, but you probably have to read from that cache to an uncompressed state for the images in use at a given time in your game.

Compressed image data have a bit more sense if fast hardware decoding were possible. For normal mapping at least, I remember this http://en.wikipedia.org/wiki/3Dc. With that you can save some VRAM. I'm not aware of other examples of hardware decoding yet.

In resume: whatever the formats used for your game to store graphics in persistent storage, you will have to decode that and maintain an uncompressed version in dynamic memory, video memory, or both, to be able to fast render them when needed.

Finally: I'm a desktop guy. When I say "memory" I always referring to dynamic memory. When I say "disk", "file system" or "persistent storage" I always referring to whatever your device use as persistent storage, usually I think in hard disks. When you said "memory-efficiency" I took it for "dynamic memory" not "persistent storage". Lately, I see a lot of people using the word "memory" to refer to "persistent storage" (maybe that the terminology of mobile devices?).

\$\endgroup\$
2
  • \$\begingroup\$ Is it possible also that it is not the JPEG nor PNG affects the memory but the file size? \$\endgroup\$ Jan 29, 2015 at 5:59
  • \$\begingroup\$ Yes. You will choose any of the discussed formats thinking in save disk space or bandwidth. When loading images into the game, any library/engine I know will decode them to uncompressed pixel buffers (think in pixel buffers as an array of RGB or RGBA values, where each channel usually occupies 1 Byte in RAM/VRAM if using 32 bits per pixels, that is probably what everyone is doing). \$\endgroup\$ Jan 31, 2015 at 7:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .