[英]How to work with HEIC image file types in Python
The High Efficiency Image File (HEIF) format is the default when airdropping an image from an iPhone to a OSX device.将图像从 iPhone 空投到 OSX 设备时, 高效图像文件(HEIF) 格式是默认格式。 I want to edit and modify these.HEIC files with Python.
我想用Python编辑和修改这些.HEIC文件。
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.我可以修改手机设置以默认保存为 JPG,但这并不能真正解决能够使用其他文件类型的问题。 I still want to be able to process HEIC files for doing file conversion, extracting metadata, etc. ( Example Use Case -- Geocoding )
我仍然希望能够处理 HEIC 文件以进行文件转换、提取元数据等。( 示例用例——地理编码)
Pillow枕头
Here is the result of working with Python 3.7 and Pillow when trying to read a file of this type.这是在尝试读取此类文件时使用 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'
It looks like support in python-pillow was requested ( #2806 ) but there are licensing / patent issues preventing it there.看起来需要对 python-pillow 的支持( #2806 ),但存在许可/专利问题阻止它。
ImageMagick + Wand ImageMagick + 魔杖
It appears that ImageMagick may be an option.看来ImageMagick可能是一个选项。 After doing a
brew install imagemagick
and pip install wand
however I was unsuccessful.在执行
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
Any other alternatives available to do a conversion programmatically?还有其他可用于以编程方式进行转换的替代方法吗?
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:你们应该看看这个库,它是libheif库的 Python 3 包装器,它应该用于文件转换,提取元数据:
https://github.com/david-poirier-csn/pyheif https://github.com/david-poirier-csn/pyheif
https://pypi.org/project/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")
...
Adding to the answer by danial, i just had to modify the byte array slighly to get a valid datastream for further work.添加到 danial 的答案中,我只需要稍微修改字节数组即可获得有效的数据流以供进一步工作。 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.
前 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)
At least this worked for me.至少这对我有用。
I was quite successful with Wand package : Install Wand: https://docs.wand-py.org/en/0.6.4/ Code for conversion:我使用 Wand 包非常成功:安装 Wand: 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()
You can use the pillow_heif
library to read HEIF images in a way compatible with PIL.您可以使用
pillow_heif
库以与PIL 兼容的方式读取HEIF 图像。
The example below will import a HEIF picture and save it in png
format.下面的示例将导入一张 HEIF 图片并将其保存为
png
格式。
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")
This will do go get the exif data from the heic file这将确实从 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)
I am facing the exact same problem as you, wanting a CLI solution.我面临着与您完全相同的问题,需要 CLI 解决方案。 Doing some further research, it seems ImageMagick requires the
libheif
delegate library.做一些进一步的研究,似乎 ImageMagick需要
libheif
委托库。 The libheif library itself seems to have some dependencies as well. libheif 库本身似乎也有一些依赖项。
I have not had success in getting any of those to work as well, but will continue trying.我也没有成功地让其中任何一个工作,但会继续尝试。 I suggest you check if those dependencies are available to your configuration.
我建议您检查这些依赖项是否可用于您的配置。
Simple solution after going over multiple responses from people.经过人们的多次回复后的简单解决方案。
Please install whatimage
, pyheif
and PIL
libraries before running this code.请在运行此代码之前安装
whatimage
、 pyheif
和PIL
库。
[NOTE] : I used this command for install. [注意] :我使用此命令进行安装。
python3 -m pip install Pillow
Also using linux was lot easier to install all these libraries.此外,使用 linux 安装所有这些库要容易得多。 I recommend
WSL
for windows.我推荐 Windows 的
WSL
。
import whatimage
import pyheif
from PIL import Image
import os
def decodeImage(bytesIo, index):
with open(bytesIo, 'rb') as f:
data = f.read()
fmt = whatimage.identify_image(data)
if fmt in ['heic', 'avif']:
i = pyheif.read_heif(data)
pi = Image.frombytes(mode=i.mode, size=i.size, data=i.data)
pi.save("new" + str(index) + ".jpg", format="jpeg")
# For my use I had my python file inside the same folder as the heic files
source = "./"
for index,file in enumerate(os.listdir(source)):
decodeImage(file, index)
看起来有一个名为heic-to-jpg的解决方案,但我可能不太确定这将如何在 colab 中工作。
the first answer works, but since its just calling save with a BytesIO object as the argument, it doesnt actually save the new jpeg file, but if you create a new File object with open
and pass that, it saves to that file ie:第一个答案有效,但由于它只是使用 BytesIO 对象作为参数调用 save ,它实际上并没有保存新的 jpeg 文件,但是如果您创建一个带有
open
的新 File 对象并传递它,它会保存到该文件,即:
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)
# Convert to other file format like jpeg
s = open('my-new-image.jpg', mode='w')
pi = Image.frombytes(
mode=i.mode, size=i.size, data=i.data)
pi.save(s, format="jpeg")
Consider using PIL in conjunction with pillow-heif :考虑将 PIL 与Pillow-heif结合使用:
pip3 installl pillow-heif
from PIL import Image
from pillow_heif import register_heif_opener
register_heif_opener()
image = Image.open('image.heic')
Here is another solution to convert heic
to jpg
while keeping the metadata intact.这是将
heic
转换为jpg
同时保持元数据完整的另一种解决方案。 It is based on mara004
s solution above, however I was not able to extract the images timestamp in that way, so had to add some code.它基于上面的
mara004
解决方案,但是我无法以这种方式提取图像时间戳,因此必须添加一些代码。 Put the heic
files in dir_of_interest
before applying the function:在应用函数之前将
heic
文件放在dir_of_interest
:
import os
from PIL import Image, ExifTags
from pillow_heif import register_heif_opener
from datetime import datetime
import piexif
import re
register_heif_opener()
def convert_heic_to_jpeg(dir_of_interest):
filenames = os.listdir(dir_of_interest)
filenames_matched = [re.search("\.HEIC$|\.heic$", filename) for filename in filenames]
# Extract files of interest
HEIC_files = []
for index, filename in enumerate(filenames_matched):
if filename:
HEIC_files.append(filenames[index])
# Convert files to jpg while keeping the timestamp
for filename in HEIC_files:
image = Image.open(dir_of_interest + "/" + filename)
image_exif = image.getexif()
if image_exif:
# Make a map with tag names and grab the datetime
exif = { ExifTags.TAGS[k]: v for k, v in image_exif.items() if k in ExifTags.TAGS and type(v) is not bytes }
date = datetime.strptime(exif['DateTime'], '%Y:%m:%d %H:%M:%S')
# Load exif data via piexif
exif_dict = piexif.load(image.info["exif"])
# Update exif data with orientation and datetime
exif_dict["0th"][piexif.ImageIFD.DateTime] = date.strftime("%Y:%m:%d %H:%M:%S")
exif_dict["0th"][piexif.ImageIFD.Orientation] = 1
exif_bytes = piexif.dump(exif_dict)
# Save image as jpeg
image.save(dir_of_interest + "/" + os.path.splitext(filename)[0] + ".jpg", "jpeg", exif= exif_bytes)
else:
print(f"Unable to get exif data for {filename}")
Just to note: Today was first release of pillow-heif that support 64 bit windows.请注意:今天是第一个支持 64 位 windows 的pillow-heif版本。
Now it support almost all platforms, except windows arm and 32 bit systems.现在它支持几乎所有平台,除了 windows arm 和 32 位系统。
In this topic two people showed it's basic usage.在这个主题中,两个人展示了它的基本用法。
Example for working with HDR(10/12) bit HEIF files using OpenCV and pillow-heif:使用 OpenCV 和pillow-heif 处理 HDR(10/12) 位 HEIF 文件的示例:
import numpy as np
import cv2
import pillow_heif
heif_file = pillow_heif.open_heif("images/rgb12.heif", convert_hdr_to_8bit=False)
heif_file.convert_to("BGRA;16" if heif_file.has_alpha else "BGR;16")
np_array = np.asarray(heif_file)
cv2.imwrite("rgb16.png", np_array)
Input file for this example can be 10 or 12 bit file.此示例的输入文件可以是 10 位或 12 位文件。
I use the pillow_heif library.我使用 pillow_heif 库。 For example, I use this script when I have a folder of heif files I want to convert to png.
例如,当我有一个要转换为 png 的 heif 文件文件夹时,我会使用此脚本。
from PIL import Image
import pillow_heif
import os
from tqdm import tqdm
import argparse
def get_images(heic_folder):
# Get all the heic images in the folder
imgs = [os.path.join(heic_folder, f) for f in os.listdir(heic_folder) if f.endswith('.HEIC')]
# Name of the folder where the png files will be stored
png_folder = heic_folder + "_png"
# If it doesn't exist, create the folder
if not os.path.exists(png_folder):
os.mkdir(png_folder)
for img in tqdm(imgs):
heif_file = pillow_heif.read_heif(img)
image = Image.frombytes(
heif_file.mode,
heif_file.size,
heif_file.data,
"raw",
)
image.save(os.path.join(png_folder,os.path.basename(img).split('.')[0])+'.png', format("png"))
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Convert heic images to png')
parser.add_argument('heic_folder', type=str, help='Folder with heic images')
args = parser.parse_args()
get_images(args.heic_folder)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.