Pillow Plugin — pillow-heif 0.21.0 documentation

# Pillow Plugin

For using it as a Pillow plugin, refer to Pillow’s documentation: Pillow Tutorial and to examples started with `pillow_`.

Here are described only some differences and peculiarities.

## Registering plugin

There are two ways to register it as a plugin, here are both of them:

### Automatic

    from PIL import Image, ImageFilter
    from pillow_heif import HeifImagePlugin

    with Image.open("image.heic") as im:
        im.filter(filter=ImageFilter.BLUR).save("blurred_image.heic")

### Manual

    from PIL import Image
    from pillow_heif import register_heif_opener

    register_heif_opener()
    with Image.open("image.heic") as im:
        im.rotate(45).save("rotated_image.heic")

### AVIF plugin

`AVIF` plugin can be registered the same way as `HEIF`:

    from pillow_heif import register_avif_opener

    register_avif_opener()

`AVIF` plugin should support all operations and work the same way as `HEIF` plugin do.

### Tips & Tricks

If you do not need HEIF thumbnails functionality, then it is a good idea to disable them during plugin registration:

    register_heif_opener(thumbnails=False)

Remember, then you can pass multiply config values to `register_heif_opener()` at once:

    register_heif_opener(thumbnails=False, quality=-1)

Note

`register_avif_opener()` works in the same way.

## Image Modes

Currently all images are opened in `RGB` or `RGBA` 8 bit modes. There is a restriction in `libheif` that we cant check before decoding if an image is `monochrome` or not.

See Modes for a list of supported modes for saving.

## Metadata

Available metadata are stored in `info` dictionary as in other Pillow plugins.

It is the same as in `HeifImage` class.

During saving operation all known metadata in `info` dictionary are saved. So it can be edited in place.

Removing EXIF and XMP information inside `info` dictionary:

    image = Image.open(Path("test.heic"))
    del image.info["exif"]
    del image.info["xmp"]
    image.save("output.heic")

Removing EXIF and XMP specifying them when calling `save`:

    image = Image.open(Path("test.heic"))
    image.save("output.heic", exif=None, xmp=None)

Limitations of second code variant is that when file has multiply images inside, setting `exif` or `xmp` during `save` affects only Primary(Main) image and not all images.

To edit metadata of all images in a file just iterate throw all images and change metadata in place.

Here are two ways as an example:

Edit `info["exif"]` field of each copy of image:

    heic_pillow = Image.open(Path("test.heic"))
    output_wo_exif = []
    for frame in ImageSequence.Iterator(heic_pillow):
        copied_frame = frame.copy()
        copied_frame.info["exif"] = None
        output_wo_exif.append(copied_frame)
    empty_pillow = Image.new("P", (0, 0))
    empty_pillow.save("no_exif.heic", save_all=True, append_images=output_wo_exif)

Or editing `info["exif"]` in place:

    heic_pillow = Image.open(Path("test.heic"))
    for frame in ImageSequence.Iterator(heic_pillow):
        frame.info["exif"] = None
    heic_pillow.save("no_exif.heic", save_all=True)

## Save operation

For HEIF next extensions are registered: `.heic`, `.heics`, `.heif`, `.heifs` and `.hif`

For AVIF registered extensions are: `.avif`

Also images can be saved to memory, using `format` parameter:

    output_buffer = BytesIO()
    with Image.open("image.heic") as im:
        im.save(output_buffer, format="HEIF")

See here Save parameters for additional information.

## Changing order of images

There is no such easy way to change order as for HeifFile usage, but the standard Pillow way to do so looks fine. Let’s create image where second image will be primary:

    img1 = Image.open(Path("images/jpeg_gif_png/1.png"))
    img2 = Image.open(Path("images/jpeg_gif_png/2.png"))
    img3 = Image.open(Path("images/jpeg_gif_png/3.png"))
    img1.save("1_2P_3.heic", append_images=[img2, img3], save_all=True, primary_index=1, quality=-1)

Now as example lets change primary image in a HEIC file:

    img1 = Image.open(Path("1_2P_3.heic"))
    img1.save("1_2_3P.heic", save_all=True, primary_index=-1, quality=-1)

Note

As a `primary` field are in info dictionary, you can change it in a place like with metadata before.

And here is an example how we can change order of images in container:

    src_img = Image.open(Path("1_2_3P.heic"))
    img3 = ImageSequence.Iterator(src_img)[2].copy()
    img2 = ImageSequence.Iterator(src_img)[1].copy()
    img1 = ImageSequence.Iterator(src_img)[0].copy()
    img3.save("3P_1_2.heic", save_all=True, append_images=[img1, img2], quality=-1)