#!/usr/bin/python # -*- encoding: utf-8 -*- # # exif-rewrite - Rewrites EXIF tags according to a translation dictionary # # Usage: exif-rewrite rules.ini JPG_files # # Copyright (C) Miguel Ángel Vilela # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. import ConfigParser import pyexiv2 import re import sys MultipleValuesRegex = re.compile('^(\+|\-)[^,]+(, *(\+|\-)[^,]+)*$') encoding = sys.argv[1] if encoding in ('latin-1', 'utf-8'): config = sys.argv[2] images = sys.argv[3:] else: config = sys.argv[1] images = sys.argv[2:] # Load rules from .ini file conf = ConfigParser.RawConfigParser() conf.read(config) search_tags = set(conf.get('General', 'Search.Tags').split(',')) replace_tags = set(conf.get('General', 'Replace.Tags').split(',')) replace_tags_names = dict([(tag.lower().strip(), tag.strip()) for tag in replace_tags]) search_values = set(conf.sections()) - set(['General']) # Rewrite EXIF tags on each image for image in images: print "Reading '%s'" % image im = pyexiv2.Image(image) im.readMetadata() image_tags = set(im.exifKeys() + im.iptcKeys()) interesting_tags = list(search_tags.intersection(image_tags)) already_matched_values = [] for search_tag in interesting_tags: search_tag_modified = False original_value = im[search_tag] if type(original_value) == type(""): original_value = [original_value] if encoding == 'latin-1': original_value = [v.decode('latin-1').encode('utf-8') for v in original_value] # elif encoding == 'utf-8': # original_value = [v.decode('utf-8').encode('latin-1') for v in im[search_tag]] values = set(original_value) for value in values.intersection(search_values): if value in already_matched_values: # print "Ignoring match: %s contains '%s'" % (search_tag, value) continue # print "Found match: %s contains '%s'" % (search_tag, value) for replace_tag in conf.options(value): replace_data = conf.get(value, replace_tag) if encoding == 'latin-1': replace_data = replace_data.decode('utf-8').encode('latin-1') elif encoding == 'utf-8': replace_data = replace_data.decode('latin-1').encode('utf-8') if MultipleValuesRegex.match(replace_data): actual_data = im[replace_tags_names[replace_tag]] if type(actual_data) == type(""): actual_data = list([actual_data]) else: actual_data = list(actual_data) for new_value in replace_data.split(','): op, new_value = new_value.strip()[0], new_value.strip()[1:] if op == '+': if new_value in actual_data: # print "Will not append '%s' to %s AGAIN" % (new_value, replace_tags_names[replace_tag]) continue print "Append '%s' to %s" % (new_value, replace_tags_names[replace_tag]) # Append current search_tag for re-consideration, but avoid matching just-appended value already_matched_values.append(value) interesting_tags.append(replace_tags_names[replace_tag]) actual_data.append(new_value) search_tag_modified = True elif op == '-': print "Remove '%s' from %s" % (new_value, replace_tags_names[replace_tag]) if new_value in actual_data: actual_data.remove(new_value) search_tag_modified = True else: print "This should never happen!" sys.exit(1) if len(actual_data) == 1: actual_data.append('') actual_data = [e for e in list(set(actual_data)) if len(e) > 1] # Eliminate duplicate and one-char values if set(im[replace_tags_names[replace_tag]]) != set(actual_data): im[replace_tags_names[replace_tag]] = actual_data search_tag_modified = True # print "%s now contains: %s" % (replace_tags_names[replace_tag], im[replace_tags_names[replace_tag]]) else: if replace_tags_names[replace_tag] in image_tags: if (type(im[replace_tags_names[replace_tag]]) == type(replace_data) and \ im[replace_tags_names[replace_tag]] == replace_data) or \ str(im[replace_tags_names[replace_tag]]) == str(replace_data) or \ (type(im[replace_tags_names[replace_tag]]) == type(()) and \ ' '.join([str(x) for x in im[replace_tags_names[replace_tag]]]) == replace_data): continue print "Setting %s to '%s'" % (replace_tags_names[replace_tag], replace_data) im[replace_tags_names[replace_tag]] = replace_data search_tag_modified = True # Write metadata after each interesting_tag since the list may get new ones if not search_tag_modified: continue original_value = im[search_tag] if type(original_value) == type(""): original_value = [original_value] im[search_tag] = [d for d in original_value if len(d) > 1] print "Writing '%s'" % image im.writeMetadata() print "Done with '%s'" % image