def trigger_capture(camera, shutter, start_time=(monotonic_time() + 0.05), meta=[], download_timeout=5.0): monotonic_alarm(start_time) o = gph_cmd('capture-image-and-download', timeout=shutter + download_timeout) s = filter(lambda x: x.startswith(_saving_file_response), o) if len(s) != 1: print("Couldn't retrieve file at the end of capture.") raise IOError filename = s[0][len(_saving_file_response):] exifd = ImageMetadata(filename) exifd.read() # Add a piece of debug info to exif header meta.append(('TriggerStartTime', start_time)) for (name, value) in meta: tag = 'Xmp.xmp.GPhotolapser.' + name exifd[tag] = XmpTag(tag, value=str(value)) exifd.write() return filename
def correctRotaion(fl_input): print("imageProcessing::correctRotaion(fl_input)") try: # save the result metadata = ImageMetadata(fl_input) metadata.read() # Get the thumbnail of the image from EXIF. thumb = metadata.exif_thumbnail thumb.set_from_file(fl_input) thumb.write_to_file('512_' + "a") thumb.erase() # Rewrite the thumbnail with corrected image. metadata.write() # Return the output file name. return (True) except Exception as e: print("Error occurs in imageProcessing::correctRotaion(in_file)") print(str(e)) error.ErrorMessageImageProcessing(details=str(e), show=True, language="en") return (None)
def trigger_expose_bulb(camera, bulb, start_time=(monotonic_time() + 0.05), meta=[], download_timeout=3.5): end_time = start_time + bulb monotonic_alarm(start_time) gph_cmd(camera.bulb_begin) monotonic_alarm(end_time) gph_cmd(camera.bulb_end) o = gph_cmd('wait-event-and-download %is' % int(floor(download_timeout)), timeout=download_timeout) # Should download the image s = filter(lambda x: x.startswith(_saving_file_response), o) if len(s) != 1: print("Couldn't retrieve file at the end of bulb exposure.") raise IOError filename = s[0][len(_saving_file_response):] exifd = ImageMetadata(filename) exifd.read() # Add a piece of debug info to exif header meta.append(('BulbHoldTime', bulb)) meta.append(('TriggerStartTime', start_time)) for (name, value) in meta: tag = 'Xmp.xmp.GPhotolapser.' + name exifd[tag] = XmpTag(tag, value=str(value)) exifd.write() return filename
def write_metadata(src_image, dest_image): meta_source = ImageMetadata(src_image) meta_dest = ImageMetadata(dest_image) meta_dest.read() meta_source.read() for k in meta_source.exif_keys[:]: try: meta_dest[k] = ExifTag(k, meta_source[k].value) except Exception as e: continue meta_dest.write(preserve_timestamps=True)
def setComment(self, filePath, comment): """ Set comment info to the image specified filePath: full path of the image file comment: contains comment tag info """ metadata = ImageMetadata(filePath) metadata.read() try: metadata.comment = comment metadata.write() return True except Exception as e: return False
def add_tag_to_picture(filename: str, tag: str): metadata = ImageMetadata(filename) metadata.read() current_tags = [] if 'Exif.Photo.UserComment' in metadata: userdata = json.loads(metadata['Exif.Photo.UserComment'].value) if userdata["tags"] is not None: current_tags = list(userdata["tags"]) tags = [tag] + current_tags metadata = ImageMetadata(filename) metadata.read() userdata = {'tags': tags} metadata['Exif.Photo.UserComment'] = json.dumps(userdata) metadata.write() return True
def remove_tag_from_picture(filename: str, tag: str): metadata = ImageMetadata(filename) metadata.read() if 'Exif.Photo.UserComment' not in metadata: print("Exif.Photo.UserComment does not exist in metadata") return False userdata = json.loads(metadata['Exif.Photo.UserComment'].value) current_tags = [] if userdata["tags"] is not None else list( userdata["tags"]) if len(current_tags) > 0: current_tags.remove(tag) metadata = ImageMetadata(filename) metadata.read() userdata = {'tags': current_tags} metadata['Exif.Photo.UserComment'] = json.dumps(userdata) metadata.write() return True
def write(self, fname, instr, date, time, xaxis, yaxis, xunits, yunits, filter): metadata = ImageMetadata(fname) metadata.read() userdata = { 'File name': fname, 'Instrument': instr, 'Date': date, 'Time': time, 'X-Axis': xaxis, 'X-units': xunits, 'Y-units': yunits, 'Y-Axis': yaxis, 'Filter': filter, } metadata['Exif.Photo.UserComment'] = json.dumps(userdata) metadata.write()
if (ver_pyexiv2 < ver_pyexiv2_min): print 'Newer version of pyexiv2 required.' sys.exit(1) if (len(sys.argv) != 3): print 'Usage: ' + sys.argv[0] + ' <sourcefile> <targetfile>' sys.exit(1) # Load the image, read the metadata and extract the thumbnail data src_metadata = ImageMetadata(sys.argv[1]) src_metadata.read() tgt_metadata = ImageMetadata(sys.argv[2]) tgt_metadata.read() for groupName, tagList in copy_tags.iteritems(): # print groupName # print tagList for i, tagName in enumerate(tagList): fullkey = 'Exif.' + groupName + '.' + tagName try: tag = src_metadata[fullkey] print fullkey + ': ' + tag.raw_value except KeyError: print "WARNING: can't find EXIF key '" + fullkey + "'" tgt_metadata[fullkey] = tag # we're done, so write the updates to the target file (preserving # the file's timestamps via the 'True' parameter) tgt_metadata.write(True)
class Photograph(Coordinates): """Represents a single photograph and it's location in space and time.""" liststore = get_obj('loaded_photos') def __init__(self, filename, thumb_size=200): """Initialize new Photograph object's attributes with default values.""" self.filename = filename self.thm_size = thumb_size self.label = None self.exif = None self.thumb = None self.manual = None self.camera = None self.iter = None def read(self): """Load exif data from disk.""" self.exif = ImageMetadata(self.filename) self.timestamp = None self.altitude = None self.latitude = None self.longitude = None self.timezone = None self.manual = False try: self.exif.read() except TypeError: raise IOError self.camera = get_camera(self) # Try to get a thumbnail. try: self.thumb = GdkPixbuf.Pixbuf.new_from_file_at_size( self.filename, self.thm_size, self.thm_size) except GObject.GError: if len(self.exif.previews) > 0: data = self.exif.previews[-1].data elif len(self.exif.exif_thumbnail.data) > 0: data = self.exif.exif_thumbnail.data else: raise IOError self.thumb = GdkPixbuf.Pixbuf.new_from_stream_at_scale( Gio.MemoryInputStream.new_from_data(data, None), self.thm_size, self.thm_size, True, None) # If we're reloading, then hide the label and clear the ListStore, # but if we're loading afresh then we'll need a new iter... if self.label is not None: self.label.hide() if self.thm_size < 250: if self.iter is None: self.iter = self.liststore.append() self.liststore.set_row(self.iter, [self.filename, self.long_summary(), self.thumb, self.timestamp]) self.calculate_timestamp() try: self.latitude = dms_to_decimal( *self.exif[GPS + 'Latitude'].value + [self.exif[GPS + 'LatitudeRef'].value] ) self.longitude = dms_to_decimal( *self.exif[GPS + 'Longitude'].value + [self.exif[GPS + 'LongitudeRef'].value] ) except KeyError: pass try: self.altitude = float(self.exif[GPS + 'Altitude'].value) if int(self.exif[GPS + 'AltitudeRef'].value) > 0: self.altitude *= -1 except KeyError: pass def calculate_timestamp(self): """Determine the timestamp based on the currently selected timezone. This method relies on the TZ environment variable to be set before it is called. If you don't set TZ before calling this method, then it implicitely assumes that the camera and the computer are set to the same timezone. """ try: self.timestamp = int(mktime( self.exif['Exif.Photo.DateTimeOriginal'].value.timetuple())) except KeyError: self.timestamp = int(stat(self.filename).st_mtime) self.timestamp += self.camera.get_offset() if self.label is not None: auto_timestamp_comparison(self) def write(self): """Save exif data to photo file on disk.""" if self.altitude is not None: self.exif[GPS + 'Altitude'] = float_to_rational(self.altitude) self.exif[GPS + 'AltitudeRef'] = '0' if self.altitude >= 0 else '1' self.exif[GPS + 'Latitude'] = decimal_to_dms(self.latitude) self.exif[GPS + 'LatitudeRef'] = 'N' if self.latitude >= 0 else 'S' self.exif[GPS + 'Longitude'] = decimal_to_dms(self.longitude) self.exif[GPS + 'LongitudeRef'] = 'E' if self.longitude >= 0 else 'W' self.exif[GPS + 'MapDatum'] = 'WGS-84' self.exif.write() modified.discard(self) self.liststore.set_value(self.iter, 1, self.long_summary()) def set_location(self, lat, lon, ele=None): """Alter the coordinates of this photo.""" if ele is not None: self.altitude = ele self.latitude = lat self.longitude = lon self.position_label() self.lookup_geoname() self.modify_summary() def modify_summary(self): """Update the text displayed in the GtkListStore.""" modified.add(self) self.liststore.set_value(self.iter, 1, ('<b>%s</b>' % self.long_summary())) def position_label(self): """Maintain correct position and visibility of ChamplainLabel.""" if self.label.get_parent() is None: return if self.valid_coords(): self.label.set_location(self.latitude, self.longitude) self.label.show() if self.label.get_selected(): self.label.raise_top() else: self.label.hide() def set_label_highlight(self, highlight, transparent): """Set the highlightedness of the given photo's ChamplainLabel.""" if self.label.get_property('visible'): self.label.set_scale(*[1.1 if highlight else 1] * 2) self.label.set_selected(highlight) self.label.set_opacity(64 if transparent and not highlight else 255) if highlight: self.label.raise_top() def set_geodata(self, data): """Override Coordinates.set_geodata to apply directly into IPTC.""" city, state, country, tz = data self.exif[IPTC + 'City'] = [city or ''] self.exif[IPTC + 'ProvinceState'] = [get_state(country, state) or ''] self.exif[IPTC + 'CountryName'] = [get_country(country) or ''] self.exif[IPTC + 'CountryCode'] = [country or ''] self.timezone = tz.strip() self.camera.set_found_timezone(self.timezone) def pretty_geoname(self): """Override Coordinates.pretty_geoname to read from IPTC.""" names = [] for key in [ 'City', 'ProvinceState', 'CountryName' ]: try: names.extend(self.exif[IPTC + key].values) except KeyError: pass return ', '.join([name for name in names if name]) def destroy(self): """Agony!""" self.label.unmap() self.label.destroy() self.camera.photos.discard(self) del photos[self.filename] modified.discard(self) self.liststore.remove(self.iter)
class Photograph(Coordinates): """Represents a single photograph and it's location in space and time.""" def __init__(self, filename, callback, thumb_size=200): """Initialize new Photograph object's attributes with default values.""" self.filename = filename self.callback = callback self.thm_size = thumb_size self.label = None self.iter = None self.exif = None self.thumb = None self.manual = None def read(self): """Load exif data from disk.""" self.exif = ImageMetadata(self.filename) self.timestamp = None self.altitude = None self.latitude = None self.longitude = None self.timezone = None self.manual = False try: self.exif.read() except TypeError: raise IOError Camera(self.exif) # Try to get a thumbnail. try: self.thumb = GdkPixbuf.Pixbuf.new_from_file_at_size( self.filename, self.thm_size, self.thm_size) except GObject.GError: if len(self.exif.previews) > 0: data = self.exif.previews[-1].data elif len(self.exif.exif_thumbnail.data) > 0: data = self.exif.exif_thumbnail.data else: raise IOError self.thumb = GdkPixbuf.Pixbuf.new_from_stream_at_scale( Gio.MemoryInputStream.new_from_data(data, None), self.thm_size, self.thm_size, True, None) self.calculate_timestamp() try: self.latitude = dms_to_decimal( *self.exif[GPS + 'Latitude'].value + [self.exif[GPS + 'LatitudeRef'].value]) self.longitude = dms_to_decimal( *self.exif[GPS + 'Longitude'].value + [self.exif[GPS + 'LongitudeRef'].value]) except KeyError: pass try: self.altitude = float(self.exif[GPS + 'Altitude'].value) if int(self.exif[GPS + 'AltitudeRef'].value) > 0: self.altitude *= -1 except KeyError: pass def calculate_timestamp(self): """Determine the timestamp based on the currently selected timezone. This method relies on the TZ environment variable to be set before it is called. If you don't set TZ before calling this method, then it implicitely assumes that the camera and the computer are set to the same timezone. """ try: self.timestamp = int( mktime(self.exif['Exif.Photo.DateTimeOriginal'].value. timetuple())) except KeyError: self.timestamp = int(stat(self.filename).st_mtime) def write(self): """Save exif data to photo file on disk.""" if self.altitude is not None: self.exif[GPS + 'Altitude'] = float_to_rational(self.altitude) self.exif[GPS + 'AltitudeRef'] = '0' if self.altitude >= 0 else '1' self.exif[GPS + 'Latitude'] = decimal_to_dms(self.latitude) self.exif[GPS + 'LatitudeRef'] = 'N' if self.latitude >= 0 else 'S' self.exif[GPS + 'Longitude'] = decimal_to_dms(self.longitude) self.exif[GPS + 'LongitudeRef'] = 'E' if self.longitude >= 0 else 'W' self.exif[GPS + 'MapDatum'] = 'WGS-84' self.exif.write() def set_location(self, lat, lon, ele=None): """Alter the coordinates of this photo.""" if ele is not None: self.altitude = ele self.latitude = lat self.longitude = lon self.position_label() self.lookup_geoname() self.callback(self) def position_label(self): """Maintain correct position and visibility of ChamplainLabel.""" if self.valid_coords(): self.label.set_location(self.latitude, self.longitude) self.label.show() if self.label.get_selected(): self.label.raise_top() else: self.label.hide() def set_label_highlight(self, highlight, transparent): """Set the highlightedness of the given photo's ChamplainLabel.""" if self.label.get_property('visible'): self.label.set_scale(*[1.1 if highlight else 1] * 2) self.label.set_selected(highlight) self.label.set_opacity( 64 if transparent and not highlight else 255) if highlight: self.label.raise_top() def set_geodata(self, data): """Override Coordinates.set_geodata to apply directly into IPTC.""" city, state, country, tz = data self.exif[IPTC + 'City'] = [city or ''] self.exif[IPTC + 'ProvinceState'] = [get_state(country, state) or ''] self.exif[IPTC + 'CountryName'] = [get_country(country) or ''] self.exif[IPTC + 'CountryCode'] = [country or ''] self.timezone = tz.strip() def pretty_geoname(self): """Override Coordinates.pretty_geoname to read from IPTC.""" names = [] for key in ['City', 'ProvinceState', 'CountryName']: try: names.extend(self.exif[IPTC + key].values) except KeyError: pass length = sum(map(len, names)) return format_list(names, ',\n' if length > 35 else ', ')
print '[not set]' # Add a new tag key = 'Iptc.Application2.Keywords' keywords = ['little', 'big', 'man'] metadata[key] = keywords print_key_value(metadata, key) # Print a list of all the keys of the XMP tags in the image print os.linesep, 'XMP keys:', metadata.xmp_keys try: # Print the value of the Xmp.dc.subject tag key = 'Xmp.dc.subject' print_key_value(metadata, key) # Set the value of the Xmp.dc.subject tag metadata[key] = keywords print_key_value(metadata, key) except KeyError: print '[not set]' # Add a new tag key = 'Xmp.dc.title' metadata[key] = {'x-default': 'Sunset', 'fr': 'Coucher de soleil'} print_key_value(metadata, key) # Write back the metadata to the file metadata.write()
class Photograph(Coordinates): """Represents a single photograph and it's location in space and time.""" def __init__(self, filename, callback, thumb_size=200): """Initialize new Photograph object's attributes with default values.""" self.filename = filename self.callback = callback self.thm_size = thumb_size self.label = None self.iter = None self.exif = None self.thumb = None self.manual = None def read(self): """Load exif data from disk.""" self.exif = ImageMetadata(self.filename) self.timestamp = None self.altitude = None self.latitude = None self.longitude = None self.timezone = None self.manual = False try: self.exif.read() except TypeError: raise IOError Camera(self.exif) # Try to get a thumbnail. try: self.thumb = GdkPixbuf.Pixbuf.new_from_file_at_size( self.filename, self.thm_size, self.thm_size) except GObject.GError: if len(self.exif.previews) > 0: data = self.exif.previews[-1].data elif len(self.exif.exif_thumbnail.data) > 0: data = self.exif.exif_thumbnail.data else: raise IOError self.thumb = GdkPixbuf.Pixbuf.new_from_stream_at_scale( Gio.MemoryInputStream.new_from_data(data, None), self.thm_size, self.thm_size, True, None) self.calculate_timestamp() try: self.latitude = dms_to_decimal( *self.exif[GPS + 'Latitude'].value + [self.exif[GPS + 'LatitudeRef'].value] ) self.longitude = dms_to_decimal( *self.exif[GPS + 'Longitude'].value + [self.exif[GPS + 'LongitudeRef'].value] ) except KeyError: pass try: self.altitude = float(self.exif[GPS + 'Altitude'].value) if int(self.exif[GPS + 'AltitudeRef'].value) > 0: self.altitude *= -1 except KeyError: pass def calculate_timestamp(self): """Determine the timestamp based on the currently selected timezone. This method relies on the TZ environment variable to be set before it is called. If you don't set TZ before calling this method, then it implicitely assumes that the camera and the computer are set to the same timezone. """ try: self.timestamp = int(mktime( self.exif['Exif.Photo.DateTimeOriginal'].value.timetuple())) except KeyError: self.timestamp = int(stat(self.filename).st_mtime) def write(self): """Save exif data to photo file on disk.""" if self.altitude is not None: self.exif[GPS + 'Altitude'] = float_to_rational(self.altitude) self.exif[GPS + 'AltitudeRef'] = '0' if self.altitude >= 0 else '1' self.exif[GPS + 'Latitude'] = decimal_to_dms(self.latitude) self.exif[GPS + 'LatitudeRef'] = 'N' if self.latitude >= 0 else 'S' self.exif[GPS + 'Longitude'] = decimal_to_dms(self.longitude) self.exif[GPS + 'LongitudeRef'] = 'E' if self.longitude >= 0 else 'W' self.exif[GPS + 'MapDatum'] = 'WGS-84' self.exif.write() def set_location(self, lat, lon, ele=None): """Alter the coordinates of this photo.""" if ele is not None: self.altitude = ele self.latitude = lat self.longitude = lon self.position_label() self.lookup_geoname() self.callback(self) def position_label(self): """Maintain correct position and visibility of ChamplainLabel.""" if self.valid_coords(): self.label.set_location(self.latitude, self.longitude) self.label.show() if self.label.get_selected(): self.label.raise_top() else: self.label.hide() def set_label_highlight(self, highlight, transparent): """Set the highlightedness of the given photo's ChamplainLabel.""" if self.label.get_property('visible'): self.label.set_scale(*[1.1 if highlight else 1] * 2) self.label.set_selected(highlight) self.label.set_opacity(64 if transparent and not highlight else 255) if highlight: self.label.raise_top() def set_geodata(self, data): """Override Coordinates.set_geodata to apply directly into IPTC.""" city, state, country, tz = data self.exif[IPTC + 'City'] = [city or ''] self.exif[IPTC + 'ProvinceState'] = [get_state(country, state) or ''] self.exif[IPTC + 'CountryName'] = [get_country(country) or ''] self.exif[IPTC + 'CountryCode'] = [country or ''] self.timezone = tz.strip() def pretty_geoname(self): """Override Coordinates.pretty_geoname to read from IPTC.""" names = [] for key in [ 'City', 'ProvinceState', 'CountryName' ]: try: names.extend(self.exif[IPTC + key].values) except KeyError: pass length = sum(map(len, names)) return format_list(names, ',\n' if length > 35 else ', ')