NAME

Imager::File::HEIF - read and write HEIF files

SYNOPSIS

use Imager;
# before Imager 1.013 you need to explicitly load this
use Imager::File::HEIF;

my $img = Imager->new;
$img->read(file => "foo.heif")
  or die $img->errstr;

# type won't be necessary if the extension is heif from Imager 1.008
$img->write(file => "foo.heif", type => "heif")
  or die $img->errstr;

DESCRIPTION

Implements .heif file support for Imager.

CLASS METHODS

libversion()
buildversion()
my $lib_version   = Imager::File::HEIF->libversion;
my $build_version = Imager::File::HEIF->buildversion;

Returns the version of libheif, either the version of the library currently being used, or the version that Imager::File::HEIF was built with.

These might differ because the library was updated after Imager::File::HEIF was built.

init()
deinit()
Imager::File::HEIF->init;
Imager::File::HEIF->deinit;

You do not need to call these in normal code.

Initialise or clean up respectively the state of libheif.

These require libheif 1.13.0 or later to have any effect.

Imager::File::HEIF will call these on load and at END time respectively.

In practice libx265 still leaves a lot of memory leaked in my testing.

dump_encoders
Imager::File::HEIF->dump_encoders

Dump information about each encoder configured for libheif to standard output. See the /encoders method for programmatic access.

For example:

265 HEVC encoder (4.1+1-1d117be) (x265):
  Format: hevc
  Lossless: Yes
  Lossy: Yes
  Parameters:
    quality (int): 0 ... 100 (default 50)
    lossless (boolean): (default false)
    preset (str): "ultrafast" "superfast" "veryfast" "faster" "fast" "medium" "slow" "slower" "veryslow" "placebo" (default "slow")
    tune (str): "psnr" "ssim" "grain" "fastdecode" (default "ssim")
    tu-intra-depth (int): 1 ... 4 (default 2)
    complexity (int): 0 ... 100 (default 0)
    chroma (str): "420" "422" "444" (default "420")

The first line for each is a descriptive name of the encoder followed by the identifier for that encoder, which can be supplied as heif_encoder when writing an image.

Format is the compression supported by this encoder.

Lossless reports whether the encoder supports lossless encoding.

Lossy reports whether the encoder supports lossy encoding.

Parameters lists the paremeters supported by this encoder, which can be set when writing.

dump_decoders
Imager::File::HEIF->dump_decoders

Dump information about each encoder. This provides very little information and may list a decoder more than once if it supports more than one (de-)compression.

libde265 HEVC decoder, version 1.0.15 (libde265):
  Format: hevc
FFMPEG HEVC decoder 7.1.3-0+deb13u1 (ffmpeg):
  Format: hevc
libjpeg-turbo 2.1.5 (libjpeg 6.2) (jpeg):
  Format: jpeg
have_decoder_for($compression)
if (Imager::File::HEIF->have_decoder_for("jpeg")) {
  ...

Returns true if libheif supports decoding the given compression type. Throws an exception for a compression type that this version of libheif doesn't support.

have_encoder_for($compression)
if (Imager::File::HEIF->have_encoder_for("jpeg")) {
  ...

Returns true if libheif supports encoding the given compression type. Throws an exception for a compression type that this version of libheif doesn't support.

compression_names

Returns a list of compression names suitable for the have_encoder_for, have_decoder_for and encoders methods, or for the heif_compression write parameter.

This includes the "undefined" (not the perl undef) method only accepted by the "encoders" method.

encoders
encoders($compression)

Returns a list of Imager::File::HEIF::Encoder objects, which provides information about each encoder the libheif Imager::File::HEIF was built against.

If $compression is supplied only decoders supporting that compression are returned. This defaults to "undefined" (not the perl undef) which returns all encoders.

If an unknown compression name is supplied this method will throw an exception.

PATENTS

The h.265 compression libheif uses is covered by patents, if you use this code for commercial purposes you may need to license those patents.

LICENSING

Imager::File::HEIF itself and Imager are licensed under the same terms as Perl itself, and libheif is licensed under the LGPL 3.0.

But libx264, which libheif is typically built to use for encoding, is licensed under the GPL 2.0, and the owners provide a fairly strict interpretation of that license. They also sell commercial licenses.

INSTALLATION

To install Imager::File::HEIF you need Imager installed and you need libheif, libde265 and libx265 and their development files.

Imager::File::HEIF requires at least version 1.11.0 of libheif, but in general you want the very latest version you can get. Imager::File::HEIF has been tested up to version 1.21.2 of libheif.

1.14 through 1.16 need LIBDE265 support installed as part of the library, not as a plugin.

STANDARD IMAGER TAGS

Imager::File::HEIF supports the i_xres and i_yres tags, but only for setting or retrieving the pixel aspect ratio. As generally a photographic or movie format, HEIF doesn't support physical resolution, which is generally a print or scan mechanism.

i_aspect_only is ignored on writing, i_xres and i_yres are treated as an aspect ratio.

When you read a HEIF image i_xres and i_yres are set from the aspect ratio and i_aspect_only is set to 1.

CONTROLLING COMPRESSION

You can control output through a number of tags, (implicitly set on the images via write() or write_multi()):

  • heif_lossless - if non-zero the image is compressed in "lossless" mode. Note that in both lossy and lossless modes the image is converted from the RGB colorspace to the YCbCr colorspace, which will lose information. In lossless mode the heif_quality value is ignored and irrelevant. Default: set by the libheif encoder.

  • heif_quality - a value from 0 to 100 representing the quality of lossy compression. Default: set by the libheif encoder.

  • heif_compression - the compression type to use, this defaults to "hevc". The values supported depend on the version of libheif and how it was built. You can use different compression methods for different images in a multi-image file, but don't be too surprised if readers fail to read it.

    Using a compression other than hevc with the .heif extension may confuse other software.

    Be aware this chooses the compression inside the ISOBMFF file, selecting jpeg compression does not produce a JPEF/JFIF file.

  • heif_encoder - the identifier of the encoder to use, this also sets the compression to use, if you also supply heif_compression and it doesn't match the compression used by this encoder writing will fail. Default: an encoder is selected by libheif based on the compression selected.

Other parameters set by the encoder can also be set by setting a tag with that name with a heif_ prefix. You can see a list of parameters for each encoder using the dump_encoders() method, or by calling the parameters() method on the encoder object returned by the encoders() method.

So you can set the chroma with the heif_chroma tag:

$img->write(..., heif_chroma => "444")...

Parameter names can contain dashes and these are reflected in the tag names:

# from the AOM AV1 encoder
$img->write(..., "heif_alpha-quality" => 80) ...

If the encoder has quality or lossless parameters those are handled by their dedicated APIs, not via the general "parameter" API.

If setting such a parameter fails, writing will fail.

Unfortunately the only way to see if the parameter was recognized is to enable logging and examine the log.

WARNING: from my testing, using the rough measure done by Imager i_img_diff(), lossy at 80 quality turned out closer to the original image than lossless.

RESOURCE USAGE

HEIF processing is fairly resource intensive, and libheif uses multiple decoding threads by default when you read a HEIF image.

With libheif 1.13.0 or later you can set $Imager::File::HEIF::MaxThreads to the maximum number of threads to use. If this is negative or not defined the default is used, which is defined by libheif.

BUGS

Imager::File::HEIF have_decoder_for() returns false for av1 before libheif 1.13, neither Imager::File::HEIF nor the libheif tools were able to decode av1 encoded files created by the libheif tool, even with av1 support enabled in libheif.

TODO

  • 10-bit/sample and 12-bit/sample images. Based on https://github.com/strukturag/libheif/issues/40 this might not be supported completely yet.

  • reading metadata (any to read?)

  • writing metadata. We don't seem to have the animation metadata that webp does. (image sequences seems to have it)

  • reading sub-image data? we can probably skip thumbs (or provide an option to read the thumb rather than the main image), but are there other images to read? Depth images. Low priority.

  • writing sub-image data? thumbnails and depth images. Very low priority.

  • Everything else.

GLOSSARY

ISOBMFF

ISO Base Media File Format - the container file format defined by ISO/IEC 14496-12 used by HEIF, AVIF, JPEG2000 and many non-image formats. See https://en.wikipedia.org/wiki/ISO_base_media_file_format.

AUTHOR

Tony Cook <tony@develop-help.com>

SEE ALSO

Imager, Imager::Files.

https://en.wikipedia.org/wiki/High_Efficiency_Image_File_Format

https://github.com/strukturag/libheif

https://github.com/strukturag/libde265 - x265 decoder

https://www.x265.org/ - x265 encoder