def get_metadata(path): try: exif = GExiv2.Metadata(path=path) except TypeError: exif = GExiv2.Metadata() exif.open_path(path) return exif
def build_calibration_matrices(i, prev_sensor, K_matrices, filename1, filename2): '''Extract exif metadata from image files, and use them to build the 2 calibration matrices.''' def get_sensor_sizes(i, prev_sensor, metadata1, metadata2): '''Looks up sensor width from the database based on the camera model.''' #focal length in pixels = (image width in pixels) * (focal length in mm) / (CCD width in mm) if i == 0: sensor_1 = cam_db.get_sensor_size( metadata1['Exif.Image.Model'].strip().upper()) sensor_2 = cam_db.get_sensor_size( metadata2['Exif.Image.Model'].strip().upper()) elif i >= 1: sensor_1 = prev_sensor sensor_2 = cam_db.get_sensor_size(metadata2['Exif.Image.Model']) metadata1 = GExiv2.Metadata(filename1) metadata2 = GExiv2.Metadata(filename2) # if False and metadata1.get_supports_exif() and metadata2.get_supports_exif(): # sensor_1, sensor_2 = get_sensor_sizes(i, prev_sensor, metadata1, metadata2) # else: # if metadata1.get_supports_exif() == False: # print "Exif data not available for ", filename1 # if metadata2.get_supports_exif() == False: # print "Exif data not available for ", filename2 # sys.exit("Please try again.") # CDANCETTE : Fix sensor size at 30mm sensor_1, sensor_2 = 6.35, 6.35 focal = 50 #3.8 # 50mm # CDANCETTE # Calibration matrix for camera 1 (K1) # f1_mm = metadata1.get_focal_length() f1_mm = focal w1 = metadata1.get_pixel_width() h1 = metadata1.get_pixel_height() f1_px = (w1 * f1_mm) / sensor_1 K1 = np.array([[f1_px, 0, w1 / 2], [0, f1_px, h1 / 2], [0, 0, 1]]) # Calibration matrix for camera 2 (K2) # f2_mm = metadata2.get_focal_length() f2_mm = focal w2 = metadata2.get_pixel_width() h2 = metadata2.get_pixel_height() f2_px = (w2 * f2_mm) / sensor_2 K2 = np.array([[f2_px, 0, w2 / 2], [0, f2_px, h2 / 2], [0, 0, 1]]) if i == 0: K_matrices.append(K1) K_matrices.append(K2) elif i >= 1: K_matrices.append(K2) return sensor_2, K_matrices
def resize(self, src, dst): src_meta = GExiv2.Metadata(src) src_p = QPixmap(src) dst_p = src_p.scaled(4500, 3000, Qt.KeepAspectRatio, Qt.SmoothTransformation) dst_p.save(src) shutil.move(src, dst) # copy all the metadata dst_meta = GExiv2.Metadata(dst) for tag in src_meta.get_tags(): dst_meta[tag] = src_meta[tag] dst_meta.save_file()
def comparePicturesByExifDate(self, curOrigFullFileName): try: src_exif = GExiv2.Metadata(self.absCopiesOrigDateiName) src_ExifDate = src_exif.get_date_time().strftime('%Y%m%d%H%M%S') #logging.DEBUG("src-exifTimeStamp for " + self.fileBaseName + " is " + src_ExifDate) tgt_exif = GExiv2.Metadata(curOrigFullFileName) tgt_ExifDate = tgt_exif.get_date_time().strftime('%Y%m%d%H%M%S') #logging.DEBUG("tgt-exifTimeStamp for " + os.path.basename(curOrigFullFileName) + " is " +tgt_ExifDate) ) if src_ExifDate == tgt_ExifDate: return True else: return False except: logging.debug("Image does not have exiv date time") return False
def write_metadata(self, filepath, info): metadata = GExiv2.Metadata() metadata.open_path(filepath) compressor_name = "compressor v[{}]".format(info["version"]) # Exif.Image.ProcessingSoftware is overwritten by Lightroom when the final export is done key = "Exif.Image.ProcessingSoftware"; metadata.set_tag_string(key, compressor_name) key = "Exif.Image.Software"; metadata.set_tag_string(key, compressor_name) try: key = "Exif.Image.ExposureTime"; metadata.set_exif_tag_rational(key, info["exposure_time"], 1) except Exception as e: key = "Exif.Image.ExposureTime"; metadata.set_exif_tag_rational(key, info["exposure_time"]) key = "Exif.Image.ImageNumber"; metadata.set_tag_long(key, info["exposure_count"]) key = "Exif.Image.DateTimeOriginal"; metadata.set_tag_string(key, info["capture_date"].strftime(self.EXIF_DATE_FORMAT)) key = "Exif.Image.DateTime"; metadata.set_tag_string(key, info["compressing_date"].strftime(self.EXIF_DATE_FORMAT)) if info["focal_length"] is not None: try: key = "Exif.Image.FocalLength"; metadata.set_exif_tag_rational(key, info["focal_length"]) except Exception as e: key = "Exif.Image.FocalLength"; metadata.set_exif_tag_rational(key, info["focal_length"], 1) # TODO GPS Location metadata.save_file(filepath) self.log.debug("metadata written to {}".format(filepath))
def add_meta_data(self, img_path, comment="", rotation="landscape"): # Comment tags used by various programs: http://redmine.yorba.org/projects/shotwell/wiki/PhotoTags # All the supported tags: http://www.exiv2.org/metadata.html metadata = GExiv2.Metadata(img_path) metadata['Iptc.Application2.DateCreated'] = self.developed.date( ).strftime('%Y-%m-%d') metadata[ 'Iptc.Application2.DigitizationDate'] = self.last_digitized.date( ).strftime('%Y-%m-%d') metadata[ 'Iptc.Application2.DigitizationTime'] = self.last_digitized.time( ).strftime('%H:%M:%S%z') metadata['Exif.Photo.DateTimeOriginal'] = self.developed.date( ).strftime('%Y-%m-%d') metadata[ 'Exif.Photo.DateTimeDigitized'] = self.last_digitized.strftime( '%Y-%m-%d %H:%M:%S') metadata['Iptc.Application2.Caption'] = comment metadata['Exif.Image.ImageDescription'] = comment # We already rotated correctly, so specify that there are no further # rotations. #See: http://sylvana.net/jpegcrop/exif_orientation.html metadata['Exif.Image.Orientation'] = '1' metadata.save_file()
def initialise(cls, config_store, verbosity): if not GExiv2.initialize(): raise RuntimeError('Failed to initialise GExiv2') GExiv2.log_set_level( max(GExiv2.LogLevel.DEBUG, min(GExiv2.LogLevel.ERROR, 4 - verbosity))) GExiv2.log_use_glib_logging() # Recent versions of Exiv2 have these namespaces defined, but # older versions may not recognise them. The xapGImg URL is # invalid, but Photini doesn't write xapGImg so it doesn't # matter. for prefix, name in (('exifEX', 'http://cipa.jp/exif/1.0/'), ('xapGImg', 'http://ns.adobe.com/xxx/'), ('xmpGImg', 'http://ns.adobe.com/xap/1.0/g/img/'), ('xmpRights', 'http://ns.adobe.com/xap/1.0/rights/')): GExiv2.Metadata.register_xmp_namespace(name, prefix) # Gexiv2 won't register the 'Iptc4xmpExt' namespace as its # abbreviated version 'iptcExt' is already defined. This kludge # registers it by reading some data with the full namespace data = XMP_WRAPPER.format( 'xmlns:Iptc4xmpExt="http://iptc.org/std/Iptc4xmpExt/2008-02-29/"') # open the data to register the namespace GExiv2.Metadata().open_buf(data.encode('utf-8')) # make list of possible character encodings cls.encodings = ['utf-8', 'iso8859-1', 'ascii'] char_set = locale.getdefaultlocale()[1] if char_set: try: name = codecs.lookup(char_set).name if name not in cls.encodings: cls.encodings.append(name) except LookupError: pass
def merge_sc(self, other): # merge sidecar data into image file data, ignoring thumbnails raw_sc = GExiv2.Metadata() raw_sc.open_path(other._path) # allow exiv2 to infer Exif tags from XMP for tag in raw_sc.get_exif_tags(): if tag.startswith('Exif.Thumbnail'): continue # ignore inferred datetime values the exiv2 gets wrong # (I think it's adding the local timezone offset) if tag in ('Exif.Image.DateTime', 'Exif.Photo.DateTimeOriginal', 'Exif.Photo.DateTimeDigitized'): self.clear_tag(tag) else: value = raw_sc.get_tag_string(tag) if value: self.set_tag_string(tag, value) # copy all XMP tags except inferred Exif tags for tag in raw_sc.get_xmp_tags(): if tag.startswith('Xmp.xmp.Thumbnails'): continue ns = tag.split('.')[1] if ns in ('exif', 'exifEX', 'tiff', 'aux'): # exiv2 will already have supplied the equivalent Exif tag pass elif self.get_tag_type(tag) == 'XmpText': value = raw_sc.get_tag_string(tag) if value: self.set_tag_string(tag, value) else: value = raw_sc.get_tag_multiple(tag) if value: self.set_tag_multiple(tag, value)
def UpdateFileMetadata(filename, datetime): exif = GExiv2.Metadata(filename) if exif is not None: fileDate = GetDateFromExif(exif) if fileDate is not None: fileDate = datetime.strptime(fileDate, DATE_FORMAT) # date within acceptable limit. don't update if abs((fileDate - datetime).days) <= FILE_METADATA_DATE_TOLERANCE: return log('Updating exif: %s to date: %s', \ filename, datetime.strftime(DATE_FORMAT)) if DRY_RUN == False: if exif is not None: exif['Exif.Photo.DateTimeOriginal'] = datetime.strftime( DATE_FORMAT) exif['Exif.Photo.DateTimeDigitized'] = datetime.strftime( DATE_FORMAT) exif['Exif.Image.DateTime'] = datetime.strftime(DATE_FORMAT) exif['Exif.Image.DateTimeOriginal'] = datetime.strftime( DATE_FORMAT) exif.save_file() xmpfile = XMPFiles(file_path=filename, open_forupdate=True) xmp = xmpfile.get_xmp() if xmp is not None: for xmpConst in XMP_CONSTANTS: for dateConst in DATE_CONSTANTS: if xmp.does_property_exist(xmpConst, dateConst): xmp.set_property( \ xmpConst, dateConst, datetime.strftime(DATE_FORMAT_XMP)) if (xmpfile.can_put_xmp(xmp)): xmpfile.put_xmp(xmp) xmpfile.close_file()
def resize_image_to_1024(parent_file_path, file_path): """Resizes the image to 1024 if it is larger in width. Parameters ========== parent_file_path : string The path to the original image file with all the metadata. file_path : string The path to the temporary image file that should be resized. Notes ===== Do this before rotating the image because it is only based on width. """ img = Image.open(file_path) width, height = img.size aspect_ratio = float(width) / float(height) max_width = 1024 if width > max_width: reduced_size = max_width, int(max_width / aspect_ratio) img.thumbnail(reduced_size, Image.ANTIALIAS) img.save(file_path, img.format) # Copy all metadata from parent file to the resized file os.system('jhead -q -te {} {}'.format(parent_file_path, file_path)) metadata = GExiv2.Metadata(file_path) if (metadata.get_pixel_width() != reduced_size[0] or metadata.get_pixel_height() != reduced_size[1]): metadata.set_pixel_width(reduced_size[0]) metadata.set_pixel_height(reduced_size[1]) metadata.save_file()
def get_data(self, filename): tag_camera = "" tag_focal = "" tag_city = "" tag_country = "" # get EXIF metadata self.tags = GExiv2.Metadata(filename) # read tags from metadata if 'Exif.Image.Model' in self.tags: tag_camera = self.tags['Exif.Image.Model'] if 'Exif.Photo.FocalLengthIn35mmFilm' in self.tags: tag_focal = self.tags['Exif.Photo.FocalLengthIn35mmFilm'] if 'Xmp.photoshop.City' in self.tags: tag_city = self.tags['Xmp.photoshop.City'] if 'Xmp.photoshop.Country' in self.tags: tag_country = self.tags['Xmp.photoshop.Country'] # check if GPS info available posGPS = self.tags.get_gps_info() if posGPS[0] <> 0 or posGPS[1] <> 0: tag_gps = "yes" else: tag_gps = "no" return tag_camera, tag_focal, tag_gps, tag_city, tag_country
def read(self): if self.pixmap is None: self.pixmap = QPixmap(self.path) self.metadata = GExiv2.Metadata(self.path) # the view will need three parameters: # rotation # size # zoom # the first is needed to properly orient the view over the scene # the other two are needed for zoom, mostly # but the rotation defines the images size, so they're linked self.size = self.pixmap.size() try: # try directly to get the tag, because sometimes get_tags() returns # tags that don't actually are in the file # this implicitly loads the metadata rot = self.metadata['Exif.Image.Orientation'] except KeyError: # guess :-/ logger.info("rotation 'guessed'") rot = '1' self.rotation = self.rotation_to_degrees[rot] if self.rotation in (90, 270): self.size = QSize(self.size.height(), self.size.width()) self.zoom
def fetch_thumbnail(filename, size=Gst.get_int('thumbnail-size'), orient=1): """Load a photo's thumbnail from disk >>> fetch_thumbnail('gg/widgets.py') Traceback (most recent call last): OSError: gg/widgets.py: No thumbnail found. >>> type(fetch_thumbnail('demo/IMG_2411.JPG')) <class 'gi.repository.GdkPixbuf.Pixbuf'> """ try: exif = GExiv2.Metadata(filename) except GObject.GError: raise OSError('{}: No thumbnail found.'.format(filename)) with ignored(KeyError, ValueError): orient = int(exif['Exif.Image.Orientation']) try: thumb = GdkPixbuf.Pixbuf.new_from_file_at_size(filename, size, size) except GObject.GError: try: preview = exif.get_preview_properties() data = exif.get_preview_image(preview[0]).get_data() except (IndexError, GObject.GError): raise OSError('{}: No thumbnail found.'.format(filename)) return GdkPixbuf.Pixbuf.new_from_stream_at_scale( Gio.MemoryInputStream.new_from_data(data, None), size, size, True, None) return ROTATIONS.get(orient, lambda x: x)(thumb)
def save_img(self, rating=None): exif = GExiv2.Metadata(self.fname) self.pixmap.save(self.fname, None, self.quality) if rating is not None: exif["Exif.Image.Rating"] = str(rating) if exif: exif.save_file()
def to_file(self, path): """Write metadata to an XMP sidecar file. :param str path: The image/video file path name. """ xmp_path = path + '.xmp' # create empty XMP with open(xmp_path, 'w') as of: of.write('<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" ') of.write('xmlns:x="adobe:ns:meta/">\n</x:xmpmeta>') # open empty XMP md = GExiv2.Metadata() md.open_path(xmp_path) # add our namespace md.register_xmp_namespace( 'https://github.com/jim-easterbrook/pyctools', 'pyctools') # copy metadata for tag, value in self.data.items(): if md.get_tag_type(tag) in ('XmpBag', 'XmpSeq'): md.set_tag_multiple(tag, value) else: md.set_tag_string(tag, value) if self.comment is not None: md.set_comment(self.comment) # save file md.save_file(xmp_path)
def fix_exif_dates(img_path, timedelta, dry_run=True): """ Fix EXIF timestamps if date & time were set incorrectly on the camera when capturing the image. The file's access and modified times are preserved (restored). timedelta : datetime.timedelta applied to the original timestamp. """ # Uses GExiv2 # A GObject-based wrapper around the Exiv2 library. # Ubuntu/Debian: apt-get install gir1.2-gexiv2-0.10 libgexiv2-2 # Mac OS X: brew install pygobject3 gtk+3 gexiv2 # Arch Linux: pacman -S libgexiv2 import gi gi.require_version('GExiv2', '0.10') from gi.repository import GExiv2 import os from datetime import datetime as dt stat_result = os.stat(img_path) exif = GExiv2.Metadata() exif.open_path(img_path) orig_ts = exif.get_tag_string('Exif.Image.DateTime') orig_dt = dt.strptime(orig_ts, '%Y:%m:%d %H:%M:%S') fixed_dt = orig_dt + timedelta fixed_ts = fixed_dt.strftime('%Y:%m:%d %H:%M:%S') if not dry_run: exif.set_tag_string('Exif.Image.DateTime', fixed_ts) exif.set_tag_string('Exif.Photo.DateTimeDigitized', fixed_ts) exif.set_tag_string('Exif.Photo.DateTimeOriginal', fixed_ts) exif.save_file(img_path) os.utime(img_path, (stat_result.st_atime_ns, stat_result.st_mtime_ns)) return (orig_dt, fixed_dt)
def from_file(self, path): """Read metadata from an XMP sidecar file or, if there is no sidecar, from the image/video file (if it has metadata). Returns the :py:class:`Metadata` object, allowing convenient code like this:: md = Metadata().from_file(path) :param str path: The image/video file path name. :rtype: :py:class:`Metadata` """ for xmp_path in (path + '.xmp', path): md = GExiv2.Metadata() try: md.open_path(xmp_path) except GObject.GError: continue for tag in (md.get_exif_tags() + md.get_iptc_tags() + md.get_xmp_tags()): if md.get_tag_type(tag) in ('XmpBag', 'XmpSeq'): self.data[tag] = md.get_tag_multiple(tag) else: self.data[tag] = md.get_tag_string(tag) self.comment = md.get_comment() break return self
def exif_extract(self, temp_file, tweet): """ Attempt to extract exif information from the provided tweet. If gexiv2 dependency is not installed, this will not work and will merely return an empty list """ if not GExiv2: return [] try: exif_data = GExiv2.Metadata(temp_file) longitude, latitude, altitude = exif_data.get_gps_info() if longitude == 0 and latitude == 0: return [] coordinates = {} coordinates['from'] = 'exif' coordinates['context'] = ( 'https://twitter.com/%s/status/%s' % (tweet.user.screen_name, tweet.id), 'Location retrieved from image exif metadata.\n Tweet was %s\n' % (tweet.text)) coordinates['time'] = exif_data.get_date_time() coordinates['latitude'] = latitude coordinates['realname'] = tweet.user.name coordinates['longitude'] = longitude return coordinates except Exception: err = 'Error extracting gps coordinates from exif metadata' self.errors.append({ 'from': 'exif', 'tweetid': 0, 'url': '', 'error': err })
def read_photo_metadata(filepath): '''Parses image metadata using GExiv2.''' metadata = GExiv2.Metadata(filepath) if not metadata.get_tags(): return None else: return metadata
def run(self, task): # Save task id for logging. self.task_id = task.id # Read metadata from a temp file. try: self.metadata = GExiv2.Metadata() self.metadata.open_buf(bytes(task.get_file_data)) except Exception as e: logger.warning( "[Task {0}]: Unable to read image metadata: {1}".format( task.id, e)) self.metadata = None # Run all analysis. if self.metadata: self._get_comment() self._get_dimensions() self._get_exif() self._get_iptc() self._get_xmp() self._get_previews() self._get_gps_data() return self.results
def save_pixbuf(pixbuf, filename, update_orientation_tag=False): """Save the image with all the exif keys that exist if we have exif support. NOTE: This is used to override edited images, not to save images to new paths. The filename must exist as it is used to retrieve the image format and exif data. Args: pixbuf: GdkPixbuf.Pixbuf image to act on. filename: Name of the image to save. update_orientation_tag: If True, set orientation tag to NORMAL. """ if not os.path.isfile(filename): raise FileNotFoundError( "Original file to retrieve data from not found") # Get needed information info = GdkPixbuf.Pixbuf.get_file_info(filename)[0] extension = info.get_extensions()[0] if _has_exif: exif = GExiv2.Metadata(filename) # Save pixbuf.savev(filename, extension, [], []) if _has_exif and exif.get_supports_exif(): if update_orientation_tag: exif.set_orientation(GExiv2.Orientation.NORMAL) exif.save_file()
def remove_rotation(image_path): ''' Fix a picture taken from an Apple device :param image: Image path ''' # Get Metadata exif = GExiv2.Metadata(image_path) # Get current orientation orientation = exif.get_orientation() degrees = None if orientation == GExiv2.Orientation.ROT_90: degrees = 90 elif orientation == GExiv2.Orientation.ROT_180: degrees = 180 elif orientation == GExiv2.Orientation.ROT_270: degrees = 270 if degrees is not None: # Remove orientation tag exif.set_orientation(GExiv2.Orientation.NORMAL) exif.save_file() # Rotate image image = Image.open(image_path) rotated_image = image.rotate(360 - degrees) rotated_image.save()
def reload_auto(self): """Load a new image with auto-orientation.""" self.get_img() try: orient = GExiv2.Metadata(self.fname)['Exif.Image.Orientation'] self.orient_dict[orient]() except: self.load_img()
def _read_data(self, data): fp = temporary.file(suffix='.xmp') try: fp.write(data) fp.flush() self._meta = GExiv2.Metadata(fp.name) finally: fp.close()
def __init__(self, file_path): try: self.metadata = GExiv2.Metadata(file_path) except Exception as e: logger.warning("Unable to read image metadata: {0}".format(e)) self.metadata = None self.results = AutoVivification()
def update_images_info(self, folder, output_folder): """ 1) Retrieves all the images available in the input folder 2) For each image, retrieves the timestamp 3) From the list of available locations, searches for the closest location in time. 4) EXIF is modified and image is stored in the output folder. :param folder: Name of the input folder :param output_folder: Name of the output folder. :return: None """ extensions = ["jpg"] if not os.path.exists(output_folder): mkpath(output_folder) files = [] for extension in extensions: files += glob.glob('%s/*.%s' % (folder, extension.lower())) files += glob.glob('%s/*.%s' % (folder, extension.upper())) timestamps = sorted(self.locations.keys()) take_closest = lambda num, collection: min(collection, key=lambda x: abs(x - num)) # http://coreygoldberg.blogspot.com.es/2014/01/python-fixing-my-photo-library-dates.html # https://git.gnome.org/browse/gexiv2/tree/GExiv2.py for filename in files: output_file = os.path.join(output_folder, os.path.basename(filename)) print filename, "-->", output_file copyfile(filename, output_file) exif = GExiv2.Metadata(filename) curr_timestamp = datetime.strptime(exif['Exif.Image.DateTime'], "%Y:%m:%d %H:%M:%S") curr_timestamp = (curr_timestamp - datetime(1970, 1, 1)).total_seconds() closest_timestamp = take_closest(curr_timestamp, timestamps) gps_coords = self.locations[closest_timestamp] exif.set_gps_info(gps_coords[1], gps_coords[0], 0.0) if gps_coords[0] >= 0.0: exif.set_tag_string("Exif.GPSInfo.GPSLatitudeRef", "N") else: exif.set_tag_string("Exif.GPSInfo.GPSLatitudeRef", "S") if gps_coords[1] >= 0.0: exif.set_tag_string("Exif.GPSInfo.GPSLongitudeRef", "E") else: exif.set_tag_string("Exif.GPSInfo.GPSLongitudeRef", "W") exif.save_file(output_file)
def strip_metadata(path): from gi.repository import GExiv2 import os for infile in os.listdir(path): exif = GExiv2.Metadata(infile) exif.clear_exif() exif.clear_xmp() exif.save_file()
def fix_image_dates(img_path): t = os.path.getctime(img_path) ctime = time.strftime('%Y:%m:%d %H:%M:%S', time.localtime(t)) exif = GExiv2.Metadata(img_path) exif['Exif.Image.DateTime'] = ctime exif['Exif.Photo.DateTimeDigitized'] = ctime exif['Exif.Photo.DateTimeOriginal'] = ctime exif.save_file() os.utime(img_path, (t, t))
def main(camera, date, film, iso, files): """Tag scanned images with film-specific EXIF metadata.""" if date: exif_datetime = date.strftime('%Y:%m:%d %H:%M:%S') click.echo('Set dates to: {}'.format(date)) if camera: click.echo('Set camera to: {}'.format(camera)) if film: click.echo('Set film to: {}'.format(film)) if iso: click.echo('Set ISO to: {}'.format(iso)) click.confirm('Does this look OK?', abort=True) workqueue = [] for f in files: p = Path(f) if p.exists() and p.is_dir(): workqueue.extend([x for x in p.glob("*.[jJ][pP][gG]")]) elif p.exists() and p.is_file(): workqueue.append(p) with click.progressbar(workqueue, label='Tagging images...', show_pos=True) as bar: for image in bar: # Write new metadata to image. m = GExiv2.Metadata() m.register_xmp_namespace("http://analogexif.sourceforge.net/ns", "AnalogExif") m.open_path(str(image)) if date: m.set_tag_string('Exif.Image.DateTime', exif_datetime) m.set_tag_string('Exif.Photo.DateTimeOriginal', exif_datetime) m.set_tag_string('Exif.Photo.DateTimeDigitized', exif_datetime) if camera: if not camera in m.get_tag_multiple('Xmp.dc.subject'): m.set_tag_string('Xmp.dc.subject', camera) # set a keyword! for k, v in cameras[camera].items(): if isinstance(v, int): m.set_tag_long(k, v) else: m.set_tag_string(k, v) if film: if not film in m.get_tag_multiple('Xmp.dc.subject'): m.set_tag_string('Xmp.dc.subject', film) # set a keyword! m.set_tag_string('Xmp.AnalogExif.Film', film) for k, v in films[film].items(): if isinstance(v, int): m.set_tag_long(k, v) else: m.set_tag_string(k, v) if iso: m.set_tag_long("Exif.Photo.ISOSpeedRatings", iso) m.save_file(str(image)) click.echo("Done.")
def test_rotate_image(self): tmp_image_path = 'tmp_rotation_test_image.jpg' shutil.copyfile('rotation_test_image.jpg', tmp_image_path) metadata_before = GExiv2.Metadata(tmp_image_path) self.uploader.rotate_image(tmp_image_path) metadata_after = GExiv2.Metadata(tmp_image_path) assert metadata_after['Exif.Image.Orientation'] == '1' assert metadata_after.get_pixel_height() == \ metadata_before.get_pixel_width() assert metadata_after.get_pixel_width() == \ metadata_before.get_pixel_height() os.remove('tmp_rotation_test_image.jpg')