#!/usr/bin/python # -*- encoding: utf-8 -*- # # exif-film-tags-iptc - Updates EXIF for film picture from IPTC tags # # Usage: exif-film-tags-iptc 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 commands import datetime import os import pyexiv2 import re import sys # These EXIF tags will always be assigned the same value StaticMap = { "Exif.Image.Artist": "Miguel Ángel Vilela (miguev.net)".decode('utf-8'), "Exif.Image.Copyright": "© Miguel Ángel Vilela (miguev.net)".decode('utf-8'), "Exif.Photo.UserComment": "http://www.flickr.com/photos/miguev/", } # IPTC tags to EXIF tags mapping. TagMap = { # Camera body: AF/MF Matrix/Spot/Centered # Exif.Image.Make Ascii # Exif.Image.Model Ascii # Exif.Photo.ExposureProgram Short 1 1 + idx(Manual,Auto,Aperture priority,Shutter priority,Creative program,Action program,Portrait mode,Landscape mode) # Exif.Photo.MeteringMode Short 1 1 + idx(Average,Center weighted average,Spot,Multi-spot,Multi-segment,Partial) # Exif.Nikon3.Focus Ascii 7 MANUAL/AF-S/AF-C "Nikon FM-2n": { "Exif.Image.Make": "NIKON CORPORATION", "Exif.Image.Model": "NIKON FM-2n", "Exif.Photo.ExposureProgram": "1", "Exif.Photo.MeteringMode": "2", "Exif.Nikon3.Focus": "MANUAL", }, "Olympus OM-1": { "Exif.Image.Make": "OLYMPUS IMAGING CORP.", "Exif.Image.Model": "OM-1", "Exif.Photo.ExposureProgram": "1", "Exif.Photo.MeteringMode": "2", "Exif.Nikon3.Focus": "MANUAL", }, "Nikon F90X": { "Exif.Image.Make": "NIKON CORPORATION", "Exif.Image.Model": "NIKON F90X", }, "Chinon MA-8": { "Exif.Image.Make": "CHINON CORPORATION", "Exif.Image.Model": "CHINON MA-8", "Exif.Photo.ExposureProgram": "1", "Exif.Photo.MeteringMode": "2", "Exif.Nikon3.Focus": "MANUAL", }, "Samsung Vega 70D": { "Exif.Image.Make": "Samsung Techwin", "Exif.Image.Model": "Vega 70D", "Exif.Photo.FocalLength": "350/10", "Exif.Photo.FocalLengthIn35mmFilm": "35" , "Exif.Photo.MaxApertureValue" : "35/10", "Exif.Photo.FNumber": "80/10", "Exif.Photo.ExposureTime": "1/60", "Exif.Photo.Flash": "0", "Exif.Photo.ExposureProgram": "2", "Exif.Photo.MeteringMode": "2", "Exif.Nikon3.Focus": "AF-S", "Exif.Nikon3.Lens": "350/10 1050/10 35/10 56/10", }, # Lens: # Exif.Photo.FocalLengthIn35mmFilm Short 1 len # Exif.Photo.FocalLength Rational 1 len x 10/10 # Exif.Photo.MaxApertureValue Rational 1 FM x 10/10 # Exif.Nikon3.Lens Rational 4 (wide tele Fw Ft) x 10/10 # Exif.Nikon3.LensType Byte 1 2 ^ idx(MF,D,G,VR) "Chinon 28mm 1:3.5": { # 28-70mm set at 28mm "Exif.Photo.FocalLengthIn35mmFilm" : "28", "Exif.Photo.FocalLength" : "280/10", "Exif.Photo.MaxApertureValue" : "35/10", "Exif.Nikon3.Lens": "280/10 700/10 35/10 45/10", }, "Chinon 50mm 1:4": { # 28-70mm set at 50mm "Exif.Photo.FocalLengthIn35mmFilm" : "50", "Exif.Photo.FocalLength" : "500/10", "Exif.Photo.MaxApertureValue" : "40/10", "Exif.Nikon3.Lens": "280/10 700/10 35/10 45/10", }, "Chinon 70mm 1:4.5": { # 28-70mm set at 70mm "Exif.Photo.FocalLengthIn35mmFilm" : "70", "Exif.Photo.FocalLength" : "700/10", "Exif.Photo.MaxApertureValue" : "45/10", "Exif.Nikon3.Lens": "280/10 700/10 35/10 45/10", }, "Chinon 28-70mm 1:3.5-4.5": { "Exif.Nikon3.Lens": "280/10 700/10 35/10 45/10", }, # Nikkor lenses for Nikon "AF Nikkor 20mm 1:2.8D": { "Exif.Photo.FocalLengthIn35mmFilm" : "20", "Exif.Photo.FocalLength" : "200/10", "Exif.Photo.MaxApertureValue" : "28/10", "Exif.Nikon3.Lens": "200/10 200/10 28/10 28/10", "Exif.Nikon3.LensType": "2", }, "AF Nikkor 28mm 1:2.8": { "Exif.Photo.FocalLengthIn35mmFilm" : "28", "Exif.Photo.FocalLength" : "280/10", "Exif.Photo.MaxApertureValue" : "28/10", "Exif.Nikon3.Lens": "280/10 280/10 28/10 28/10", "Exif.Nikon3.LensType": "0", }, "AF Nikkor 35mm 1:3.5D": { # 35-105mm set at 35mm "Exif.Photo.FocalLengthIn35mmFilm" : "35", "Exif.Photo.FocalLength" : "350/10", "Exif.Photo.MaxApertureValue" : "35/10", "Exif.Nikon3.Lens": "350/10 1050/10 35/10 56/10", "Exif.Nikon3.LensType": "2", }, "AF Nikkor 50mm 1:1.4D": { "Exif.Photo.FocalLengthIn35mmFilm" : "50", "Exif.Photo.FocalLength" : "500/10", "Exif.Photo.MaxApertureValue" : "14/10", "Exif.Nikon3.Lens": "500/10 500/10 14/10 14/10", "Exif.Nikon3.LensType": "2", }, "AF Nikkor 85mm 1:1.8": { "Exif.Photo.FocalLengthIn35mmFilm" : "85", "Exif.Photo.FocalLength" : "850/10", "Exif.Photo.MaxApertureValue" : "18/10", "Exif.Nikon3.Lens": "850/10 850/10 18/10 18/10", "Exif.Nikon3.LensType": "0", }, "AF Nikkor 105mm 1:5.6D": { # 35-105mm set at 105mm "Exif.Photo.FocalLengthIn35mmFilm" : "105", "Exif.Photo.FocalLength" : "1050/10", "Exif.Photo.MaxApertureValue" : "56/10", "Exif.Nikon3.Lens": "350/10 1050/10 35/10 56/10", "Exif.Nikon3.LensType": "2", }, "AF Nikkor 35-105mm 1:3.5-4.5D": { "Exif.Nikon3.Lens": "350/10 1050/10 35/10 56/10", "Exif.Nikon3.LensType": "2", }, # 2nd brand lenses for Nikon (Hanimex, Sigma, Tokina) "Hanimex 135mm 1:2.8": { "Exif.Photo.FocalLengthIn35mmFilm" : "135", "Exif.Photo.FocalLength" : "1350/10", "Exif.Photo.MaxApertureValue" : "28/10", "Exif.Nikon3.Lens": "1350/10 1350/10 28/10 28/10", "Exif.Nikon3.LensType": "1", }, "Sigma Macro 50mm 1:2.8 DG EX": { "Exif.Photo.FocalLengthIn35mmFilm" : "50", "Exif.Photo.FocalLength" : "500/10", "Exif.Photo.MaxApertureValue" : "28/10", "Exif.Nikon3.Lens": "500/10 500/10 28/10 28/10", "Exif.Nikon3.LensType": "2", }, "Tokina 12-24mm 1:4": { # 12-24mm at 18mm "Exif.Photo.FocalLengthIn35mmFilm" : "18", "Exif.Photo.FocalLength" : "180/10", "Exif.Photo.MaxApertureValue" : "40/10", "Exif.Nikon3.Lens": "120/10 240/10 40/10 40/10", "Exif.Nikon3.LensType": "6", }, "Tokina 12-24mm 1:4": { # 12-24mm at 20mm "Exif.Photo.FocalLengthIn35mmFilm" : "20", "Exif.Photo.FocalLength" : "200/10", "Exif.Photo.MaxApertureValue" : "40/10", "Exif.Nikon3.Lens": "120/10 240/10 40/10 40/10", "Exif.Nikon3.LensType": "6", }, "Tokina 12-24mm 1:4": { # 12-24mm at 24mm "Exif.Photo.FocalLengthIn35mmFilm" : "24", "Exif.Photo.FocalLength" : "240/10", "Exif.Photo.MaxApertureValue" : "40/10", "Exif.Nikon3.Lens": "120/10 240/10 40/10 40/10", "Exif.Nikon3.LensType": "6", }, "Tokina 12-24mm 1:4": { "Exif.Photo.MaxApertureValue" : "40/10", "Exif.Nikon3.Lens": "120/10 240/10 40/10 40/10", "Exif.Nikon3.LensType": "6", }, # Zuiko lenses for Olympus OM-1 "Zuiko 24mm 1:2.8": { "Exif.Photo.FocalLengthIn35mmFilm" : "24", "Exif.Photo.FocalLength" : "240/10", "Exif.Photo.MaxApertureValue" : "28/10", "Exif.Nikon3.Lens": "240/10 240/10 28/10 28/10", "Exif.Nikon3.LensType": "1", }, "Zuiko 35mm 1:2.8": { "Exif.Photo.FocalLengthIn35mmFilm" : "35", "Exif.Photo.FocalLength" : "350/10", "Exif.Photo.MaxApertureValue" : "28/10", "Exif.Nikon3.Lens": "350/10 350/10 28/10 28/10", "Exif.Nikon3.LensType": "1", }, "Zuiko Micro 50mm 1:3.5": { "Exif.Photo.FocalLengthIn35mmFilm" : "50", "Exif.Photo.FocalLength" : "500/10", "Exif.Photo.MaxApertureValue" : "35/10", "Exif.Nikon3.Lens": "500/10 500/10 35/10 35/10", "Exif.Nikon3.LensType": "1", }, "Zuiko 100mm 1:2.8": { "Exif.Photo.FocalLengthIn35mmFilm" : "100", "Exif.Photo.FocalLength" : "1000/10", "Exif.Photo.MaxApertureValue" : "28/10", "Exif.Nikon3.Lens": "1000/10 1000/10 28/10 28/10", "Exif.Nikon3.LensType": "1", }, # Film: # Exif.Photo.ISOSpeedRatings Short 1 ISO # Exif.Nikon3.ISOSpeed Short 2 0 ISO "Kodak VPS 160": { "Exif.Photo.ISOSpeedRatings": "160", }, "Agfa NPS 160": { "Exif.Photo.ISOSpeedRatings": "160", }, "Fujifilm Superia X-tra 400": { "Exif.Photo.ISOSpeedRatings": "400", }, "Fujifilm Reala 100": { "Exif.Photo.ISOSpeedRatings": "100", }, "Fujifilm Sensia 100": { "Exif.Photo.ISOSpeedRatings": "100", }, "Fujifilm PRO 160": { "Exif.Photo.ISOSpeedRatings": "160", }, "Kodak T-Max 100": { "Exif.Photo.ISOSpeedRatings": "100", }, "Kodak T-Max 400": { "Exif.Photo.ISOSpeedRatings": "400", }, "Kodak T-Max 3200": { "Exif.Photo.ISOSpeedRatings": "3200", }, "Ilford HP5 400": { "Exif.Photo.ISOSpeedRatings": "400", }, "Ilford HP5+ 125": { "Exif.Photo.ISOSpeedRatings": "125", }, # Focus mode # Exif.Nikon3.Focus Ascii 7 MANUAL/AF-S/AF-C "AF-C" : { "Exif.Nikon3.Focus": "AF-C", }, "AF-S" : { "Exif.Nikon3.Focus": "AF-S", }, "Manual" : { "Exif.Nikon3.Focus": "MANUAL", }, # Metering mode # Exif.Photo.MeteringMode Short 1 1 + idx(Average,Center weighted average,Spot,Multi-spot,Multi-segment,Partial) "Matrix" : { "Exif.Photo.MeteringMode": "5", }, "Ponderada" : { "Exif.Photo.MeteringMode": "2", }, "Spot" : { "Exif.Photo.MeteringMode": "3", }, # Program used # Exif.Photo.ExposureProgram Short 1 1 + idx(Manual,Auto,Aperture priority,Shutter priority,Creative program,Action program,Portrait mode,Landscape mode) "Auto" : { "Exif.Photo.ExposureProgram": "2", }, "Deportes" : { "Exif.Photo.ExposureProgram": "6", }, "Manual" : { "Exif.Photo.ExposureProgram": "1", }, "Paisaje" : { "Exif.Photo.ExposureProgram": "8", }, "Prioridad de apertura" : { "Exif.Photo.ExposureProgram": "3", }, "Prioridad de velocidad" : { "Exif.Photo.ExposureProgram": "4", }, "Retrato" : { "Exif.Photo.ExposureProgram": "7", }, # Exposure values # Exif.Photo.FNumber Rational 1 Fn x 10/10 # Exif.Photo.ExposureTime Rational 1 1/exp x 10/10 "f/1.4": { "Exif.Photo.FNumber": "14/10", }, "f/2": { "Exif.Photo.FNumber": "20/10", }, "f/2.8": { "Exif.Photo.FNumber": "28/10", }, "f/4": { "Exif.Photo.FNumber": "40/10", }, "f/5.6": { "Exif.Photo.FNumber": "56/10", }, "f/8": { "Exif.Photo.FNumber": "80/10", }, "f/11": { "Exif.Photo.FNumber": "110/10", }, "f/16": { "Exif.Photo.FNumber": "160/10", }, "f/22": { "Exif.Photo.FNumber": "220/10", }, "f/32": { "Exif.Photo.FNumber": "320/10", }, "1 s": { "Exif.Photo.ExposureTime": "10/10", }, "1/2 s": { "Exif.Photo.ExposureTime": "10/20", }, "1/4 s": { "Exif.Photo.ExposureTime": "10/40", }, "1/8 ms": { "Exif.Photo.ExposureTime": "10/80", }, "1/15 s": { "Exif.Photo.ExposureTime": "10/150", }, "1/30 s": { "Exif.Photo.ExposureTime": "10/300", }, "1/60 s": { "Exif.Photo.ExposureTime": "10/600", }, "1/125 s": { "Exif.Photo.ExposureTime": "10/1250", }, "1/250 s": { "Exif.Photo.ExposureTime": "10/2500", }, "1/500 s": { "Exif.Photo.ExposureTime": "10/5000", }, "1/1000 s": { "Exif.Photo.ExposureTime": "10/10000", }, "1/2000 s": { "Exif.Photo.ExposureTime": "10/20000", }, "1/4000 s": { "Exif.Photo.ExposureTime": "10/40000", }, "1/8000 s": { "Exif.Photo.ExposureTime": "10/80000", }, } # Get all relevant images images = sys.argv[1:] # Compile regular expressions ExifTagRegex = dict() for exif_tag in TagMap.keys(): ExifTagRegex[exif_tag] = re.compile('/?%s$' % exif_tag) # Assign EXIF commands to each IPTC tag exif_cmds = dict([(iptc_tag, []) for iptc_tag in TagMap.keys()]) for iptc_tag in TagMap.keys(): for exif_tag, value in TagMap[iptc_tag].iteritems(): exif_cmds[iptc_tag].append((exif_tag, value)) # Set EXIF tags on each image for image in images: im = pyexiv2.Image(image) im.readMetadata() for exif_tag, value in StaticMap.iteritems(): im[exif_tag] = value.encode('utf-8') if 'Iptc.Application2.Keywords' not in im.iptcKeys(): continue for iptc_tag in im['Iptc.Application2.Keywords']: for exif_tag, regex in ExifTagRegex.iteritems(): if regex.match(iptc_tag): for tag, value in exif_cmds[exif_tag]: im[tag] = value # print exif_tag, tag, value if 'Exif.Image.DateTime' not in im.exifKeys(): if 'Exif.Photo.DateTimeOriginal' not in im.exifKeys(): fstat = os.stat(image) im['Exif.Image.DateTime'] = datetime.datetime.fromtimestamp( fstat[-2]).strftime('%Y:%m:%d %H:%M:%S') im['Exif.Photo.DateTimeOriginal'] = im['Exif.Image.DateTime'] else: im['Exif.Image.DateTime'] = im['Exif.Photo.DateTimeOriginal'] if 'Exif.Photo.DateTimeOriginal' not in im.exifKeys(): im['Exif.Photo.DateTimeOriginal'] = im['Exif.Image.DateTime'] im.writeMetadata() # print "Done with %s" % image