Почему после обновления изображения происходит сбой кодирования из тегов Exif

У меня возникла проблема с добавлением новых тегов в данные Exif для изображения.

Настройка

Я создал скрипт Python PySimpleGUI для простых манипуляций с изображениями и проработал все, кроме последних шагов.

Скрипт отображает изображение (jpg, jepg) и ключевые данные Exif. Сценарий использует серию флажков для быстрого «пометки» и изображения из выбранного (списка). У меня есть набор флажков, изображение обновляется правильно. Таким образом, я могу правильно декодировать данные Exif, но когда я хочу обновить изображение, у меня возникают проблемы.

Я использую Windows 10 с Python3, с импортом из PIL, PySimpleGUI.

Мета-данные:

  • 40094 (идентификатор Exif для ключа, который я хочу обновить)
  • Exif.Image.XPKeywords
  • Байт (тип переменной)
  • Тег ключевых слов, используемый Windows (в кодировке UCS2)

Я нашел помощь: Кодировать UCS2

Используя помощь сверху, я могу получить следующее:

Exif: b'O\x00u\x00t\x00d\x00o\x00o\x00r\x00;\x00a\x00r\x00t\x00\x00\x00'

Преобразуется в Outdoor;art

<i = 40094>
    img = Image.open(pathname + '\\' + filename)
    exifDataRaw = img._getexif()
        if exifDataRaw.get(i):
            if exifDataRaw[i]:
                print("Exif:", exifDataRaw[i])
                return str(exifDataRaw[i].decode('utf-16'))

Хорошо, я могу преобразовать этот str в список и обновить флажки.

Обновление тегов (ключевых слов)

Я добавляю дополнительные ключевые слова в str. Сейчас: Outdoor;art;box;machine;

Для обновления ключей у меня есть эта функция. Установленные флажки имеют значение "Истина", а невыделенные флажки - значение "Ложь". PySimpleGUI as собирает события и значения. Функция просматривает значения для выбранного «True». TaggerList - это главный список тегов, которые я использую в скрипте. Когда флажок установлен в True, цикл добавляет теги в InsertString. Показано выше.

def PushTags(pathname, filename):
    InsertString = ""
    img = Image.open(pathname + '\\' + filename)
    for Tag in TaggerList[:-1]:
        if values[Tag]:
            InsertString = InsertString + Tag + ";"
            first = False
    #Get whole dataset
    exifDataRaw = img._getexif()
    i = 40094
    # Set new data to Exif
    exifDataRaw[i] = InsertString[:-1].encode('utf-16')  # remove the last ";" and encode
    img.save(pathname + '\\' + filename, exif=exifDataRaw)   #Update image with new values

Я могу использовать Image.Exif.__setitem__(i, InsertString[:-1].encode('utf-16')), чтобы сохранять только обновленные ключевые слова.

Но кодировка все равно выдает ошибку.

Оригинал: Exif: b'O\x00u\x00t\x00d\x00o\x00o\x00r\x00;\x00a\x00r\x00t\x00\x00\x00'

Сохраненные теги: b'\xff\xfeu\x00t\x00d\x00o\x00o\x00r\x00;\x00a\x00r\x00t\x00;\x00b\x00o\x00x\x00;\x00m\x00a\x00c\x00h\x00i\x00n\x00e\x00'

Кодирование не кажется взаимным в обоих направлениях. Закодированная строка добавляет '\xff\xfeu Я предполагаю, что \ xfeu - это заглавная «О».

Кодировка неправильная, изображение ломается. Обычные программы просмотра изображений выдают ошибку при обновлении изображения.

Если я смогу это исправить, я смогу закончить сценарий.


person Richard E    schedule 10.06.2020    source источник
comment
\xff\xfe - метка порядка байтов и необязательная часть кодирования.   -  person Klaus D.    schedule 10.06.2020
comment
Я могу посмотреть, есть ли какие-нибудь заметки о необязательной кодировке. Тем не менее, как мне отключить его, поскольку данные должны быть совместимы по байтам. Мне это нужно как начало: O\x00u...   -  person Richard E    schedule 11.06.2020


Ответы (1)


Я понял, о чем идет речь. Кодирование зависит от порядка байтов.

Чтобы получить желаемый формат, мне потребовалась небольшая порядковая нотация. В python utf_16_le little и utf_16_be для кодеков с прямым порядком байтов.

utf_16_le помещает первые 8 бит данных в начало, а затем последние 8 бит в хвост.

i = 40094
img = Image.open(pathname + '\\' + filename)
exifDataRaw = img._getexif()
    if exifDataRaw.get(i):
        if exifDataRaw[i]:
            print("Exif:", exifDataRaw[i])
            return str(exifDataRaw[i].decode('utf_16_le'))

В этом коде я получаю ожидаемые результаты. b'a\x00b\x00c\x00d\x00...

Таким образом, данные Image Exif упорядочены с прямым порядком байтов.

person Richard E    schedule 14.06.2020