Reputation: 384
I have to in to a problem with adding new tags to Exif data for an image.
I have created a PySimpleGUI python script for simple image manipulation and worked out all but the last steps.
The script displays an image (jpg, jepg) and a key Exif data. The script uses a series of checkboxes to 'tag' and image quickly from a selection (list). I have the array of checkboxes, image updating properly. So I can decode the Exif data properly, but when I want to update the image I run into problems.
I use Windows 10 with Python3, with Imports from PIL, PySimpleGUI.
The meta data:
I found some help: Encode UCS2
Using the help from above I can get this:
Exif: b'O\x00u\x00t\x00d\x00o\x00o\x00r\x00;\x00a\x00r\x00t\x00\x00\x00'
Converts to 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'))
Good, I can convert that str
to a list and update the checkboxes.
I add more keywords to the str
. Now:Outdoor;art;box;machine;
To update the keys I have this function. Checkboxes selected are True, and unselected are False.
PySimpleGUI as collects events and vales. The function scans the values for selected "True".
TaggerList is the master list of tags I use in the script. When a checkbox is True the loop adds the Tags to the InsertString
. Shown above.
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
I can use Image.Exif.__setitem__(i, InsertString[:-1].encode('utf-16'))
to save just the updated keywords.
But the encoding still give an error.
The original: Exif: b'O\x00u\x00t\x00d\x00o\x00o\x00r\x00;\x00a\x00r\x00t\x00\x00\x00'
Saved Tags: 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'
The encoding does not seem to be mutual both ways. The encoded string adds '\xff\xfeu
I assume \xfeu is a capital 'O'.
The encoding is wrong and breaks the image. General image viewers error out the updated image.
If I can fix this I can then finish the script.
Upvotes: 0
Views: 802
Reputation: 384
I figured out what was at issue. The encoding is a priory to byte order.
To get the format I wanted I needed little endian notation. In python utf_16_le
little and utf_16_be
for big endian codecs.
utf_16_le
puts the first 8 bits of the data at the head and then the last 8 bits at the tail.
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'))
In this code I get the expected results. b'a\x00b\x00c\x00d\x00...
So Image Exif data is little endian byte ordered.
Upvotes: 2