Изменение размера изображения в Python без потери данных EXIF
Мне нужно изменить размер изображений jpg с помощью Python без потери данных EXIF исходного изображения (метаданные о дате съемки, модели камеры и т. Д.). Все поиски в Google по поводу python и изображений указывают на библиотеку PIL, которую я сейчас использую, но, похоже, не в состоянии сохранить метаданные. Код, который я имею до сих пор (используя PIL), таков:
img = Image.open('foo.jpg')
width,height = 800,600
if img.size[0] < img.size[1]:
width,height = height,width
resized_img = img.resize((width, height), Image.ANTIALIAS) # best down-sizing filter
resized_img.save('foo-resized.jpg')
Есть идеи? Или другие библиотеки, которые я мог бы использовать?
10 ответов
import jpeg
jpeg.setExif(jpeg.getExif('foo.jpg'), 'foo-resized.jpg')
На самом деле существует действительно простой способ копирования EXIF-данных из одного изображения в другое с использованием только PIL. Хотя это не позволяет изменять теги exif.
image = Image.open('test.jpg')
exif = image.info['exif']
# Your picture process here
image = image.rotate(90)
image.save('test_rotated.jpg', 'JPEG', exif=exif)
Как видите, функция сохранения может принимать аргумент exif, который позволяет копировать необработанные данные exif в новое изображение при сохранении. На самом деле вам не нужна никакая другая библиотека, если это все, что вы хотите сделать. Кажется, я не могу найти какую-либо документацию по параметрам сохранения, и я даже не знаю, относится ли она к Pillow или к работе с PIL. (Если у кого-то есть какая-то ссылка, я был бы рад, если бы он разместил ее в комментариях)
Вы можете использовать pyexiv2 для копирования данных EXIF из исходного изображения. В следующем примере размер изображения изменяется с использованием библиотеки PIL, данные EXIF, скопированные с помощью pyexiv2, и поля EXIF размера изображения устанавливаются с новым размером.
def resize_image(source_path, dest_path, size):
# resize image
image = Image.open(source_path)
image.thumbnail(size, Image.ANTIALIAS)
image.save(dest_path, "JPEG")
# copy EXIF data
source_image = pyexiv2.Image(source_path)
source_image.readMetadata()
dest_image = pyexiv2.Image(dest_path)
dest_image.readMetadata()
source_image.copyMetadataTo(dest_image)
# set EXIF image size info to resized size
dest_image["Exif.Photo.PixelXDimension"] = image.size[0]
dest_image["Exif.Photo.PixelYDimension"] = image.size[1]
dest_image.writeMetadata()
# resizing local file
resize_image("41965749.jpg", "resized.jpg", (600,400))
Вот обновленный ответ от 2018. piexif - это чистая библиотека python, которая для меня легко устанавливается через pip (pip install piexif) и прекрасно работает (спасибо, сопровождающие!). https://pypi.org/project/piexif/
Использование очень простое: одна строка будет копировать принятый ответ и скопировать все теги EXIF из исходного изображения в изображение с измененным размером:
import piexif
piexif.transplant("foo.jpg", "foo-resized.jpg")
Я еще не пробовал, но похоже, что вы также можете легко выполнять модификации, используя функции загрузки, выгрузки и вставки, как описано в связанной документации.
Почему бы не использовать ImageMagick?
Это довольно стандартный инструмент (например, это стандартный инструмент, используемый в Gallery 2); Я никогда не использовал его, однако он также имеет интерфейс Python (или, вы также можете просто вызвать команду) и, прежде всего, должен поддерживать информацию EXIF между всеми преобразованиями.
Для pyexiv2 v0.3.2 документация API относится к методу копирования для переноса данных EXIF из одного изображения в другое. В этом случае это будут EXIF-данные исходного изображения с измененным размером.
Если оставить @Maksym Kozlenko, обновленный код для копирования данных EXIF:
source_image = pyexiv2.ImageMetadata(source_path)
source_image.read()
dest_image = pyexiv2.ImageMetadata(dest_path)
dest_image.read()
source_image.copy(dest_image,exif=True)
dest_image.write()
Вы можете использовать pyexiv2, чтобы изменить файл после его сохранения.
Кажется, решение @Depado не работает для меня, в моем сценарии изображение даже не содержит сегмент exif.
pyexiv2 сложно установить на моем Mac, вместо этого я использую модуль pexif https://github.com/bennoleslie/pexif/blob/master/pexif.py. Чтобы "добавить сегмент exif" к изображению, не содержащему информацию exif, я добавил информацию exif, содержащуюся в изображении, которому принадлежит сегмент exif.
from pexif import JpegFile
#get exif segment from an image
jpeg = JpegFile.fromFile(path_with_exif)
jpeg_exif = jpeg.get_exif()
#import the exif segment above to the image file which does not contain exif segment
jpeg = JpegFile.fromFile(path_without_exif)
exif = jpeg.import_exif(jpeg_exif)
jpeg.writeFile(path_without_exif)
Обновленная версия Maksym Kozlenko Python3 и py3exiv2 v0.7
# Resize image and update Exif data
from PIL import Image
import pyexiv2
def resize_image(source_path, dest_path, size):
# resize image
image = Image.open(source_path)
# Using thumbnail, then 'size' is MAX width or weight
# so will retain aspect ratio
image.thumbnail(size, Image.ANTIALIAS)
image.save(dest_path, "JPEG")
# copy EXIF data
source_exif = pyexiv2.ImageMetadata(source_path)
source_exif.read()
dest_exif = pyexiv2.ImageMetadata(dest_path)
dest_exif.read()
source_exif.copy(dest_exif,exif=True)
# set EXIF image size info to resized size
dest_exif["Exif.Photo.PixelXDimension"] = image.size[0]
dest_exif["Exif.Photo.PixelYDimension"] = image.size[1]
dest_exif.write()
from PIL import Image
img_path = "/tmp/img.jpg"
img = Image.open(img_path)
exif = img.info['exif']
img.save("output_"+img_path, exif=exif)
Проверено в подушке 2.5.3
PIL обрабатывает данные EXIF, не так ли? Посмотри в PIL.ExifTags.