def test_sync_datetime_to_exif_and_iptc(self): # Create an image. file_descriptor, file_path = tempfile.mkstemp(suffix='.jpg') os.close(file_descriptor) Image.new('RGB', (1, 1)).save(file_path, 'JPEG') metadata = pyexiv2.Image(file_path) metadata.readMetadata() keys = ('Exif.Photo.DateTimeOriginal', 'Iptc.Application2.DateCreated', 'Iptc.Application2.TimeCreated',) # Synchronize to Exif. value = datetime.datetime.now() performed_sync = sync_datetime_to_exif_and_iptc(value, metadata, *keys) self.assertTrue(performed_sync) metadata.writeMetadata() # Metadata doesn't have microsecond precision. value_no_us = value.replace(microsecond=0) self.assertEqual(metadata['Exif.Photo.DateTimeOriginal'], value_no_us) self.assertFalse( 'Iptc.Application2.DateCreated' in metadata.iptcKeys()) self.assertFalse( 'Iptc.Application2.TimeCreated' in metadata.iptcKeys()) self.assertFalse( sync_datetime_to_exif_and_iptc(value, metadata, *keys)) try: metadata['Iptc.Application2.DateCreated'] = value.date() except TypeError: pass try: metadata['Iptc.Application2.TimeCreated'] = value.time() except TypeError: pass # If the value exists in IPTC, the metadata isn't modified. del metadata['Exif.Photo.DateTimeOriginal'] metadata.writeMetadata() self.assertFalse( sync_datetime_to_exif_and_iptc(value, metadata, *keys)) # Syncing a new value will remove the IPTC in favor of Exif. one_second = datetime.timedelta(seconds=1) value += one_second performed_sync = sync_datetime_to_exif_and_iptc(value, metadata, *keys) self.assertTrue(performed_sync) metadata.writeMetadata() value_no_us = value.replace(microsecond=0) self.assertEqual(metadata['Exif.Photo.DateTimeOriginal'], value_no_us) self.assertFalse( 'Iptc.Application2.DateCreated' in metadata.iptcKeys()) self.assertFalse( 'Iptc.Application2.TimeCreated' in metadata.iptcKeys()) # Synchronize the None value. none_argument = None performed_sync = sync_datetime_to_exif_and_iptc(none_argument, metadata, *keys) self.assertTrue(performed_sync) metadata.writeMetadata() self.assertFalse( 'Exif.Photo.DateTimeOriginal' in metadata.exifKeys()) self.assertFalse( 'Iptc.Application2.DateCreated' in metadata.iptcKeys()) self.assertFalse( 'Iptc.Application2.TimeCreated' in metadata.iptcKeys()) self.assertFalse( sync_datetime_to_exif_and_iptc(none_argument, metadata, *keys)) # Clean up. os.remove(file_path)
def sync_metadata_to_file(self): """\ Synchronizes the image metadata from the object to the filesystem. This stores certain properties of the object to the image file itself as Exif and/or IPTC tags, allowing the information to be portable outside of this application. Metadata is only actually written to the filesystem if the values do not match up, however. Returns True if metadata needed to be written to the file; False otherwise. """ if not self.metadata_sync_enabled: return False try: image_metadata = pyexiv2.Image(self.image.path) image_metadata.readMetadata() except IOError: self.metadata_sync_enabled = False self.save() return False mod = False # whether or not file actually needs written to # sync description mod = sync_value_to_exif_and_iptc(self.description, image_metadata, 'Exif.Image.ImageDescription', 'Iptc.Application2.Caption') or mod # sync artist mod = sync_value_to_exif_and_iptc(self.artist, image_metadata, 'Exif.Image.Artist', 'Iptc.Application2.Byline') or mod # sync country mod = sync_value_to_iptc(self.country, image_metadata, 'Iptc.Application2.CountryName') or mod # sync province_state mod = sync_value_to_iptc(self.province_state, image_metadata, 'Iptc.Application2.ProvinceState') or mod # sync city mod = sync_value_to_iptc(self.city, image_metadata, 'Iptc.Application2.City') or mod # sync location mod = sync_value_to_iptc(self.location, image_metadata, 'Iptc.Application2.SubLocation') or mod # sync time_created mod = sync_datetime_to_exif_and_iptc(self.time_created, image_metadata, 'Exif.Photo.DateTimeOriginal', 'Iptc.Application2.DateCreated', 'Iptc.Application2.TimeCreated')\ or mod # sync keywords mod = sync_value_to_iptc(self.keyword_list, image_metadata, 'Iptc.Application2.Keywords') or mod # sync image_width mod = sync_value_to_exif(self.image_width, image_metadata, get_image_width_key(self.is_jpeg)) or mod # sync image_height mod = sync_value_to_exif(self.image_height, image_metadata, get_image_height_key(self.is_jpeg)) or mod if mod: try: image_metadata.writeMetadata() except IOError: self.metadata_sync_enabled = False self.save() return False return mod