Get date and time when photo was taken from EXIF data using PIL

后端 未结 7 837
隐瞒了意图╮
隐瞒了意图╮ 2020-12-13 02:16

I can get the EXIF data from an image using PIL, but how can I get the date and time that the photo was taken?

相关标签:
7条回答
  • 2020-12-13 03:08

    I create a function (get_exif) that can get attributes easier.

    USAGE

    your_date_time: str = get_exif(Path('test.jpg'), 'DateTimeOriginal')
    # your_date_time = get_exif(Path('test.jpg'), 0x9003)  # same as above
    

    get_exif

    from pathlib import Path
    from typing import Union, List, Tuple
    import PIL.Image
    import PIL.ExifTags
    
    
    def get_exif(file_path: Path,
                 search_list: Union[int, str, List, Tuple] = None,
                 ignore_error=True
                 ) -> Union[int, PIL.Image.Exif, List]:
        """
        :param file_path: image path
        :param search_list: if you want to get some property, then you can pass the id or name, it will return by order.
        :param ignore_error:
        :return:
            int: -1 FileNotFoundError, or exif is None
            PIL.Image.Exif: when the `search_list` is None, return the whole Exif
        """
        tag_by_id: dict = PIL.ExifTags.TAGS
        try:
            im: PIL.Image.Image = PIL.Image.open(str(file_path))
        except FileNotFoundError:
            if ignore_error:
                return -1
            else:
                raise FileNotFoundError(file_path)
        exif: PIL.Image.Exif = im.getexif()
        if not exif:
            if ignore_error:
                return -1
            else:
                raise ValueError("exif is None")
        if search_list is None:
            return exif
        tag_by_name = {tag_by_id[dec_value]: exif[dec_value] for dec_value in exif if dec_value in tag_by_id}
        result_list = []
        if not isinstance(search_list, (list, tuple)):
            search_list = [search_list]
        for key in search_list:
            if isinstance(key, int):
                result_list.append(exif.get(key, None))
                continue
            try:
                dec_value = int(key, 16)
                result_list.append(exif.get(dec_value, None))
                continue
            except ValueError:
                ...
            result_list.append(tag_by_name.get(key, None))
        return result_list if len(result_list) > 1 else result_list[0]
    

    MORE TEST

    import unittest
    
    class ExifTests(unittest.TestCase):
        def test(self):
            exif: PIL.Image.Exif = get_exif(Path('test.jpg'))  # same as the ``PIL.Image.open().getexif()``
    
            # get specify attribute only
            date_t_ori1 = get_exif(Path('test.jpg'), 0x9003)
            date_t_ori2 = get_exif(Path('test.jpg'), '0x9003', )  # hex string is ok too.
            date_t_ori3 = get_exif(Path('test.jpg'), 'DateTimeOriginal')  # Give name is also working.
            self.assertTrue(date_t_ori1 == date_t_ori2 == date_t_ori3)
    
            # You can get multiple values at once. If the key does not exist, it returns None.
            date_t_ori4, img_length, _, __ = get_exif(Path('test.jpg'),
                                                      (36867, 'ImageLength', 'NoteExitName', -12345))
    
            # Occurring error return -1 (by default ignore_error=True)
            self.assertEqual(-1, get_exif(Path('not exist.jpg')))  # FileNotFoundError
            self.assertEqual(-1, get_exif(Path('no_exif_tag.jpg')))  # ValueError
    
            self.assertRaises(FileNotFoundError, get_exif, Path('not exist.jpg'), ignore_error=False)
            self.assertRaises(ValueError, get_exif, Path('no_exif_tag.jpg'), ignore_error=False)
    

    note

    This website is good, but if you want to get the full list, you should reference PIL.ExifTags.py, see below,

    # ExifTags.py
    
    # Maps EXIF tags to tag names.
    
    TAGS = {
        # possibly incomplete
        0x000B: "ProcessingSoftware",
        0x00FE: "NewSubfileType",
        0x00FF: "SubfileType",
        0x0100: "ImageWidth",
        0x0101: "ImageLength",
        0x0102: "BitsPerSample",
        ...
        0xA430: "CameraOwnerName",  # <-- The website does not record it. (The website record last tag is A420.)
        0xA431: "BodySerialNumber",
        0xA432: "LensSpecification",
        0xA433: "LensMake",
        0xA434: "LensModel",
    }
    
    
    # Maps EXIF GPS tags to tag names.
    
    GPSTAGS = {
        0: "GPSVersionID",
        1: "GPSLatitudeRef",
        2: "GPSLatitude",
        3: "GPSLongitudeRef",
        4: "GPSLongitude",
        5: "GPSAltitudeRef",
        6: "GPSAltitude",
        7: "GPSTimeStamp",
        ...
    }
    
    0 讨论(0)
提交回复
热议问题