我有一个巨大的文件夹,里面装着我多年来收集的图片,我的学生会用它们来做课程作业。一开始只有大约 20 张图片,所以我并没有费心为它们命名或建立任何结构,只是给它们贴上标签,然后把它们放进去。现在同一个文件夹中有大约 5000 张图片,处理起来已经很困难了。
理想情况下,我希望能够运行一个命令(现在和将来随着更多命令的提交),该命令将查看图像标签并创建一个具有标签名称的目录并将该图像移动到其中,或者如果先前的图像已经创建了该目录,则只需将图像移动到该目录中。
我不确定我是否能很好地解释这一点。
例如,前 5 张图片是汽车 - 宝马、本田、福特、阿尔法罗密欧和另一辆宝马。文件名都是唯一的 - 记住它们都在同一个文件夹中。因此,运行这个神秘的脚本后,我将拥有 4 个文件夹,其中宝马文件夹中有 2 张图片。
Shotwell 中所有内容都已标记,大部分是 JPG,还有一些 PNG,只是为了使事情复杂化!可能有多个标签,但 95% 只是单个标签。我不确定标签存储在哪里,但我假设在每个文件中都有,因为标签在我的两台计算机上都显示,但只在主计算机上标记过。
进一步调查表明,标签是根据单个图像的“关键词”存储的,所以也许我应该问如何根据关键词创建目录?
我在这里学到了很多东西!
如果有帮助的话,这是来自的输出exiftool
:
$ exiftool 010.jpg
ExifTool Version Number : 10.10
File Name : 010.jpg
Directory : .
File Size : 274 kB
File Modification Date/Time : 2016:04:23 21:03:59+01:00
File Access Date/Time : 2016:04:23 21:03:59+01:00
File Inode Change Date/Time : 2016:04:23 21:03:59+01:00
File Permissions : rw-rw-r--
File Type : JPEG
File Type Extension : jpg
MIME Type : image/jpeg
JFIF Version : 1.01
Resolution Unit : inches
X Resolution : 72
Y Resolution : 72
Exif Byte Order : Little-endian (Intel, II)
Software : Shotwell 0.22.0
XMP Toolkit : XMP Core 4.4.0-Exiv2
Subject : BMW, Bell_Photography
Current IPTC Digest : 6249bf63f46e9abb15cfe27d71a87a72
Keywords : BMW, Bell_Photography
Originating Program : Shotwell
Program Version : 0.22.0
Image Width : 936
Image Height : 1334
Encoding Process : Baseline DCT, Huffman coding
Bits Per Sample : 8
Color Components : 3
Y Cb Cr Sub Sampling : YCbCr4:4:4 (1 1)
Image Size : 936x1334
Megapixels : 1.2
假设除了我之外的任何人都能理解这一点,这可能吗?
答案1
虽然 JF Sebastian 的答案可能正是您想要的,但还有一个名为的基于标签的文件系统标记助手这可能值得研究。您可以将标签视为传统文件系统中的目录,并通过导航浏览文件。如果您在文件中有多个标签并想搜索和排序它们,这会更容易。
答案2
你可以使用exiftool
,从 jpg、png 文件获取元信息。要安装exiftool
,请运行:
$ sudo apt-get install libimage-exiftool-perl
用法:exiftool -s example.jpg
似乎最完整的信息存储为TagsList
。它甚至支持 Shotwell 保存的分层标签,例如nature/sky
。标签也可以在Subject
、、Keywords
字段中找到LastKeywordXMP
。Subject
,Keywords
不保留标签层次结构 - 如果您不想为嵌套标签创建嵌套目录,则可以使用它们。
以下python3
脚本将命令行上指定的图像文件移动到相应的标签目录(通过创建硬链接并删除原始文件名),例如,如果有example.jpg
标签列表:nature
,,,则结果目录树如下所示:nature/clouds
nature/mountain
nature/sky
.
└── nature
├── clouds
│ └── example.jpg
├── example.jpg
├── mountain
│ └── example.jpg
└── sky
└── example.jpg
笔记:在运行可能造成破坏的命令之前,请务必备份数据(可能会出现错误):
#!/usr/bin/env python3
"""Move image files to their tag directories by creating hardlinks.
Usage: move-to-tag-dirs <image>...
"""
import json
import os
import sys
from subprocess import Popen, PIPE
TAGNAMES = ['TagsList', 'Keywords', 'Subject']
__version__ = '0.3.1'
def move_to_dirs(filename, dirs):
"""Move *filename* to *dirs* by creating hardlinks.
Create destination directories if they don't exist.
"""
for dirname in dirs:
os.makedirs(dirname, exist_ok=True)
dest_filename = os.path.join(dirname, os.path.basename(filename))
os.link(filename, dest_filename) # create hardlink
if dirs: # created at least one new link
os.unlink(filename) # remove old
if len(sys.argv) < 2:
sys.exit(__doc__) # print usage
command = ['exiftool', '-json'] + ['-' + t for t in TAGNAMES] + sys.argv[1:]
try:
process = Popen(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
except OSError as e:
sys.exit("error: can't start exiftool: " + str(e))
else:
output, errors = process.communicate()
if process.returncode != 0:
sys.exit("error: can't read tags info: exiftool exit code: %d: %s" % (
process.returncode, errors))
for metadata in json.loads(output):
# get first available tags list
dirs = next(filter(None, map(metadata.get, TAGNAMES)), [])
if isinstance(dirs, str): # single tag
dirs = [dirs]
try:
move_to_dirs(metadata['SourceFile'], dirs)
except OSError as e:
print("warning: failed to move %s to %s: %s" % (
metadata['SourceFile'], dirs, e), file=sys.stderr)
将其保存到名为某处的文件move-to-tag-dirs
中$PATH
. 确保文件具有可执行权限:
$ chmod +x move-to-tag-dirs
有关的:如何直接运行.py程序?
然后将所有图像移动到相应的标签目录,运行:
$ move-to-tag-dirs *.jpg *.png
如果出现'Argument list too long'
错误则运行:
$ find . -maxdepth 1 -name \*.jpg -o -name \*.png -exec move-to-tag-dirs {} +
如果忽略错误处理、对分层标签的支持、对文件名、标签等中不常见字符的支持,那么脚本可以大大简化(也许在这种情况下,一个简单的一次性 shell 脚本就足够了)。