def get_property_pages(self, files): # test file type if len(files) != 1: return file = files[0] if file.get_uri_scheme() != 'file': return # if mimetype corresponds to an image, read exif tags #if file.get_mime_type() in ('image/jpeg' 'image/png'): mimetype = file.get_mime_type().split('/') if mimetype[0] == "image": # create label and grid self.property_label = Gtk.Label('EXIF') self.property_label.show() self.grid = Gtk.Grid() self.grid.set_margin_start(10) self.grid.set_margin_end(10) self.grid.set_margin_top(5) self.grid.set_margin_bottom(5) self.grid.show() # display title self.dislayTag("<b>Tag</b>", "<b>Readable value</b>", "<b>Raw value</b>", 0, 0) gtk_separator = Gtk.Separator( orientation=Gtk.Orientation.HORIZONTAL) self.grid.attach(gtk_separator, 0, 1, 3, 1) # read metadata from file filename = unquote(file.get_uri()[7:]) self.tags = Metadata() self.tags.open_path(filename) # loop thru the tags index = 0 for name in self.tags: interpreted = self.tags.get_tag_interpreted_string(name)[0:64] string_raw = self.tags.get_tag_string(name)[0:64] if interpreted == string_raw: string_raw = "" else: string_raw = "<i>" + string_raw + "</i>" name = "<b>" + name + "</b>" self.dislayTag(name, interpreted, string_raw, 0, index + 2) index = index + 1 # declare main scrolled window self.window = Gtk.ScrolledWindow() self.window.add_with_viewport(self.grid) self.window.show_all() # return label and tab content return Nautilus.PropertyPage(name="NautilusPython::tags_info", label=self.property_label, page=self.window),
def get_preview_sizes(self, metadata: GExiv2.Metadata): previews = metadata.get_preview_properties() sizes_and_types = [] for idx, preview in enumerate(previews): image = metadata.get_preview_image(preview) sizes_and_types.append( (image.get_width(), image.get_height(), image.get_extension())) self.preview_size_and_types = "; ".join([ "{}x{} {}".format(width, height, ext[1:]) for width, height, ext in sizes_and_types ])
def thumbnail_extract(self, metadata: GExiv2.Metadata, size_in_bytes) -> bool: thumbnail = metadata.get_exif_thumbnail() if not thumbnail: previews = metadata.get_preview_properties() if previews: # In every RAW file I've analyzed, the smallest preview is always first preview = previews[0] thumbnail = metadata.get_preview_image(preview).get_data() if thumbnail == self.exif_thumbnail_or_preview: self.minimum_exif_read_size_in_bytes_thumbnail = size_in_bytes return True return False
def getMeta(path, args): m = Metadata(path) if args.print: print( 'getMeta: {} exif_tags, {} iptc_tags, {} xmp_tags, path {}, dateFromDirname {}' .format( len(m.get_exif_tags()), len(m.get_iptc_tags()), len(m.get_xmp_tags()), path, dateFromDirname.strftime(DATE_FORMAT) if dateFromDirname else None)) for t in m.get_tags(): # if t != 'Exif.Photo.MakerNote': # avoid big binary? item if any(x in t for x in [ 'Date', 'Image.Make', 'Model', 'Categories', 'GPS', 'Latitude', 'Longitude' ]): print('getMeta: {} -> {}'.format(t, m.get(t))) if any(x in t for x in [ 'Tags', 'LastKeywordXMP', 'HierarchicalSubject', 'CatalogSets', 'Subject', 'Keywords' ]): print('getMeta: {} => [ {} ]'.format( t, ', '.join(m.get_tag_multiple(t)))) return m
def assign_photo_attributes(self, metadata: GExiv2.Metadata) -> None: # I don't know how GExiv2 gets these values: self.width = metadata.get_pixel_width() self.height = metadata.get_pixel_height() try: self.orientation = metadata.get_tag_string('Exif.Image.Orientation') except KeyError: pass if metadata.has_tag('Exif.Image.Make') and metadata.has_tag('Exif.Image.Model'): self.model = '{} {}'.format( metadata.get_tag_string('Exif.Image.Make').strip(), metadata.get_tag_string('Exif.Image.Model').strip() ) self.has_gps = metadata.get_gps_info()[0] self.iso = metadata.get_iso_speed() self.datetime = photo_date_time(metadata)
def extract_thumbnail(self, metadata: GExiv2.Metadata) -> None: # not all files have an exif preview, but all CR2 & CR3 seem to exif_thumbnail = metadata.get_exif_thumbnail() self.process_exif_thumbnail(thumbnail=exif_thumbnail) previews = metadata.get_preview_properties() self.no_previews = len(previews) for idx, preview in enumerate(previews): image = metadata.get_preview_image(preview) if image.get_width() >= 160 and image.get_height() >= 120: preview_thumbnail = metadata.get_preview_image(preview).get_data() if self.has_exif_thumbnail: self.exif_thumbnail_and_preview_identical = preview_thumbnail == exif_thumbnail else: self.exif_thumbnail_or_preview = preview_thumbnail self.preview_source = PreviewSource(idx).name.replace('_', ' ').capitalize() self.preview_width = image.get_width() self.preview_height = image.get_height() self.preview_extension = image.get_extension() return
def metadata_comp_table(files): # Extract tags for each file tags = {} for f in files: exif = Metadata() exif.open_path(f) tags[f] = {(x, exif[x]) for x in exif.get_tags()} # Compute common tags intersecting all sets commontags = tags[files[0]] for f in tags: commontags = commontags.intersection(tags[f]) # Delete common tags for each entry for f in tags: tags[f] = tags[f] - commontags # Print results head = ["Tag"] + [os.path.basename(x) for x in files] tab = [] alluniquetags = set() for f in tags: alluniquetags |= ({x[0] for x in tags[f]}) for t in alluniquetags: aux = [t] for f in files: if t in [x[0] for x in tags[f]]: aux.append(dict(tags[f])[t][:200]) else: aux.append("-") tab.append(aux) t = tt.Texttable() t.header(head) t.add_rows(tab, header=False) t.set_deco(t.HEADER) t.set_chars(['-', '|', '+', '-']) maxw = len(max(alluniquetags, key=len)) if alluniquetags else 5 arrw = [maxw] + [25] * len(files) t.set_cols_width(arrw) print() print(t.draw()) print("\n(Unique fields only. Common EXIF tags have been omitted)") print()
def metadata_comp_table(files): # Extract tags for each file tags={} for f in files: exif=Metadata() exif.open_path(f) tags[f]={(x,exif[x]) for x in exif.get_tags()} # Compute common tags intersecting all sets commontags=tags[files[0]] for f in tags: commontags=commontags.intersection(tags[f]) # Delete common tags for each entry for f in tags: tags[f]=tags[f]-commontags # Print results head=["Tag"]+[os.path.basename(x) for x in files] tab=[] alluniquetags=set() for f in tags: alluniquetags|=({x[0] for x in tags[f]}) for t in alluniquetags: aux=[t] for f in files: if t in [x[0] for x in tags[f]]: aux.append(dict(tags[f])[t][:200]) else: aux.append("-") tab.append(aux) t=tt.Texttable() t.header(head) t.add_rows(tab,header=False) t.set_deco(t.HEADER) t.set_chars(['-','|','+','-']) maxw=len(max(alluniquetags,key=len)) if alluniquetags else 5 arrw=[maxw]+[25]*len(files) t.set_cols_width(arrw) print() print(t.draw()) print("\n(Unique fields only. Common EXIF tags have been omitted)") print()
def get_image_aspect_ratio(cls, file_phys_path): metadata = Metadata() metadata.open_path(file_phys_path) aspect_ratio = metadata.get_pixel_width() / metadata.get_pixel_height() # sideways rotation -> 90 or 270 degrees aspect ratio should be inverted if metadata.get_tag_long('Exif.Image.Orientation') in (6, 8): aspect_ratio = 1 / aspect_ratio return aspect_ratio
def get_property_pages(self, files): # default map size and zoom factor sizeMap = "512x512" zoomMap = "7" # test file type file = files[0] if len(files) != 1: return if file.get_uri_scheme() != 'file': return # if mimetype corresponds to JPG image, read data and populate tab mimetype = file.get_mime_type().split('/') if mimetype[0] in ('image'): # create tab self.tab = Gtk.Label('GPS') self.tab.show() # create grid self.grid = Gtk.Grid() self.grid.set_margin_start(10) self.grid.set_margin_end(10) self.grid.set_margin_top(5) self.grid.set_margin_bottom(5) self.grid.show() # create main scrolled window self.window = Gtk.ScrolledWindow() self.window.add_with_viewport(self.grid) self.window.show_all() # read metadata from file filename = unquote(file.get_uri()[7:]) self.tags = Metadata() self.tags.open_path(filename) # get signed GPS position latitude = self.tags.get_gps_latitude() longitude = self.tags.get_gps_longitude() altitude = self.tags.get_gps_altitude() # if no GPS data, return if latitude == 0 and longitude == 0 and altitude == 0: return # trunk GPS data to 6 digits parts = str(latitude).split(".") strLatitude = parts[0] + "." + parts[1][:6] parts = str(longitude).split(".") strLongitude = parts[0] + "." + parts[1][:6] strAltitude = str(altitude) # generate GPS position strPosition = strLatitude + ',' + strLongitude # generate Google Maps links urlMaps = 'https://www.google.com/maps/place/' + strPosition + '/@' + strPosition + ',' + zoomMap + 'z/' urlJpeg = 'https://maps.googleapis.com/maps/api/staticmap?maptype=hybrid&zoom=' + zoomMap + '&size=' + sizeMap urlJpeg += '¢er=' + strPosition + '&markers=' + strPosition + '&key=' + apikey # generate cache folder, and create if needed dirHomeCache = os.environ['HOME'] + '/.cache' dirGeotagCache = os.getenv('XDG_CACHE_HOME', dirHomeCache) + '/geotag' if not os.path.exists(dirGeotagCache): os.makedirs(dirGeotagCache) # generate cache file names fileMap = dirGeotagCache + '/map_' + strLatitude + '_' + strLongitude + '_' + sizeMap + '_' + zoomMap + '.png' fileDesc = dirGeotagCache + '/map_' + strLatitude + '_' + strLongitude + '.txt' # if description is not in the cache, retrieve it from Nominatim if not os.path.exists(fileDesc): # retrieve place description geolocator = Nominatim(user_agent="nautilus-exif-geotag") location = geolocator.reverse(strPosition) strDescription = location.address # write description to cache file = codecs.open(fileDesc, "w", "utf-8") file.write(strDescription) file.close() # if map is not in the cache, retrieve it from Google Maps if not os.path.exists(fileMap): urllib.request.urlretrieve(urlJpeg, fileMap) # retrieve description from cache file = codecs.open(fileDesc, "r", "utf-8") strDescription = file.read() file.close() # dislay GPS data self.DisplayText("<b>latitude</b>", 0, 0, 1, 1, "right") self.DisplayText(strLatitude, 1, 0, 1, 1, "left") self.DisplayText("<b>longitude</b>", 0, 1, 1, 1, "right") self.DisplayText(strLongitude, 1, 1, 1, 1, "left") self.DisplayText("<b>altitude</b>", 0, 2, 1, 1, "right") self.DisplayText(strAltitude, 1, 2, 1, 1, "left") # dislay address value = re.compile(',').sub('\n', strDescription) self.DisplayText("<b>address</b>", 2, 0, 1, 3, "right") self.DisplayText("<a href='" + urlMaps + "'>" + value + "</a>", 3, 0, 1, 5, "left") # dislay gmaps image self.DisplayImage(fileMap, 0, 5, 4, 1) # return label and tab content return Nautilus.PropertyPage( name="NautilusPython::geotag_info", label=self.tab, page=self.window ),
def metadata_summary(path): exif = Metadata() exif.open_path(path) taglist = exif.get_tags() # Date date = [] if 'Exif.Photo.DateTimeOriginal' in taglist: date.append(exif['Exif.Photo.DateTimeOriginal']) if 'Xmp.exif.DateTimeOriginal' in taglist: date.append(exif['Xmp.exif.DateTimeOriginal']) #date.append(time.ctime(os.path.getmtime(path))) if len(date) > 0: date = time.strftime("%d/%m/%Y %H:%M:%S", time.strptime(date[0], "%Y:%m:%d %H:%M:%S")) else: date = "" # Orientation ori = exif.get('Exif.Image.Orientation', "?") # Tags tags = [] if 'Iptc.Application2.Keywords' in taglist: tags.append(exif['Iptc.Application2.Keywords']) if 'Xmp.dc.subject' in taglist: tags += exif['Xmp.dc.subject'].split(",") if 'Xmp.digiKam.TagsList' in taglist: tags += exif['Xmp.digiKam.TagsList'].split(",") if 'Xmp.MicrosoftPhoto.LastKeywordXMP' in taglist: tags += exif['Xmp.MicrosoftPhoto.LastKeywordXMP'].split(",") tags = [x.strip() for x in tags] tags = list(set(tags)) tags.sort() # Title aux = [] title = "" if 'Iptc.Application2.Caption' in taglist: aux.append(exif['Iptc.Application2.Caption']) if 'Xmp.dc.title' in taglist: aux.append(exif['Xmp.dc.title']) if 'Iptc.Application2.Headline' in taglist: aux.append(exif['Iptc.Application2.Headline']) if len(aux) > 0: title = aux[0] # Software aux = [] soft = "" if 'Exif.Image.Software' in taglist: aux.append(exif['Exif.Image.Software']) if 'Iptc.Application2.Program' in taglist: aux.append(exif['Iptc.Application2.Program']) if len(aux) > 0: soft = list(set(aux))[0] # Shorten title and soft if len(title) > 13: title = title[:10] + "..." if len(soft) > 15: soft = soft[:12] + "..." dinfo = { "date": date, "orientation": ori, "tags": tags, "title": title, "software": soft } return dinfo
def photo_date_time( metadata: GExiv2.Metadata, full_file_name: Optional[str] = None, file_type: Optional[FileType] = None, ) -> Union[datetime.datetime, Any]: """ Returns in python datetime format the date and time the image was recorded. Tries these tags, in order: Exif.Photo.DateTimeOriginal Exif.Image.DateTimeOriginal Exif.Image.DateTime :return: metadata value, or None if value is not present. """ # GExiv2.Metadata used to provide get_date_time(), but as of version # 0.10.09 it appears to have been removed! # In any case, get_date_time() seems to have tried only one key, Exif.Photo.DateTimeOriginal # Try other keys too, and with a more flexible datetime parser. # For example some or maybe all Android 6.0 DNG files use Exif.Image.DateTimeOriginal do_log = full_file_name is not None and file_type is not None for tag in ('Exif.Photo.DateTimeOriginal', 'Exif.Image.DateTimeOriginal', 'Exif.Image.DateTime'): try: dt_string = metadata.get_tag_string(tag) except Exception: pass else: if dt_string is None: continue # ignore all zero values, e.g. '0000:00:00 00:00:00' try: digits = int(''.join(c for c in dt_string if c.isdigit())) except ValueError: if do_log: logging.warning( 'Unexpected malformed date time metadata value %s for photo %s', dt_string, full_file_name) else: if not digits: if do_log: logging.debug( 'Ignoring date time metadata value %s for photo %s', dt_string, full_file_name) else: try: return datetime.datetime.strptime( dt_string, "%Y:%m:%d %H:%M:%S") except (ValueError, OverflowError): if do_log: logging.debug( 'Error parsing date time metadata %s for photo %s; attempting ' 'flexible approach', dt_string, full_file_name) try: dtr, fs = flexible_date_time_parser( dt_string.strip()) if do_log: logging.debug( "Extracted photo time %s using flexible approach", dtr.strftime(fs)) return dtr except AssertionError: if do_log: logging.warning( "Error extracting date time metadata '%s' for %s %s", dt_string, file_type, full_file_name) except (ValueError, OverflowError): if do_log: logging.warning( "Error parsing date time metadata '%s' for %s %s", dt_string, file_type, full_file_name) except Exception: if do_log: logging.error( "Unknown error parsing date time metadata '%s' for %s %s", dt_string, file_type, full_file_name) return None
def get_exiv2(path): exif = {} for tag in m.get_tags(m(path)): exif[tag] = m.get(m(path), tag)
class TagsPropertyPage(GObject.GObject, Nautilus.PropertyPageProvider): def __init__(self): pass # -------------------- # Display one tag # -------------------- def dislayTag(self, name, interpreted, raw_value, x, y): # check if third column is needed width = 1 if raw_value == "": width = 2 # dislay name gtk_label = Gtk.Label() gtk_label.set_markup(name) gtk_label.set_alignment(1.0, 0) gtk_label.set_padding(10, 2) gtk_label.show() self.grid.attach(gtk_label, x, y, 1, 1) # dislay interpreted string gtk_label = Gtk.Label() gtk_label.set_markup(interpreted) gtk_label.set_alignment(0.0, 0) gtk_label.set_padding(10, 2) gtk_label.show() self.grid.attach(gtk_label, x + 1, y, width, 1) # if different, dislay raw string if raw_value != "": gtk_label = Gtk.Label() gtk_label.set_markup(raw_value) gtk_label.set_alignment(0.0, 0) gtk_label.set_padding(10, 2) gtk_label.show() self.grid.attach(gtk_label, x + 2, y, 1, 1) return # ------------------------- # Display property tab # ------------------------- def get_property_pages(self, files): # test file type if len(files) != 1: return file = files[0] if file.get_uri_scheme() != 'file': return # if mimetype corresponds to an image, read exif tags #if file.get_mime_type() in ('image/jpeg' 'image/png'): mimetype = file.get_mime_type().split('/') if mimetype[0] == "image": # create label and grid self.property_label = Gtk.Label('EXIF') self.property_label.show() self.grid = Gtk.Grid() self.grid.set_margin_start(10) self.grid.set_margin_end(10) self.grid.set_margin_top(5) self.grid.set_margin_bottom(5) self.grid.show() # display title self.dislayTag("<b>Tag</b>", "<b>Readable value</b>", "<b>Raw value</b>", 0, 0) gtk_separator = Gtk.Separator( orientation=Gtk.Orientation.HORIZONTAL) self.grid.attach(gtk_separator, 0, 1, 3, 1) # read metadata from file filename = unquote(file.get_uri()[7:]) self.tags = Metadata() self.tags.open_path(filename) # loop thru the tags index = 0 for name in self.tags: interpreted = self.tags.get_tag_interpreted_string(name)[0:64] string_raw = self.tags.get_tag_string(name)[0:64] if interpreted == string_raw: string_raw = "" else: string_raw = "<i>" + string_raw + "</i>" name = "<b>" + name + "</b>" self.dislayTag(name, interpreted, string_raw, 0, index + 2) index = index + 1 # declare main scrolled window self.window = Gtk.ScrolledWindow() self.window.add_with_viewport(self.grid) self.window.show_all() # return label and tab content return Nautilus.PropertyPage(name="NautilusPython::tags_info", label=self.property_label, page=self.window),
class ExifColumnExtension(GObject.GObject, Nautilus.ColumnProvider, Nautilus.InfoProvider): def __init__(self): pass # ----------------------------- # List of available columns # ----------------------------- def get_columns(self): return ( Nautilus.Column(name="NautilusPython::ExifWidth", attribute="exif_width", label=" Width ", description="Image width"), Nautilus.Column(name="NautilusPython::ExifHeight", attribute="exif_height", label=" Height ", description="Image height"), Nautilus.Column(name="NautilusPython::ExifAperture", attribute="exif_apert", label="Aperture", description="Aperture"), Nautilus.Column(name="NautilusPython::ExifFocal", attribute="exif_focal", label="Focal", description="Focal length (35mm)"), Nautilus.Column(name="NautilusPython::ExifCity", attribute="exif_city", label="City", description="City"), Nautilus.Column(name="NautilusPython::ExifCountry", attribute="exif_country", label="Country", description="Country"), Nautilus.Column(name="NautilusPython::ExifGPS", attribute="exif_gps", label="GPS", description="GPS"), Nautilus.Column(name="NautilusPython::ExifMaker", attribute="exif_maker", label="Manufacturer", description="Camera manufacturer"), Nautilus.Column(name="NautilusPython::ExifModel", attribute="exif_model", label="Model", description="Camera model"), ) # ------------------------ # Retrieve file values # ------------------------ def update_file_info(self, file): # test file type if file.get_uri_scheme() != 'file': return # read data only if image file mimetype = file.get_mime_type().split('/') if mimetype[0] == "image": # format filename filename = unquote(file.get_uri()[7:]) # get metadata self.tags = Metadata() self.tags.open_path(filename) # image width tag_value = "" if self.tags.has_tag('Exif.Photo.PixelXDimension'): tag_value = self.tags.get_tag_string( 'Exif.Photo.PixelXDimension') if tag_value == "" and self.tags.has_tag('Exif.Image.ImageWidth'): tag_value = self.tags.get_tag_string('Exif.Image.ImageWidth') file.add_string_attribute('exif_width', tag_value) # image height tag_value = "" if self.tags.has_tag('Exif.Photo.PixelYDimension'): tag_value = self.tags.get_tag_string( 'Exif.Photo.PixelYDimension') if tag_value == "" and self.tags.has_tag('Exif.Image.ImageLength'): tag_value = self.tags.get_tag_string('Exif.Image.ImageLength') file.add_string_attribute('exif_height', tag_value) # camera manufacturer tag_value = "" if self.tags.has_tag('Xmp.VendorInfo.Manufacturer'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.VendorInfo.Manufacturer') if tag_value == "" and self.tags.has_tag('Exif.Image.Make'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Image.Make') file.add_string_attribute('exif_maker', tag_value) # camera model tag_value = "" if self.tags.has_tag('Xmp.VendorInfo.Model'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.VendorInfo.Model') if tag_value == "" and self.tags.has_tag('Exif.Image.Model'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Image.Model') file.add_string_attribute('exif_model', tag_value) # camera focal length tag_value = "" if self.tags.has_tag('Xmp.Exif.FocalLengthIn35mmFormat'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.Exif.FocalLengthIn35mmFormat') if tag_value == "" and self.tags.has_tag( 'Exif.Photo.FocalLengthIn35mmFilm'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.FocalLengthIn35mmFilm') if tag_value == "" and self.tags.has_tag('Exif.Photo.FocalLength'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.FocalLength') file.add_string_attribute('exif_focal', tag_value) # camera aperture tag_value = "" if self.tags.has_tag('Xmp.Exif.ApertureValue'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.Exif.ApertureValue') if tag_value == "" and self.tags.has_tag( 'Exif.Photo.ApertureValue'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.ApertureValue') if tag_value == "" and self.tags.has_tag('Exif.Photo.FNumber'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.FNumber') file.add_string_attribute('exif_apert', tag_value) # city tag tag_value = "" if self.tags.has_tag('Xmp.City'): tag_value = self.tags.get_tag_interpreted_string('Xmp.City') if tag_value == "" and self.tags.has_tag('Xmp.photoshop.City'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.photoshop.City') if tag_value == "" and self.tags.has_tag('Iptc.City'): tag_value = self.tags.get_tag_interpreted_string('Iptc.City') file.add_string_attribute('exif_city', tag_value) # country tag tag_value = "" if self.tags.has_tag('Xmp.CountryName'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.CountryName') if tag_value == "" and self.tags.has_tag('Xmp.photoshop.Country'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.photoshop.Country') file.add_string_attribute('exif_country', tag_value) # GPS tag tag_value = "no" if self.tags.has_tag('Xmp.Exif.GPSLatitude'): tag_value = "yes" if tag_value == "no" and self.tags.has_tag( 'Xmp.LocationDetails.GPSLatitude'): tag_value = "yes" if tag_value == "no" and self.tags.has_tag( 'Exif.GPSInfo.GPSLatitude'): tag_value = "yes" file.add_string_attribute('exif_gps', tag_value) # else, file is not an image else: file.add_string_attribute('exif_maker', "") file.add_string_attribute('exif_model', "") file.add_string_attribute('exif_focal', "") file.add_string_attribute('exif_city', "") file.add_string_attribute('exif_country', "") file.add_string_attribute('exif_gps', "")
def update_file_info(self, file): # test file type if file.get_uri_scheme() != 'file': return # read data only if image file mimetype = file.get_mime_type().split('/') if mimetype[0] == "image": # format filename filename = unquote(file.get_uri()[7:]) # get metadata self.tags = Metadata() self.tags.open_path(filename) # image width tag_value = "" if self.tags.has_tag('Exif.Photo.PixelXDimension'): tag_value = self.tags.get_tag_string( 'Exif.Photo.PixelXDimension') if tag_value == "" and self.tags.has_tag('Exif.Image.ImageWidth'): tag_value = self.tags.get_tag_string('Exif.Image.ImageWidth') file.add_string_attribute('exif_width', tag_value) # image height tag_value = "" if self.tags.has_tag('Exif.Photo.PixelYDimension'): tag_value = self.tags.get_tag_string( 'Exif.Photo.PixelYDimension') if tag_value == "" and self.tags.has_tag('Exif.Image.ImageLength'): tag_value = self.tags.get_tag_string('Exif.Image.ImageLength') file.add_string_attribute('exif_height', tag_value) # camera manufacturer tag_value = "" if self.tags.has_tag('Xmp.VendorInfo.Manufacturer'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.VendorInfo.Manufacturer') if tag_value == "" and self.tags.has_tag('Exif.Image.Make'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Image.Make') file.add_string_attribute('exif_maker', tag_value) # camera model tag_value = "" if self.tags.has_tag('Xmp.VendorInfo.Model'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.VendorInfo.Model') if tag_value == "" and self.tags.has_tag('Exif.Image.Model'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Image.Model') file.add_string_attribute('exif_model', tag_value) # camera focal length tag_value = "" if self.tags.has_tag('Xmp.Exif.FocalLengthIn35mmFormat'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.Exif.FocalLengthIn35mmFormat') if tag_value == "" and self.tags.has_tag( 'Exif.Photo.FocalLengthIn35mmFilm'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.FocalLengthIn35mmFilm') if tag_value == "" and self.tags.has_tag('Exif.Photo.FocalLength'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.FocalLength') file.add_string_attribute('exif_focal', tag_value) # camera aperture tag_value = "" if self.tags.has_tag('Xmp.Exif.ApertureValue'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.Exif.ApertureValue') if tag_value == "" and self.tags.has_tag( 'Exif.Photo.ApertureValue'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.ApertureValue') if tag_value == "" and self.tags.has_tag('Exif.Photo.FNumber'): tag_value = self.tags.get_tag_interpreted_string( 'Exif.Photo.FNumber') file.add_string_attribute('exif_apert', tag_value) # city tag tag_value = "" if self.tags.has_tag('Xmp.City'): tag_value = self.tags.get_tag_interpreted_string('Xmp.City') if tag_value == "" and self.tags.has_tag('Xmp.photoshop.City'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.photoshop.City') if tag_value == "" and self.tags.has_tag('Iptc.City'): tag_value = self.tags.get_tag_interpreted_string('Iptc.City') file.add_string_attribute('exif_city', tag_value) # country tag tag_value = "" if self.tags.has_tag('Xmp.CountryName'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.CountryName') if tag_value == "" and self.tags.has_tag('Xmp.photoshop.Country'): tag_value = self.tags.get_tag_interpreted_string( 'Xmp.photoshop.Country') file.add_string_attribute('exif_country', tag_value) # GPS tag tag_value = "no" if self.tags.has_tag('Xmp.Exif.GPSLatitude'): tag_value = "yes" if tag_value == "no" and self.tags.has_tag( 'Xmp.LocationDetails.GPSLatitude'): tag_value = "yes" if tag_value == "no" and self.tags.has_tag( 'Exif.GPSInfo.GPSLatitude'): tag_value = "yes" file.add_string_attribute('exif_gps', tag_value) # else, file is not an image else: file.add_string_attribute('exif_maker', "") file.add_string_attribute('exif_model', "") file.add_string_attribute('exif_focal', "") file.add_string_attribute('exif_city', "") file.add_string_attribute('exif_country', "") file.add_string_attribute('exif_gps', "")
def metadata_summary(path): exif=Metadata() exif.open_path(path) taglist=exif.get_tags() # Date date=[] if 'Exif.Photo.DateTimeOriginal' in taglist: date.append(exif['Exif.Photo.DateTimeOriginal']) if 'Xmp.exif.DateTimeOriginal' in taglist: date.append(exif['Xmp.exif.DateTimeOriginal']) #date.append(time.ctime(os.path.getmtime(path))) if len(date)>0: date=time.strftime("%d/%m/%Y %H:%M:%S",time.strptime(date[0],"%Y:%m:%d %H:%M:%S")) else: date="" # Orientation ori=exif.get('Exif.Image.Orientation',"?") # Tags tags=[] if 'Iptc.Application2.Keywords' in taglist: tags.append(exif['Iptc.Application2.Keywords']) if 'Xmp.dc.subject' in taglist: tags+=exif['Xmp.dc.subject'].split(",") if 'Xmp.digiKam.TagsList' in taglist: tags+=exif['Xmp.digiKam.TagsList'].split(",") if 'Xmp.MicrosoftPhoto.LastKeywordXMP' in taglist: tags+=exif['Xmp.MicrosoftPhoto.LastKeywordXMP'].split(",") tags=[x.strip() for x in tags] tags=list(set(tags)) tags.sort() # Title aux=[] title="" if 'Iptc.Application2.Caption' in taglist: aux.append(exif['Iptc.Application2.Caption']) if 'Xmp.dc.title' in taglist: aux.append(exif['Xmp.dc.title']) if 'Iptc.Application2.Headline' in taglist: aux.append(exif['Iptc.Application2.Headline']) if len(aux)>0: title=aux[0] # Software aux=[] soft="" if 'Exif.Image.Software' in taglist: aux.append(exif['Exif.Image.Software']) if 'Iptc.Application2.Program' in taglist: aux.append(exif['Iptc.Application2.Program']) if len(aux)>0: soft=list(set(aux))[0] # Shorten title and soft if len(title)>13: title=title[:10]+"..." if len(soft)>15: soft=soft[:12]+"..." dinfo={"date":date,"orientation":ori,"tags":tags,"title":title,"software":soft} return dinfo