代码之家  ›  专栏  ›  技术社区  ›  j12y

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

  •  0
  • j12y  · 技术社区  · 6 年前

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

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

    枕头

    下面是在尝试读取此类文件时使用Python3.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枕头的支持( #2806 )但有许可证/专利问题阻碍了它的发展。

    ImageMagick+魔杖

    看来 ImageMagick 可能是个选择。在做了一个 brew install imagemagick pip 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
    

    是否有其他可用的方法以编程方式进行转换?

    0 回复  |  直到 5 年前
        1
  •  8
  •   danial    5 年前

    你们应该看看这个库,它是 libheif 库,它应该满足您的文件转换、提取元数据的目的:

    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")
    
      ...
    
        2
  •  1
  •   Peter Kunszt    4 年前

    除了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)
    

    至少这对我有用。

        3
  •  0
  •   Tropicalrambler    5 年前

    我正面临着和你完全一样的问题,需要一个CLI解决方案。做进一步的研究,看起来像是在幻想 requires 这个 libheif 委托库。libheif库本身似乎也有一些依赖关系。

    我并没有成功地让他们中的任何一个也能工作,但我会继续努力。我建议您检查这些依赖项是否可用于您的配置。

        4
  •  0
  •   PidePython    4 年前

    这样就可以从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)
    
    推荐文章