Чтобы не запускать новый процесс для каждого изображения, следует запускать exiftool
с помощью -stay_open
флаг. Затем вы можете отправлять команды процессу через стандартный ввод и читать вывод на стандартный вывод. ExifTool поддерживает вывод JSON, что, вероятно, является лучшим вариантом для чтения метаданных.
Вот простой класс, который запускает процесс exiftool
и содержит метод execute()
для отправки команд этому процессу. Я также включил get_metadata()
для чтения метаданных в формате JSON:
import subprocess
import os
import json
class ExifTool(object):
sentinel = "{ready}\n"
def __init__(self, executable="/usr/bin/exiftool"):
self.executable = executable
def __enter__(self):
self.process = subprocess.Popen(
[self.executable, "-stay_open", "True", "-@", "-"],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
return self
def __exit__(self, exc_type, exc_value, traceback):
self.process.stdin.write("-stay_open\nFalse\n")
self.process.stdin.flush()
def execute(self, *args):
args = args + ("-execute\n",)
self.process.stdin.write(str.join("\n", args))
self.process.stdin.flush()
output = ""
fd = self.process.stdout.fileno()
while not output.endswith(self.sentinel):
output += os.read(fd, 4096)
return output[:-len(self.sentinel)]
def get_metadata(self, *filenames):
return json.loads(self.execute("-G", "-j", "-n", *filenames))
Этот класс написан как диспетчер контекста, чтобы обеспечить выход из процесса, если вы закончите. Вы можете использовать его как
with ExifTool() as e:
metadata = e.get_metadata(*filenames)
РЕДАКТИРОВАТЬ для python 3: чтобы это работало в python 3, необходимы два небольших изменения. Первый является дополнительным аргументом для subprocess.Popen
:
self.process = subprocess.Popen(
[self.executable, "-stay_open", "True", "-@", "-"],
universal_newlines=True,
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
Во-вторых, вам нужно декодировать серию байтов, возвращаемую os.read()
:
output += os.read(fd, 4096).decode('utf-8')
РЕДАКТИРОВАТЬ для Windows: чтобы это работало в Windows, sentinel
необходимо изменить на "{ready}\r\n"
, т.е.
sentinel = "{ready}\r\n"
В противном случае программа зависнет, потому что цикл while внутри execute() не остановится.
person
Sven Marnach
schedule
09.04.2012