我可以导出保存所有标签的Shotwell图片数据库吗?


14

我已经将许多图片导入Shotwell,并花了一些时间设置标签。这些标签是否锁定在Shotwell中,或者我可以导出它们(然后再次导入或与其他软件一起使用)?

Answers:


22

我是Shotwell的制造商Yorba的创始人。感谢您的提问。

导出时,Shotwell 0.7将元数据(例如标签和标题)写入照片。元数据以EXIF,IPTC和/或XMP格式编写(取决于照片中开头的是哪种)。大多数其他照片程序都可以读取这些格式,因此,如果从Shotwell导出照片,则其他程序应该可以毫无问题地读取其标签。

即将发布的Shotwell 0.8可以即时将元数据写入照片文件- 要启用此功能,请在首选项对话框中选择“ 将标签,标题和其他元数据写入照片文件 ”选项。选择此项后,Shotwell将在您标记照片文件后立即更新它们。要使用此功能,请从源代码构建Shotwell中继(请参阅http://yorba.org/shotwell/install/#source),或仅等待Shotwell 0.8(我们计划在12月下旬发布)。


+1我是Shotwell的新用户;感谢您所做的一切。
msw 2010年

3
动态meta标签编写是否具有追溯力?
hultqvist 2011年

@hultqvist,是的,我只是检查选项,肖特韦尔开始将其写入到所有我的照片之后
一些用户

9

不幸的是,Shotwell似乎确实将标签保留在自己的数据库中,而不是将它们作为exif,IPTC或XMP嵌入图片中。您可以使用exiftool进行检查,可以通过安装存储库中提供的软件包libimage-exiftool-perl进行安装。

在这里看到一些例子

使用命令;exiftool testpicture.jpg检查您之前用Shotwell标记过的一张名为testpicture.jpg的照片。您将看到exiftool输出中不包含Shotwell标签。

exiftool实用程序可以为您的照片加标签,将标签嵌入照片中,这样做的好处是大多数照片管理器都会使用它们,其中包括Shotwell。例如:

exiftool -keywords=favourite -keywords=family testpicture.jpg

用两个新关键字(收藏夹和家族)替换现有的关键字列表。

将testpicture.jpg导入Shotwell时,该图片将被标记为“最爱和家人”

知道Shotwell数据库是位于您所在位置的sqlite数据库可能会有所帮助。~/.shotwell/data目录,通常称为photo.db,您可以将其复制到计算机上的其他位置,并使用sqlite访问。

sqlite有一些GUI前端,firefox这里有一个,或者您可以使用sqliteman。这两个前端都导出到csv功能。将标签导出到csv(逗号分隔值)时,可以检查是否有任何其他照片管理软件将标签导入并映射到其各自数据库中的相应字段。我相信Digikam可以做到。Digikam还可以在照片本身中嵌入exif数据。

希望随着Shotwell获得更多功能,这种情况将会改变。

更新:虽然确实在创建这些标签时Shotwell 0.7不会将其标签存储在图片中,但是如果您选择导出标签,则可以将这些标签嵌入图片中,这要感谢亚当(Adam)明确指出。希望此输出在处理jpeg时无损。我怀疑是这样,如果在导出对话框中为“缩放”选项选择了原始大小。


1
在导出过程中,如果“缩放比例”选项为“原始大小” 并且照片未编辑(没有颜色调整,裁切等),则它是无损的。请注意,更改照片的方向也是无损的,因为我们使用EXIF标志而不是重新编码旋转的图像。
Jim Nelson

我相信您可以在Shetwell首选项中选中“将标签,标题和其他元数据写入照片文件”框,以将其标签写到图像文件中。
JellicleCat 2015年

2

快速(肮脏的?)Python代码无需升级Shotwell就可以做到这一点(我认为从0.8.x开始Shotwell可以写出标签,但是您不能在Lucid上升级到该标签)。这东西会以标签的形式写出星级(显然,如果您不想要的话,注释会有点漏掉)。

需要exiftool。它将复制Shotwell数据库和图像中的所有标签(即Shotwell导入图像时导入的标签),因此请当心。此外,花大量时间收集大量照片。

import os
conn = sqlite3.connect("/home/  username  /.shotwell/data/photo.db")

def get_tags():
    return [ x[0] 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()[0].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[0]

def get_photos_by_rating(rating):
    return [photo[0] 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)


0

由于~/.shotwell/data/photo.dbphoto.db: SQLite 3.x database通过文件命令标识,因此我使用SQLite Database Browsersqlitebrowser)将其打开。

嗯...您可以阅读:-)它具有CVS导出功能。

这不是正常的GUI方法,但是有一种方法。


0

我尝试使用user38122的脚本来解析Shotwell数据库,但是它没有用。显然,该架构在最新版本中已更改。相反,我编写了以下脚本,该脚本使用pandas(我个人更喜欢编写SQL)来进行标记交叉。在下面的示例中,我显示了同时具有标签“ cat”和标签“ 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[0].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'
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.