如何在Python中使用HEIC图像文件类型

时间:2019-01-28 04:55:37

标签: python python-3.x heif heic

将图像从iPhone空投到OSX设备时,High Efficiency Image File(HEIF)格式是默认格式。我想用Python编辑和修改这些.HEIC文件。

我可以修改手机设置,默认情况下另存为JPG,但这并不能真正解决能够使用其他文件类型的问题。我仍然希望能够处理HEIC文件以进行文件转换,提取元数据等。(Example Use Case -- Geocoding

枕头

这是尝试读取此类文件时使用Python 3.7和Pillow的结果。

$ 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'

貌似已请求在python-pillow中提供支持(#2806),但由于那里存在许可/专利问题,因此无法提供支持。

ImageMagick +魔杖

似乎可以选择ImageMagick。在完成brew install imagemagickpip install wand之后,我失败了。

$ 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

还有其他方法可以通过编程进行转换吗?

5 个答案:

答案 0 :(得分:2)

除了danial的答案外,我只需要稍稍修改字节数组即可获得有效的数据流以进行进一步的工作。前6个字节是'Exif \ x00 \ x00'..删除这些字节将为您提供原始格式,您可以将该格式传输到任何图像处理工具中。

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)

至少这对我有用。

答案 1 :(得分:1)

这确实会从heic文件中获取exif数据

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)

答案 2 :(得分:1)

我在魔杖包装上非常成功: 安装魔杖: https://docs.wand-py.org/en/0.6.4/ 转换代码:

   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()

答案 3 :(得分:0)

我正面临与您完全相同的问题,需要CLI解决方案。做一些进一步的研究,似乎ImageMagick requires libheif委托库。 libheif库本身似乎也具有某些依赖性。

我也没有成功地使其中任何一个工作,但会继续尝试。我建议您检查这些依赖项是否可用于您的配置。

答案 4 :(得分:-1)

你们应该检查这个库,它是libheif 库的Python 3包装器,它应该可以满足您进行文件转换,提取元数据的目的:

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

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

用法示例:

 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")

  ...