Изменение размера изображения в 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') 

http://www.emilas.com/jpeg/

На самом деле существует действительно простой способ копирования 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.

Другие вопросы по тегам