def _test_add_comment(self, value): metadata = ImageMetadata(self.pathname) metadata.read() key = 'Exif.Photo.UserComment' metadata[key] = value metadata.write() metadata = ImageMetadata(self.pathname) metadata.read() self.assert_(key in metadata.exif_keys) tag = metadata[key] self.assertEqual(tag.type, 'Comment') self.assertEqual(tag.value, value)
def test_add_comment(value, uc_empty): metadata = ImageMetadata(uc_empty) metadata.read() key = 'Exif.Photo.UserComment' metadata[key] = value metadata.write() metadata = ImageMetadata(uc_empty) metadata.read() assert key in metadata.exif_keys tag = metadata[key] assert tag.type == 'Comment' assert tag.value == value
def test_makernote_types(self): # Makernote tags not attached to an image have an Undefined type by # default. When read from an existing image though, their type should be # correctly set (see https://bugs.launchpad.net/pyexiv2/+bug/781464). tag1 = ExifTag('Exif.Pentax.PreviewResolution') tag1.raw_value = '640 480' self.assertEqual(tag1.type, 'Undefined') self.failUnlessRaises(ValueError, getattr, tag1, 'value') tag2 = ExifTag('Exif.Pentax.CameraInfo') tag2.raw_value = '76830 20070527 2 1 4228109' self.assertEqual(tag2.type, 'Undefined') self.failUnlessRaises(ValueError, getattr, tag2, 'value') filepath = testutils.get_absolute_file_path( os.path.join('data', 'pentax-makernote.jpg')) checksum = '646804b309a4a2d31feafe9bffc5d7f0' self.assert_(testutils.CheckFileSum(filepath, checksum)) metadata = ImageMetadata(filepath) metadata.read() tag1 = metadata[tag1.key] self.assertEqual(tag1.type, 'Short') self.assertEqual(tag1.value, [640, 480]) tag2 = metadata[tag2.key] self.assertEqual(tag2.type, 'Long') self.assertEqual(tag2.value, [76830L, 20070527L, 2L, 1L, 4228109L])
def test_write_dont_preserve_timestamps(self): stat = os.stat(self.pathname) atime = round(stat.st_atime) mtime = round(stat.st_mtime) metadata = ImageMetadata(self.pathname) metadata.read() metadata.comment = 'Yellow Submarine' time.sleep(1.1) metadata.write() stat2 = os.stat(self.pathname) atime2 = round(stat2.st_atime) mtime2 = round(stat2.st_mtime) # It is not safe to assume that atime will have been modified when the # file has been read, as it may depend on mount options (e.g. noatime, # relatime). # See discussion at http://bugs.launchpad.net/pyexiv2/+bug/624999. #self.failIfEqual(atime2, atime) self.failIfEqual(mtime2, mtime) metadata.comment = 'Yesterday' time.sleep(1.1) metadata.write(preserve_timestamps=True) stat3 = os.stat(self.pathname) atime3 = round(stat3.st_atime) mtime3 = round(stat3.st_mtime) self.failUnlessEqual(atime3, atime2) self.failUnlessEqual(mtime3, mtime2)
def jpg_with_tags(scratch_directory): """A JPEG file with several tags, used by a bunch of tests. This fixture creates the file itself and returns its pathname. The file is made read-only for safety. N.B. we use NamedTemporaryFile(delete=False) because we want to be able to close the initial file descriptor, to avoid tripping over Windows' exclusive file access rules. Cleanup is handled by the teardown of the scratch_directory fixture. """ with tempfile.NamedTemporaryFile(dir=scratch_directory, suffix='.jpg', delete=False) as fp: fp.write(EMPTY_JPG_DATA) name = fp.name # Write some metadata m = ImageMetadata(name) m.read() m['Exif.Image.Make'] = 'EASTMAN KODAK COMPANY' m['Exif.Image.DateTime'] = datetime.datetime(2009, 2, 9, 13, 33, 20) m['Iptc.Application2.Caption'] = ['blabla'] m['Iptc.Application2.DateCreated'] = [datetime.date(2004, 7, 13)] m['Xmp.dc.format'] = ('image', 'jpeg') m['Xmp.dc.subject'] = ['image', 'test', 'pyexiv2'] m.comment = 'Hello World!' m.write() del m os.chmod(name, 0o0400) # r-------- return name
def setUp(self): # Create an empty image file fd, self.pathname = tempfile.mkstemp(suffix='.jpg') os.write(fd, EMPTY_JPG_DATA) os.close(fd) # Write some metadata m = ImageMetadata(self.pathname) m.read() m['Exif.Image.Make'] = 'EASTMAN KODAK COMPANY' m['Exif.Image.DateTime'] = datetime.datetime(2009, 2, 9, 13, 33, 20) m['Iptc.Application2.Caption'] = ['blabla'] m['Iptc.Application2.DateCreated'] = [datetime.date(2004, 7, 13)] m['Xmp.dc.format'] = ('image', 'jpeg') m['Xmp.dc.subject'] = ['image', 'test', 'pyexiv2'] m.comment = 'Hello World!' m.write() self.metadata = ImageMetadata(self.pathname)
def _read_image(self, filename): filepath = testutils.get_absolute_file_path( os.path.join('data', filename)) self.assert_(testutils.CheckFileSum(filepath, self.checksums[filename])) m = ImageMetadata(filepath) m.read() return m
def test_from_file_and_from_buffer(self): # from file m1 = ImageMetadata(self.filepath) m1.read() self.assertEqual(hashlib.md5(m1.buffer).hexdigest(), self.md5sum) # from buffer m2 = self._metadata_from_buffer() self.assertEqual(hashlib.md5(m2.buffer).hexdigest(), self.md5sum)
def test_from_file_and_from_buffer(smiley): # from file m1 = ImageMetadata(smiley.filepath) m1.read() assert hashlib.md5(m1.buffer).hexdigest() == smiley.md5sum # from buffer m2 = metadata_from_buffer(smiley) assert hashlib.md5(m2.buffer).hexdigest() == smiley.md5sum
def metadata_rw(jpg_with_tags, scratch_directory): """A fresh *writable* ImageMetadata object for a *copy* of the jpg_with_tags. Returns a 2-tuple (pathname, ImageMetadata). read() has not yet been called. """ (nfd, nname) = tempfile.mkstemp(suffix='.jpg', dir=scratch_directory) # create ofp first so that nfd is closed even if the second open throws with open(nfd, "wb") as ofp, open(jpg_with_tags, "rb") as ifp: shutil.copyfileobj(ifp, ofp) # nfd is now closed os.chmod(nname, 0o0600) # rw------- return MetadataWithPath(nname, ImageMetadata(nname))
def test_read_from_filename(tempdir, filename): if isinstance(filename, bytes): tempdir = tempdir.encode("ascii") filepath = os.path.join(tempdir, filename) try: with open(filepath, 'wb') as fd: fd.write(UNUSUAL_JPG_DATA) except OSError as e: # The OS might not let us create files with some of the above names. pytest.skip("could not create test file: " + str(e)) m = ImageMetadata(filepath) m.read() assert m['Exif.Image.DateTime'].value.isoformat() == UNUSUAL_JPG_DATETIME
def test_write_preserve_timestamps(self): stat = os.stat(self.pathname) atime = round(stat.st_atime) mtime = round(stat.st_mtime) metadata = ImageMetadata(self.pathname) metadata.read() metadata.comment = 'Yellow Submarine' time.sleep(1.1) metadata.write(preserve_timestamps=True) stat2 = os.stat(self.pathname) atime2 = round(stat2.st_atime) mtime2 = round(stat2.st_mtime) self.failUnlessEqual(atime2, atime) self.failUnlessEqual(mtime2, mtime)
def image_read_exif(filename): data = ImageMetadata(filename) # This reads the metadata and closes the file data.read() lens_model = None tag = 'Exif.Photo.LensModel' if has_exif_tag(data, tag): lens_model = data[tag].value else: tag = 'Exif.NikonLd3.LensIDNumber' if has_exif_tag(data, tag): lens_model = data[tag].human_value tag = 'Exif.Panasonic.LensType' if has_exif_tag(data, tag): lens_model = data[tag].value tag = 'Exif.Sony1.LensID' if has_exif_tag(data, tag): lens_model = data[tag].human_value tag = 'Exif.Minolta.LensID' if has_exif_tag(data, tag): lens_model = data[tag].human_value if lens_model is None: lens_model = 'Standard' tag = 'Exif.Photo.FocalLength' if has_exif_tag(data, tag): focal_length = float(data[tag].value) else: print("%s doesn't have Exif.Photo.FocalLength set. " % (filename) + "Please fix it manually.") tag = 'Exif.Photo.FNumber' if has_exif_tag(data, tag): aperture = float(data[tag].value) else: print("%s doesn't have Exif.Photo.FNumber set. " % (filename) + "Please fix it manually.") return { "lens_model" : lens_model, "focal_length" : focal_length, "aperture" : aperture }
def add_metadata(image, meta_dict, path_to_data_dir="", filename=None, delete_file=True): """Add meta data to an given image. Process: uuid is generated for a unique filename. Image will be stored locally, because ImageMetadata object need to receive filepath. TODO: Might work without save image on local storage. :param image: Pillow Image which where meta information should be stored in :type image: PIL.Image :param meta_dict: Dict with meta information. E.g. meta_dict={"color":["red","green"], "hex":["#ff0000", "#00ff00"]} :type meta_dict: [type] :param path_to_data_dir: Optional path of image_file. Local file will be removed within function anyway, therefore this paramter is not impportant. :type path_to_data_dir: str :return: [description] :rtype: [type] """ Path(path_to_data_dir).mkdir(parents=True, exist_ok=True) # download file to write new meta data to file if not filename: media_guid = uuid.uuid4().hex filename = path_to_data_dir + media_guid + '.jpg' image.save(filename) # add metadata meta = ImageMetadata(filename) meta.read() meta['Exif.Photo.UserComment'] = json.dumps(meta_dict) meta.write() # transform back to PIL Image byteio = BytesIO(meta.buffer) image = Image.open(byteio) # delete file if delete_file: os.remove(filename) # return image with meta information return image
def test_not_read_raises(self): # http://bugs.launchpad.net/pyexiv2/+bug/687373 self.assertRaises(IOError, self.metadata.write) self.assertRaises(IOError, getattr, self.metadata, 'dimensions') self.assertRaises(IOError, getattr, self.metadata, 'mime_type') self.assertRaises(IOError, getattr, self.metadata, 'exif_keys') self.assertRaises(IOError, getattr, self.metadata, 'iptc_keys') self.assertRaises(IOError, getattr, self.metadata, 'xmp_keys') self.assertRaises(IOError, self.metadata._get_exif_tag, 'Exif.Image.Make') self.assertRaises(IOError, self.metadata._get_iptc_tag, 'Iptc.Application2.Caption') self.assertRaises(IOError, self.metadata._get_xmp_tag, 'Xmp.dc.format') self.assertRaises(IOError, self.metadata._set_exif_tag, 'Exif.Image.Make', 'foobar') self.assertRaises(IOError, self.metadata._set_iptc_tag, 'Iptc.Application2.Caption', ['foobar']) self.assertRaises(IOError, self.metadata._set_xmp_tag, 'Xmp.dc.format', ('foo', 'bar')) self.assertRaises(IOError, self.metadata._delete_exif_tag, 'Exif.Image.Make') self.assertRaises(IOError, self.metadata._delete_iptc_tag, 'Iptc.Application2.Caption') self.assertRaises(IOError, self.metadata._delete_xmp_tag, 'Xmp.dc.format') self.assertRaises(IOError, getattr, self.metadata, 'comment') self.assertRaises(IOError, setattr, self.metadata, 'comment', 'foobar') self.assertRaises(IOError, delattr, self.metadata, 'comment') self.assertRaises(IOError, getattr, self.metadata, 'previews') other = ImageMetadata(self.pathname) self.assertRaises(IOError, self.metadata.copy, other) self.assertRaises(IOError, getattr, self.metadata, 'buffer') thumb = self.metadata.exif_thumbnail self.assertRaises(IOError, getattr, thumb, 'mime_type') self.assertRaises(IOError, getattr, thumb, 'extension') self.assertRaises(IOError, thumb.write_to_file, '/tmp/foobar.jpg') self.assertRaises(IOError, thumb.erase) self.assertRaises(IOError, thumb.set_from_file, '/tmp/foobar.jpg') self.assertRaises(IOError, getattr, thumb, 'data') self.assertRaises(IOError, setattr, thumb, 'data', EMPTY_JPG_DATA) self.assertRaises(IOError, getattr, self.metadata, 'iptc_charset')
def read_metadata(path, photo, prefix="orig_"): photo[prefix + "orientation"] = 1 photo[prefix + "original_orientation"] = 1 try: meta = ImageMetadata(path) meta.read() try: photo[prefix + "orientation"] = meta[ "Exif.Image.Orientation"].value photo[prefix + "original_orientation"] = meta[ "Exif.Image.Orientation"].value except KeyError: print _log.debug("Failed to read the orientation from %s" % path) exposure_dt = meta["Exif.Image.DateTime"].value photo[prefix + "exposure_time"] = exif_datetime_to_time(exposure_dt) except KeyError: pass except Exception: print _log.exception("Failed to read date from %s", path) raise
def test_read_nonexistent_file(empty_directory): non_jpg = os.path.join(empty_directory, 'non.jpg') m = ImageMetadata(non_jpg) with pytest.raises(OSError): m.read()
def metadata_ro(jpg_with_tags): """A fresh *read-only* ImageMetadata object for the jpg_with_tags. Returns a 2-tuple (pathname, ImageMetadata). read() has not yet been called. write() will fail. """ return MetadataWithPath(jpg_with_tags, ImageMetadata(jpg_with_tags))
def get_metadata(): data = ImageMetadata(COPY) data.read() return data
# # Author: Olivier Tilloy <*****@*****.**> # # ****************************************************************************** import sys from pyexiv2.metadata import ImageMetadata if __name__ == '__main__': args = sys.argv if len(args) != 2: print 'Usage: %s image_file' % args[0] sys.exit(-1) metadata = ImageMetadata(args[1]) metadata.read() for key in metadata.exif_keys: tag = metadata[key] print '%-45s%-11s%s' % (key, tag.type, str(tag)) for key in metadata.iptc_keys: tag = metadata[key] print '%-45s%-11s%s' % (key, tag.type, str(tag)) # TODO: print XMP tags.
def test_read_nonexistent_file(self): metadata = ImageMetadata('idontexist') self.failUnlessRaises(IOError, metadata.read)
def _test_filename(self, filename): self._create_file(filename) m = ImageMetadata(filename) m.read() os.remove(filename)