0
$\begingroup$

Because scaling operations are prohibitively expensive in my current rendering stack, I have to pre-render my images in all desired sizes and cache the result on disk. At the moment, I do this by dumping one PNG file per image size. However, this gets fairly large quickly and I'd like to know whether there is a possibility to take advantage of the fact that all these images are basically showing the same content.

$\endgroup$
1
  • $\begingroup$ Is there a PNG compression scheme that allows block compression? $\endgroup$
    – pmw1234
    Aug 5, 2021 at 13:27

2 Answers 2

1
$\begingroup$

However, this gets fairly large quickly and I'd like to know whether there is a possibility to take advantage of the fact that all these images are basically showing the same content.

There is. It's called... scaling the largest mipmap to produce the smaller ones. That's essentially what's happening when you generate mipmaps directly: you are "compressing" the lower mipmaps by taking advantage of the fact that all these images are algorithmically built from the largest mipmap. Since you only store the largest mipmap, the other mipmaps take up zero bytes. Then you "decompress" them by scaling them as they are loaded.

The principle cost of CPU scaling is not the computation of the lower-mipmap level itself. It's the memory bandwidth costs of reading from the higher mipmap and writing to the lower one. It doesn't really matter what your algorithm for computing the lower one is; if it requires reading every pixel of the higher mipmap, it's basically going to cost the same thing.

If you've got access to a GPU, you ought to be able to scale it there with rendering operations or even just linearly-interpolated blitting operations.

$\endgroup$
2
  • $\begingroup$ As far as I can tell, the main cost of scaling is the interpolation (note that hardware acceleration sadly is not available to me). If I understand your proposal correctly, it would use nearest interpolation by selecting the correct pixels, which is not okay in my case. $\endgroup$
    – piegames
    Jul 5, 2021 at 22:44
  • 1
    $\begingroup$ @piegames: "the main cost of scaling is the interpolation" How did you make that determination? Your CPU either is extremely old (and thus closer to your memory bandwidth) or your code is highly unoptimized, doing things like int-to-float conversions and the like. Box filter scaling ought to be a few shifts and multiplies, nothing remotely like the thousands-of-cycle cost of a cache miss. $\endgroup$ Jul 5, 2021 at 22:55
0
$\begingroup$

You could look into wavelet image compression, which effectively stores a mip pyramid "top down" with each level storing only the diffs from the next-smaller level. This would effectively let you reconstruct whichever mip level you wanted from the same file at load time, with the file being the same overall size as only the base mip. However, it is likely more expensive to decompress than PNG for the same reason.

The JPEG2000 format implements a wavelet compression method (as well as quantization and bitstream coding like other JPEG formats). I'm not sure if there are JPEG2000 libraries that support efficiently reconstructing multiple resolutions of the image while loading though.

$\endgroup$
2
  • $\begingroup$ PNG is going to be smaller than most BC formats, not bigger. The advantage of BC formats is that GPUs can read them directly, without decompression. $\endgroup$ Jul 5, 2021 at 17:47
  • $\begingroup$ Storing only difference to the next higher level is an interesting idea. Maybe it can somehow be done on a pixel level instead of wavelets? Of course, this wouldn't save any pixels, but maybe they'd then contain less information and thus be better compressed by png? $\endgroup$
    – piegames
    Jul 5, 2021 at 22:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.