strukturag / libheif

libheif is an HEIF and AVIF file format decoder and encoder.
Other
1.74k stars 301 forks source link

heif-enc output is 4x bigger than equivalent macOS Finder output #1266

Open trevor-e opened 2 months ago

trevor-e commented 2 months ago

Hello,

This is related to an issue I opened in another project (https://github.com/lovell/sharp/issues/4182) but seemed more relevant here since I'm able to reproduce this with heif-enc.

Basically, I'm trying to convert PNG images to HEIC and am finding the output to be much bigger than expected. For example, testing this command: heif-enc -q 85 -C average input.png -o output.heic produces a 736KB HEIC. However, if I take the same input image in Apple's Finder tool with 85 quality and export to HEIC, the result is much smaller at 168KB. This is a pretty drastic difference in compression size.

I've zipped and included all the images I'm testing with. Archive.zip

farindk commented 2 months ago

The quality settings are not comparable. 85 in libheif is not 85 in macOS. You need to find a compression setting that gives comparable output quality. That depends a lot on the encoder plugin used.

trevor-e commented 2 months ago

Thanks for the response. I believe I've been using libde265 for encoding, although looking at that project description now I'm not so sure since it only mentions decoding.

If you have any sensible defaults you can share for this that would be greatly appreciated, otherwise I will do some tinkering. Having the default file size generated by this tool be much smaller would be a great win.

trevor-e commented 2 months ago

Attempting to figure out my exact encoder being used:

➜  heic-test git:(master) ✗ heif-enc --list-encoders
HEIC encoders:
- x265 = x265 HEVC encoder (3.5+1-f0c1022b6) [default]
AVIF encoders:
- aom = AOMedia Project AV1 Encoder 3.9.1 [default]
VVIC encoders:
JPEG encoders:
JPEG 2000 encoders:
HT-J2K encoders:
farindk commented 2 months ago

libde265 is the decoder. You are probably using the x265 encoder.

trevor-e commented 2 months ago

Some interesting findings for anyone new to this world like me:

➜  heic-test git:(master) ✗ otool -L /opt/homebrew/bin/heif-enc
/opt/homebrew/bin/heif-enc:
    @rpath/libheif.1.dylib (compatibility version 17.0.0, current version 1.18.1)
    /opt/homebrew/opt/jpeg-turbo/lib/libjpeg.8.dylib (compatibility version 8.0.0, current version 8.3.2)
    /opt/homebrew/opt/libpng/lib/libpng16.16.dylib (compatibility version 60.0.0, current version 60.0.0)
    /opt/homebrew/opt/libtiff/lib/libtiff.6.dylib (compatibility version 7.0.0, current version 7.2.0)
    /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.12)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1700.255.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)

➜  heic-test git:(master) ✗ otool -L /opt/homebrew/lib/libheif.1.dylib
/opt/homebrew/lib/libheif.1.dylib:
    /opt/homebrew/opt/libheif/lib/libheif.1.dylib (compatibility version 17.0.0, current version 1.18.1)
    /opt/homebrew/opt/x265/lib/libx265.209.dylib (compatibility version 209.0.0, current version 209.0.0)
    /opt/homebrew/opt/libde265/lib/libde265.0.dylib (compatibility version 2.0.0, current version 2.8.0)
    /opt/homebrew/opt/aom/lib/libaom.3.dylib (compatibility version 3.0.0, current version 3.9.1)
    /opt/homebrew/opt/webp/lib/libsharpyuv.0.dylib (compatibility version 2.0.0, current version 2.0.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1700.255.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)

➜  heic-test git:(master) ✗ x265 --version
x265 [info]: HEVC encoder version 3.5+1-f0c1022b6

So I am using x265 as you suggested. Looking through the x265 options, an obvious one stood out to me:

heif-enc input.png -o output.heic -p preset=slow

simply setting it to use a slow performance preset gave me an image that's only 123KB, already smaller than Finder, and visually looks OK to me. Although interestingly if I set the -q 85 flag it doesn't seem to work and goes back to the 743KB size.

silverbacknet commented 2 months ago

That would be because the default x265 quality is 50. (Which maps to crf 25 in x265 itself.) Which may or may not be similar to Apple's quality 85 or 80 or whatever gets it to the same size, you'd have to actually view the file to figure that out.

The default x265 preset is already "slow". All you did was accidentally change the q.

(Side note: Apple will always be faster than libheif, at least for heic itself, since it's using hardware encoding on the Mx chip to do it instead of software.)

trevor-e commented 2 months ago

Thanks, you're right about that 🤦, although the x265 docs appear to be wrong:

-p/--preset <string>             Trade off performance for compression efficiency. Default medium

edit: oh you mean the libheif default for x265's preset

silverbacknet commented 2 months ago

That's x265's default, libheif sets its own defaults. OK, I admit it was confusing the way I put it, I should have said x265 plugin.

lovell commented 2 months ago

There may be some additional confusion here around controlling "how much CPU effort" an encoder should use. Many/most of libheif's encoders provide an integral speed parameter mapped to a relevant setting of their underlying library, however the x265 encoder differs slightly by providing a string-based preset parameter.

When encoding images via libheif, libvips currently exposes control over speed only (named effort to ensure consistency across all encoders, not just HEIF-based) and assumes that libheif will map speed onto something sensible. Is this still the right approach?