Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XMP image tagging and Python

Tags:

python

xmp

If I were to tag a bunch of images via XMP, in Python, what would be the best way? I've used Perl's Image::ExifTool and I am very much used to its reliability. I mean the thing never bricked on tens of thousands of images.

I found this, backed by some heavy-hitters like the European Space Agency, but it's clearly marked as unstable.

Now, assuming I am comfortable with C++, how easy is it to, say, use the Adobe XMP toolkit directly, in Python? Having never done this before, I am not sure what I'd sign up for.

Update: I tried some libraries out there and, including the fore mentioned toolkit, they are still pretty immature and have glaring problems. I resorted to actually writing an Perl-based server that accepts XML requests to read and write metadata, with the combat-tested Image::EXIF. The amount of code is actually very light, and definitely beats torturing yourself by trying to get the Python libraries to work. The server solution is language-agnostic, so it's a twofer.

like image 399
Andrei Taranchenko Avatar asked Feb 01 '09 16:02

Andrei Taranchenko


4 Answers

Well, they website says that the python-xmp-toolkit uses Exempi, which is based on the Adobe XMP toolkit, via ctypes. What I'm trying to say is that you're not likely to create a better wrapping of the C++ code yourself. If it's unstable (i.e. buggy), it's most likely still cheaper for you to create patches than doing it yourself from scratch.

However, in your special situation, it depends on how much functionality you need. If you just need a single function, then wrapping the C++ code into a small C extension library or with Cython is feasible. When you need to have all functionality & flexibility, you have to create wrappers manually or using SWIG, basically repeating the work already done by other people.

like image 133
Torsten Marek Avatar answered Nov 04 '22 17:11

Torsten Marek


I struggled for several hours with python-xmp-toolkit, and eventually gave up and just wrapped calls to ExifTool.

There is a Ruby library that wraps ExifTool as well (albeit, much better than what I created); I feel it'd be worth porting it to Python for a simple way of dealing with XMP.

like image 44
Xiong Chiamiov Avatar answered Nov 04 '22 18:11

Xiong Chiamiov


For Python 3.x there's py3exiv2 which supports editing XMP metadata

With py3exiv2 you can read and write all standard metadata, create your own XMP namespace or extract the thumbnail embedded in image file.

One thing I like about py3exiv2 is that it's built on the (C++) exiv2 library which seems well-maintained

I did encounter a problem though when installing it on my system (Ubuntu 16.04). To get it working I first had to install the latest version of libexiv2-dev (sudo apt-get install libexiv2-dev), and only after this install py3exiv2 (sudo -H pip3 install py3exiv2)

Here's how I've used py3exiv2 to write a new tag:

import pyexiv2
metadata = pyexiv2.ImageMetadata("file_name.jpg")
metadata.read()
key = "Xmp.xmp.CustomTagKey"
value = "CustomTagValue"
metadata[key] = pyexiv2.XmpTag(key, value)
metadata.write()

(There's also a tutorial in the documentation)

like image 2
sunyata Avatar answered Nov 04 '22 16:11

sunyata


For people finding this thread in the future, I would like to share my solution. I put a package up on the Python Package Index (PyPI) called imgtag. It lets you do basic XMP subject field tag editing using python-xmp-toolkit, but abstracts away all of the frustrating nonsense of actually using python-xmp-toolkit into one-line commands.

Install exempi for your platform, then run

python3 -m pip install imgtag

Now you can use it as such:

from imgtag import ImgTag

# Open image for tag editing
test = ImgTag(
           filename="test.jpg", # The image file
           force_case="lower",  # Converts the case of all tags
                                # Can be `None`, `"lower"`, `"upper"`
                                # Default: None
           strip=True,          # Strips whitespace from the ends of all tags
                                # Default: True
           no_duplicates=True   # Removes all duplicate tags (case sensitive)
                                # Default: True
       )

# Print existing tags
print("Current tags:")
for tag in test.get_tags():
    print("  Tag:", tag)

# Add tags
test.add_tags(["sleepy", "happy"])

# Remove tags
test.remove_tags(["cute"])

# Set tags, removing all existing tags
test.set_tags(["dog", "good boy"])

# Save changes and close file
test.close()

# Re-open for tag editing
test.open()

# Remove all tags
test.clear_tags()

# Delete the ImgTag object, automatically saving and closing the file
del(test)

I haven't yet added methods for the other XMP fields like description, date, creator, etc. Maybe someday I will, but if you look at how the existing functions work in the source code, you can probably figure out how to add the method yourself. If you do add more methods, make a pull request please. :)

like image 1
Ella Jameson Avatar answered Nov 04 '22 16:11

Ella Jameson