I've imported lots of pictures into Shotwell and spent some time setting tags. Are those tags locked-in in Shotwell or I can export them (and import again or use with other software)?
I'm the founder of Yorba, makers of Shotwell. Thanks for your question.
Shotwell 0.7 writes metadata (such as tags and titles) to photos when you export them. The metadata is written in EXIF, IPTC and/or XMP format (depending on which of these were present in the photo to begin with). Most other photo programs can read these formats, so if you export your photos from Shotwell then other programs should be able to read their tags with no problem.
The upcoming Shotwell 0.8 can write metadata to photo files on the fly - to enable this, select the option "Write tags, titles and other metadata to photo files" in the preferences dialog. Once this is selected, Shotwell will update metadata in photo files as soon as you tag them. To use this feature, build the Shotwell trunk from source (see http://yorba.org/shotwell/install/#source), or just wait for Shotwell 0.8 (which we plan to release later in December).
Unfortunately Shotwell does seem to keep the tags in its own database rather than embed them as exif, IPTC or XMP in the pictures. You can check by using exiftool, which can be installed by installing the package libimage-exiftool-perl, available in the repositories.
use the command;
exiftool testpicture.jpg to check a photo called testpicture.jpg that you had previously tagged with Shotwell. You will see that the exiftool output contains no Shotwell tags.
The exiftool utility can tag your pictures embedding the tags in the photo and the good thing about this is that most photo managers will use them, this includes Shotwell. For example:
exiftool -keywords=favourite -keywords=family testpicture.jpg
Replace existing keyword list with two new keywords (favourite and family).
When testpicture.jpg is imported into Shotwell the picture will be tagged with favourite and family
It may be helpful to know that the Shotwell database is an sqlite database located in your;
~/.shotwell/data directory and usually called photo.db, you can copy it somewhere else on your computer and access it with sqlite.
There are a few GUI frontends for sqlite, there is one for firefox here or you can use sqliteman. Both of these front ends have export to csv features; when you export your tags to csv (Comma Separated Values) you can check if any other photo management software will import and map the tags to the appropriate field in their own databases. I believe Digikam can do this. Digikam can also embed exif data in the photos themselves.
Hopefully as Shotwell gains more features this situation will change.
UPDATE: While it is true that Shotwell 0.7 does not store its tags in the pictures as these tags are created, the tags can be embedded in the pictures if you choose to export them, thanks Adam for making this clear. Hopefully this export is lossless when dealing with jpegs. I suspect it is, if one selects original size for the Scaling option in the export dialog.
Quick (dirty?) python code to do this without upgrading Shotwell (I think as of 0.8.x Shotwell can write out tags, but you can't upgrade to that on Lucid). This thing will write out star-ratings as tags (comment that bit out, obviously, if you don't want that).
Requires exiftool. It'll duplicate any tags that are both in the shotwell database AND the images (ie ones that Shotwell imported when it imported the images) so watch out for that. Also, takes quite a while for a big collection of photos.
import os conn = sqlite3.connect("/home/ username /.shotwell/data/photo.db") def get_tags(): return [ x for x in conn.execute("SELECT name FROM TagTable").fetchall()] def tag_query(tag): return conn.execute("SELECT photo_id_list FROM TagTable WHERE name=?", (tag,)).fetchone().split(",") def get_tagged_photos(tag): for id in tag_query(tag): result = conn.execute("select filename from PhotoTable where id=?", (id,) ).fetchone() if result: yield result def get_photos_by_rating(rating): return [photo for photo in conn.execute("select filename from PhotoTable where rating=?",(rating,)).fetchall()] def get_tagging_commands(): commands =  for rating in range(1,5): for photo in get_photos_by_rating(rating): commands.append("exiftool -overwrite_original_in_place -preserve -keywords+=rating%d \"%s\""% (rating,photo)) for tag in [tag for tag in get_tags() if tag != "keep"]: for photo in get_tagged_photos(tag): commands.append("exiftool -overwrite_original_in_place -preserve -keywords+=%s \"%s\"" % (tag,photo)) return commands commands = get_tagging_commands() for command in commands: print command os.system(command)
If you want a really good GUI tool/browser that will let you tag your images using Exif tags (and therefore available in Shotwell too), I recommend jBrout.
To install it, go to Synaptic, choose settings/repositories, click on the "Other Software" tab, then hit the "Add" button and paste in this line :
deb http://jbrout.free.fr/download/debian binary/
Then reload and search for jBrout.
I tried using user38122's script for parsing the shotwell database, and it didn't work. Apparently the schema has been changed in recent versions. Instead I wrote the following script that uses pandas (which i personally prefer to writing SQL) to do tag intersections. In the example below I show all the images that have both the tag 'cat' and the tag 'sleeping'.
#!/usr/bin/python # An example of how to query the shotwell database with pandas import sqlite3, pandas, os, time, datetime con = sqlite3.connect('/home/dov/.local/share/shotwell/data/photo.db') photo_df = pandas.read_sql("SELECT * from PhotoTable", con) for c in ['exposure_time','timestamp','time_created']: photo_df[c] = photo_df[c].map(datetime.datetime.fromtimestamp) tag_df = pandas.read_sql('SELECT * from TagTable', con) def get_image_ids(tag): """The image ids are stored morphed in the database as %016x""" global tag_df return set([int(s.replace('thumb',''),16) for s in tag_df[tag_df.name==tag].photo_id_list.iloc.split(',') if len(s)]) def get_photos(ids): """Get the photos for a list of ids""" global photo_df return photo_df[photo_df.id.isin(ids)].sort(['exposure_time']) def view_pix(rows): cmd = ('eog ' + ' '.join(['"%s"'%row.filename for idx,row in rows.iterrows()])) # print cmd os.system(cmd) print 'querying...' # An example of how to create an intersection of two tags ids1 = get_image_ids('cat') ids2 = get_image_ids('sleeping') rows = get_photos(ids1.intersection(ids2)) # An example of how to filter the rows by timestamp time_low,time_high = datetime.datetime(2006,8,1),datetime.datetime(2009,1,1) rows = rows[(rows.exposure_time > time_low) & (rows.exposure_time < time_high)] print '\n'.join([str(ts) for ts in rows['exposure_time']]) view_pix(rows) print 'done'