How to work with HEIC image file types in Python

45,680

Solution 1

You guys should check out this library, it's a Python 3 wrapper to the libheif library, it should serve your purpose of file conversion, extracting metadata:

https://github.com/david-poirier-csn/pyheif

https://pypi.org/project/pyheif/

Example usage:

 import io

 import whatimage
 import pyheif
 from PIL import Image


 def decodeImage(bytesIo):

    fmt = whatimage.identify_image(bytesIo)
    if fmt in ['heic', 'avif']:
         i = pyheif.read_heif(bytesIo)

         # Extract metadata etc
         for metadata in i.metadata or []:
             if metadata['type']=='Exif':
                 # do whatever
        
         # Convert to other file format like jpeg
         s = io.BytesIO()
         pi = Image.frombytes(
                mode=i.mode, size=i.size, data=i.data)

         pi.save(s, format="jpeg")

  ...

Solution 2

I was quite successful with Wand package : Install Wand: https://docs.wand-py.org/en/0.6.4/ Code for conversion:

   from wand.image import Image
   import os

   SourceFolder="K:/HeicFolder"
   TargetFolder="K:/JpgFolder"

   for file in os.listdir(SourceFolder):
      SourceFile=SourceFolder + "/" + file
      TargetFile=TargetFolder + "/" + file.replace(".HEIC",".JPG")
    
      img=Image(filename=SourceFile)
      img.format='jpg'
      img.save(filename=TargetFile)
      img.close()

Solution 3

Adding to the answer by danial, i just had to modify the byte array slighly to get a valid datastream for further work. The first 6 bytes are 'Exif\x00\x00' .. dropping these will give you a raw format that you can pipe into any image processing tool.

import pyheif
import PIL
import exifread

def read_heic(path: str):
    with open(path, 'rb') as file:
        image = pyheif.read_heif(file)
        for metadata in image.metadata or []:
            if metadata['type'] == 'Exif':
                fstream = io.BytesIO(metadata['data'][6:])

    # now just convert to jpeg
    pi = PIL.Image.open(fstream)
    pi.save("file.jpg", "JPEG")

    # or do EXIF processing with exifread
    tags = exifread.process_file(fstream)

At least this worked for me.

Solution 4

You can use the pillow_heif library to read HEIF images in a way compatible with PIL.

The example below will import a HEIF picture and save it in png format.

from PIL import Image
import pillow_heif

heif_file = pillow_heif.read_heif("HEIC_file.HEIC")
image = Image.frombytes(
    heif_file.mode,
    heif_file.size,
    heif_file.data,
    "raw",
)

image.save("./picture_name.png", format="png")
    

Solution 5

This will do go get the exif data from the heic file

import pyheif
import exifread
import io

heif_file = pyheif.read_heif("file.heic")

for metadata in heif_file.metadata:

    if metadata['type'] == 'Exif':
        fstream = io.BytesIO(metadata['data'][6:])

    exifdata = exifread.process_file(fstream,details=False)

    # example to get device model from heic file
    model = str(exifdata.get("Image Model"))
    print(model)
Share:
45,680
j12y
Author by

j12y

**Sr. Manager, Developer Relations, Dolby Laboratories Robot Garden, Maker Previously HERE, GE, Rackspace, DreamWorks Animation, MathWorks, Carnegie Mellon

Updated on July 09, 2022

Comments

  • j12y
    j12y almost 2 years

    The High Efficiency Image File (HEIF) format is the default when airdropping an image from an iPhone to a OSX device. I want to edit and modify these .HEIC files with Python.

    I could modify phone settings to save as JPG by default but that doesn't really solve the problem of being able to work with the filetype from others. I still want to be able to process HEIC files for doing file conversion, extracting metadata, etc. (Example Use Case -- Geocoding)

    Pillow

    Here is the result of working with Python 3.7 and Pillow when trying to read a file of this type.

    $ ipython
    Python 3.7.0 (default, Oct  2 2018, 09:20:07)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: from PIL import Image
    
    In [2]: img = Image.open('IMG_2292.HEIC')
    ---------------------------------------------------------------------------
    OSError                                   Traceback (most recent call last)
    <ipython-input-2-fe47106ce80b> in <module>
    ----> 1 img = Image.open('IMG_2292.HEIC')
    
    ~/.env/py3/lib/python3.7/site-packages/PIL/Image.py in open(fp, mode)
       2685         warnings.warn(message)
       2686     raise IOError("cannot identify image file %r"
    -> 2687                   % (filename if filename else fp))
       2688
       2689 #
    
    OSError: cannot identify image file 'IMG_2292.HEIC'
    

    It looks like support in python-pillow was requested (#2806) but there are licensing / patent issues preventing it there.

    ImageMagick + Wand

    It appears that ImageMagick may be an option. After doing a brew install imagemagick and pip install wand however I was unsuccessful.

    $ ipython
    Python 3.7.0 (default, Oct  2 2018, 09:20:07)
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.2.0 -- An enhanced Interactive Python. Type '?' for help.
    
    In [1]: from wand.image import Image
    
    In [2]: with Image(filename='img.jpg') as img:
       ...:     print(img.size)
       ...:
    (4032, 3024)
    
    In [3]: with Image(filename='img.HEIC') as img:
       ...:     print(img.size)
       ...:
    ---------------------------------------------------------------------------
    MissingDelegateError                      Traceback (most recent call last)
    <ipython-input-3-9d6f58c40f95> in <module>
    ----> 1 with Image(filename='ces2.HEIC') as img:
          2     print(img.size)
          3
    
    ~/.env/py3/lib/python3.7/site-packages/wand/image.py in __init__(self, image, blob, file, filename, format, width, height, depth, background, resolution, pseudo)
       4603                     self.read(blob=blob, resolution=resolution)
       4604                 elif filename is not None:
    -> 4605                     self.read(filename=filename, resolution=resolution)
       4606                 # clear the wand format, otherwise any subsequent call to
       4607                 # MagickGetImageBlob will silently change the image to this
    
    ~/.env/py3/lib/python3.7/site-packages/wand/image.py in read(self, file, filename, blob, resolution)
       4894             r = library.MagickReadImage(self.wand, filename)
       4895         if not r:
    -> 4896             self.raise_exception()
       4897
       4898     def save(self, file=None, filename=None):
    
    ~/.env/py3/lib/python3.7/site-packages/wand/resource.py in raise_exception(self, stacklevel)
        220             warnings.warn(e, stacklevel=stacklevel + 1)
        221         elif isinstance(e, Exception):
    --> 222             raise e
        223
        224     def __enter__(self):
    
    MissingDelegateError: no decode delegate for this image format `HEIC' @ error/constitute.c/ReadImage/556
    

    Any other alternatives available to do a conversion programmatically?

    • j12y
      j12y over 5 years
      Similarly Sindre Sorhus has an excellent HEIC Converter to generate JPEG or PNG images but not the flexibility I'm looking for. sindresorhus.com/heic-converter
    • buzjwa
      buzjwa about 5 years
      ExifTool provides a CLI for working with image metadata and supports HEIF. Should be easy to wrap in Python.
    • Mark Setchell
      Mark Setchell over 4 years
  • Norm
    Norm over 4 years
    My experience with pyheif is that it successfully reads HEIC files, but I don't understand how or why Image.frombytes() is supposed to work in the code above. Wouldn't that require PIL to understand HEIF? In any event, what I get is a badly corrupted JPG file when I run it.
  • Cigogne  Eveillée
    Cigogne Eveillée over 4 years
    read_heif required actual data, so the line should actually be: pyheif.read_heif(bytesIo.read())
  • user9074332
    user9074332 over 4 years
    can you give some examples of the do whatever? metadata['data'] here appears to be of type bytes. But when I attempt to: metadata['data'].decode('utf-8')), I see: UnicodeDecodeError: 'utf-8' codec can't decode byte 0x86 in position 27: invalid start byte
  • Tropicalrambler
    Tropicalrambler over 4 years
    Thank you for this Mark, it will prove useful.
  • Zhang18
    Zhang18 about 4 years
    fwiw, I tried to install pyheif on windows and ran into this issue. Turns out pyheif is not compatible with Windows.
  • Josh Clark
    Josh Clark over 3 years
    Using your code, when I pass an HEIC file path I get PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x109aefef0>.
  • M-Chen-3
    M-Chen-3 over 3 years
    Please explain what your code does and how it does it.
  • d1p3
    d1p3 over 3 years
    This is a simple solution using multiple libraries. It basically opens each .heic file inside the same folder as the ".py" file and converts to jpg. Did you mean code explanation?
  • M-Chen-3
    M-Chen-3 over 3 years
    Yes, every answer should explain how the code works.
  • Rodriguez
    Rodriguez over 3 years
    It seems ImageMagick (low level lib used by Wand) does not support heic delegate in some distro's package manager out of the box (eg: Centos 8).
  • pedroprates
    pedroprates almost 3 years
    Had the same problem as Josh, PIL is unable to identify the HEIC image with this code
  • AlvaroFG
    AlvaroFG almost 3 years
    Thanks!, this worked for me as I couldn't get pyheif to work in windows 10.
  • mara004
    mara004 over 2 years
    Your code has invalid indentation. Please correct your example so that it is actually testable.
  • Gerald Zehetner
    Gerald Zehetner over 2 years
    This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review
  • Alexander Piskun
    Alexander Piskun about 2 years
    I know that it is not an answer, but here are examples and documentation: pillow-heif-docs From now work with heif,heic and hif files in python as simple as with all other images using Pillow, i done my best.