Save for Roblox - Please, Optimize Your PNGs!

TL:DR

  • Optimize your in-game PNGs! Here’s some tools but there’s more out there:
    • PNGquant - Lossy (you won’t notice), ~60% size reduction
      • Don’t forget to manually update the pngquanti.exe if you picked PNGoo
  • OptiPNG - Lossless (Doesn’t work, roblox messes it up), 10~30% size reduction

  • TinyPNG - Lossy (you won’t notice), ~70-80% size reduction; it’s a web service though
  • ECT - Lossless or lossy on demand, size reduction varies accordingly
  • File → Save for Web, File → Export
  • Don’t optimize images with colored fully transparent pixels
  • You should upload your ads as jpegs to avoid recompression

It’s the future!

But your players might suffer from awful internet. They shouldn’t have to wait for your images to slowly pop in one at a time. You can make the player sit and wait for PreloadAsync to finish, but that doesn’t actually solve the problem; it still takes a while. I mean it took like five seconds for the bloxcards logo to show up on public wifi. Also when I played the dancing section of the minion obby by shovelware studios the DDR arrows took a while to load so I couldn’t see anything. :frowning:

Sure But Does Asset Size Matter

Yes, small files take shorter to download than large files. You need your thumbnails, skins, logos, buttons, etc. to load as fast as possible, ergo they must be as small as possible. For reference, you probably already know how to optimize your meshes and sounds. Nobody uploads uncompressed wavs in this future, but uncompressed 250kb 1024×1024px PNGs aren’t great either. Your players do deserve the highest fidelity graphics though, so downscaling is probably not the way to go.

What Can I Do

You can optimize/compress the PNGs, getting a lower filesize in exchange for either metadata/guff (“lossless”) or color depth (“lossy”). With lossy compression, the resulting dithering and color banding (if any) will be filtered out by either your eyeballs or anti-aliasing, but harsh gradients’ dither might be visible to the naked eye on unscaled gui elements under certain conditions or amidst certain colors. Also, fully transparent pixels almost always lose their color.

Basically: don’t worry about the loss of color depth. You’ll never notice any of this on 3D models and you can just check if you’d notice on (un)scaled gui elements. Most of your assets are probably flat, sleek and/or modern; they won’t show any artifacts at all.

For Example: A BloxCards Logo

Before (123kb):


After (45kb):

Diff:

What Can I use

PNGquant (My Personal Favorite)

Installation:

  1. Download the one with the nicest sounding description.
  2. Optional: Replace its outdated copy of PNGquant with the latest binary release. PNGoo in particular has a 5 year old build of pngquant. Replace the old exe with the new one and it’ll work fine.

Usage: Like you would any other program. You can drag&drop your PNGs into either the window or the .exe because it’s the future.

OptiPNG (doesn’t actually work, see Anaminus’ post)

Usage: Either via the command line or just drag the PNGs into the exe and it’ll replace (!!!) them with an optimized version.

TinyPNG

Usage: Follow the instructions on the site. You can optimize only 20 PNGs at a time though, and it’s a web service.

ECT

Installation: Just like build it from source.
Usage: Via the command line.

Save for Web

Your professional image editing software probably offers a Save for Web option in the File menu. Alternatively there’s probably an Export option. This is specific to your software of choice, I don’t know. It’s probably really good! But do check if there’s a plugin of any of the above availible, it’ll do a better job.

Any Other Program That Does The Same Thing There’s A Lot More

52 Likes

Thank you for this tutorial!! I will definitely use this in the future.

Last I checked, Roblox re-encodes PNGs (presumably to remove embedded data), so optimizing them yourself doesn’t actually help.

2 Likes

I’m very sure it doesn’t re-encode my PNGs as I’ve downloaded my optimized PNGs back off the site unchanged:
34ae091a236a88c2a5d64f47962b39bf9eb8e6c9.jpg

1 Like

I uploaded this image (512x512, red pixels, optimized with optipng).
Then downloaded the resulting asset (this image).
Then compared them.

$ sha1sum red.png 4ce30bda1761e0d9b0951123272f32d1.png
7b28105352a08bfe2c429ae8ac3ec3c69b8a398f *red.png
12e9e6ef3e27776c92ffa431d27d18de6d5cdfd4 *4ce30bda1761e0d9b0951123272f32d1.png

$ stat -c "%s bytes, %n" red.png 4ce30bda1761e0d9b0951123272f32d1.png
126 bytes, red.png
221 bytes, 4ce30bda1761e0d9b0951123272f32d1.png
3 Likes

Fair enough. My test image was compressed using pngquant, so this means that the lossless approach doesn’t work. Here’s my test image’s asset (this image) and the image I uploaded.

Actually I just realized that the downloaded png is larger than the size firefox told me it’d be (resp. 6.6kb and 5.9kb). I think the next step is finding out what size the png is when it’s transferred compared to when it’s stored on disk. The former is key here.

In my defense, otherwise identical images with different compression do net different (34.6kb) filesizes (50.3kb). So there’s no re-encoding of the actual png happening, just the metadata like you said.

Weirdly enough, in the image you uploaded, ROBLOX added metadata chunks. The IDAT chunk (the actual image data) is different in the input and output files, but it’s the same size in both (0x36 bytes).

Hex dumps
~> % curl https://devforum.roblox.com/uploads/[...] | xxd
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR
00000010: 0000 0200 0000 0200 0103 0000 00ce b646  ...............F
00000020: b900 0000 0350 4c54 45ff 0000 19e2 0937  .....PLTE......7
00000030: 0000 0036 4944 4154 1819 edc1 0101 0000  ...6IDAT........
00000040: 0082 a0fe af76 48c0 0000 0000 0000 0000  .....vH.........
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 ce05 8200 0001 b507  ................
00000070: 6aae 0000 0000 4945 4e44 ae42 6082       j.....IEND.B`.
~> % curl https://c2.rbxcdn.com/4ce30bda1761e0d9b0951123272f32d1 | xxd
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR
00000010: 0000 0200 0000 0200 0103 0000 00ce b646  ...............F
00000020: b900 0000 0467 414d 4100 00b1 8f0b fc61  .....gAMA......a
00000030: 0500 0000 2063 4852 4d00 007a 2600 0080  .... cHRM..z&...
00000040: 8400 00fa 0000 0080 e800 0075 3000 00ea  ...........u0...
00000050: 6000 003a 9800 0017 709c ba51 3c00 0000  `..:....p..Q<...
00000060: 0650 4c54 45ff 0000 ffff ff41 1d34 1100  .PLTE......A.4..
00000070: 0000 0162 4b47 4401 ff02 2dde 0000 0007  ...bKGD...-.....
00000080: 7449 4d45 07e1 0704 133a 23b5 209b e200  tIME.....:#. ...
00000090: 0000 3649 4441 5478 daed c101 0100 0000  ..6IDATx........
000000a0: 8220 ffaf 6e48 4001 0000 0000 0000 0000  . ..nH@.........
000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000000c0: 0000 0000 0000 007c 1b82 0000 0163 7550  .......|.....cuP
000000d0: a400 0000 0049 454e 44ae 4260 82         .....IEND.B`.

If you think I’m giving up a single one of my crispy pixels then you are gravely misstaken sir.
Thank you. Good day!

12 Likes

If only ROBLOX streamed lower resolution versions of images automatically on bad connections / mobile devices…

1 Like

That is really not a good idea. If I make a logo in a certain resolution with a certain artistic view then I wish that every single device will get exactly the same image.

2 Likes

They better not, imagine if I have a 1024x1024 spritesheet with a bunch of small icons, and Roblox starts scaling that down and my small icons become smudges instead of being crisp

2 Likes

A toggle could easily fix both of your problems. I’d much rather see a pixelated version of an icon then no icon at all on really bad connections.

3 Likes

It would be interesting to first see the horrible quality version, then as you play it downloads the full resolution version.

I believe they call this streaming?

5 Likes

You’re thinking of interlacing.

5 Likes