Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow original image if new content-length is larger than origin content length #1254

Open
lucasRolff opened this issue Mar 9, 2024 · 8 comments

Comments

@lucasRolff
Copy link

I've observed that sometimes images processed by imgproxy without any special processing logic (blur, resize, watermark etc), may turn out larger than the origin file, if source/result is the same (e.g. source is jpg and requested format is jpg).

With the (default) compression settings, it may be that the processed image may become bigger than the original when nothing has been done other than the image running through imgproxy (processing_options="Format: jpeg" or processing_options="Format: png"), in some cases I see images grow by up to 30% in size.

It would be awesome if we could have a kind of flag to allow returning the original image if the filesize of the original is smaller than the processed one, when no special processing options has been passed (that effectively changes the dimensions, blur, watermark etc).

I'm aware of the skip_processing / skp flag that exists to bypass the processing entirely, but this on the other hand does not account for cases where the compression processing could lead to decreased file sizes by the compression settings.

So having a flag that would evaluate the file size before and after processing and then decide to serve the smaller file when the source and resulting file types are the same (jpg -> jpg, png -> png, gif -> gif).

@divaltor
Copy link

I found the same issue with images in PNG format -> PNG format with compression (q:0 preset and format_quality: png=75). Original image is ~640 KB, compressed by imgproxy results in ~680 KB somehow and I can't understand why.

Would be nice if someone could describe that behavior, because it's kinda weird to see compressed image larger than original image

@DarthSim
Copy link
Member

Hey everyone,

Well, we have two options here:

  1. Add a processing option that will enable the fallback to the original image no matter what. It will be the caller's responsibility to decide if they want the fallback (i.e. use that processing option only when the resizing option is not used).
  2. Change every processing step so it indicates if it actually changed the image.

Anyway, PRs are always welcome 😉

Would be nice if someone could describe that behavior, because it's kinda weird to see compressed image larger than original image

Unless the original is BMP or something like that, it is compressed too. The size may increase for various reasons. In the case of JPEG, the original may be saved with lower quality than you set for imgproxy. In the case of PNG, it may be saved with a higher level of compression than imgproxy uses. imgproxy uses compression level 6 for PNGs as it is a good compromise between speed and the resulting size. Higher levels of compression dramatically slow encoding. However, having a config for this would be nice, I guess.

@divaltor
Copy link

divaltor commented Mar 21, 2024

In the case of JPEG, the original may be saved with lower quality than you set for imgproxy. In the case of PNG, it may be saved with a higher level of compression than imgproxy uses. imgproxy uses compression level 6 for PNGs as it is a good compromise between speed and the resulting size.

I don't undestand it very well, but even if we imagine that we send already compressed images (I can guarantee that we don't) how imgproxy actually "restore" information for compressed image and return a file larger than we pass to imgproxy? Otherwise I can't describe what's happening in that case

100% quality of image -> q:85 -> 85%

85% quality of image -> q:85 -> 85*0.85 -> 72.25%

I can't see a case when we get a better image than we provide to imgproxy

UPD: I even tried to compare images with PSNR, but it showed me that images are equal (when I used q:0 preset with config formatQuality: png=75)

@lucasRolff
Copy link
Author

  1. Add a processing option that will enable the fallback to the original image no matter what. It will be the caller's responsibility to decide if they want the fallback (i.e. use that processing option only when the resizing option is not used).

But isn't that just skp? Or are you thinking the processing option would do the fallback to the original image only if the size of the "processed" one is larger?

  1. Change every processing step so it indicates if it actually changed the image.

At least from my POV, what I'm after boils down to that not every image will have some kind of resize/blur/watermark/etc processing done, but may still utilize webp/avif processing, but if e.g. the client does not support webp or avif, one would usually want to deliver in the original format (png -> png, gif -> gif, jpeg -> jpeg for example), but if we end up with larger images we only made the experience worse for the user.

That's why I'd love a "flag" to say, if processed image is larger, then use the original.

I'd love to do the PR if I had any sense of Go experience 😅

@DarthSim
Copy link
Member

But isn't that just skp? Or are you thinking the processing option would do the fallback to the original image only if the size of the "processed" one is larger?

Yup, this is what I was talking about.

I'd love to do the PR if I had any sense of Go experience 😅

Neither did I a few years ago 🙂 I mean, I could do this myself, but I can't give you any estimations on when this will be done.

@DarthSim
Copy link
Member

@divaltor

even if we imagine that we send already compressed images (I can guarantee that we don't)

I can guarantee that you do. Only a few image formats like BMP or ICO (and very rarely – TIFF) store image data uncompressed.

100% quality of image -> q:85 -> 85%
85% quality of image -> q:85 -> 85*0.85 -> 72.25%

This is not how image compression works.

First of all, PNG does not have a quality factor since it is a lossless format (unless it is a paletted PNG). Yet it can be saved with different compression levels. As I said before, imgproxy doesn't use the maximum compression level for performance reasons.

But formats like JPEG do lossy compression. I won't describe the whole JPEG compression algorithm here, but the most important part is that it does discrete cosine transform (DCT) and removes some data according to the quantization table. When imgproxy (or any other image processing tool) needs to process an image, it decodes it to raw pixels and encodes it back in the end. If you encode it with a larger quality factor, less data will be discarded, and thus file size will be larger. You can ask: "How it can discard less data that was discarded during the initial encoding?" The thing is that the result of DCT will be different as raw pixels are changed.

@divaltor
Copy link

Thanks for the describing the de-encoding process, I'll test then a few more times with different presets to ensure that problem is not on imgproxy side

@lucasRolff
Copy link
Author

but I can't give you any estimations on when this will be done.

No worries at all! I just thought it would be an overall nice improvement

I'll likely buy the pro version in the coming days regardless for the more intelligent optimization logic it has, and hope it can help a bit anyway (among some other cool features that I would love to utilize)

Thank you for an amazing piece of software regardless!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants