2012-04-09 5 views
5

Я ищу, чтобы использовать exiftool для сканирования тегов EXIF ​​из моих фотографий и видео. Это исполняемый файл perl. Каков наилучший способ сделать это? Существуют ли библиотеки Python для этого? Или мне нужно напрямую вызвать исполняемый файл и проанализировать вывод? (Последний кажется грязным.) Спасибо.Вызвать exiftool из скрипта python?

Причина, по которой я спрашиваю, это потому, что в настоящее время я использую pyexiv2, у которого нет поддержки для видео. Perl exiftool имеет очень широкую поддержку для изображений и видео, и я хотел бы использовать его.

+1

Вы должны прочитать документацию модуля suprocess: HTTP://docs.python.org/library/subprocess.html – mandel

+1

Я загрузил более полную версию кода в свой ответ на https://github.com/smarnach/pyexiftool. –

ответ

18

Чтобы избежать запуска нового процесса для каждого изображения, вы должны запустить exiftool, используя флаг -stay_open. Затем вы можете отправлять команды в процесс через stdin и читать вывод на stdout. 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", "[email protected]", "-"], 
      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) 

EDIT для Python 3: Для того, чтобы получить эту работу в питона необходимо-два небольшие изменения. Первый является дополнительным аргументом в пользу subprocess.Popen:

self.process = subprocess.Popen(
     [self.executable, "-stay_open", "True", "[email protected]", "-"], 
     universal_newlines=True, 
     stdin=subprocess.PIPE, stdout=subprocess.PIPE) 

Во-вторых, вы должны декодировать серии байт, возвращаемый os.read():

output += os.read(fd, 4096).decode('utf-8') 
+0

Спасибо, это было очень полезно. Как передать команды exiftool так, чтобы исполняемый файл оставался открытым? Если я поместил исполняемый файл в функцию parseImage(), не будет ли она повторно открываться при каждом вызове функции? – ensnare

+0

@ensnare: Я включил немного кода. Я улучшу код за несколько месяцев. –

+0

Yup, это здорово. Спасибо. – ensnare

Смежные вопросы