Exchangeable image file format (Exif): Python (read-write) parsing library

This page hosts a formal specification of Exchangeable image file format (Exif) using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Python (read-write) source code to parse Exchangeable image file format (Exif)

exif.py

# This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
# type: ignore

import kaitaistruct
from kaitaistruct import ReadWriteKaitaiStruct, KaitaiStream, BytesIO
from enum import IntEnum


if getattr(kaitaistruct, 'API_VERSION', (0, 9)) < (0, 11):
    raise Exception("Incompatible Kaitai Struct Python API: 0.11 or later is required, but you have %s" % (kaitaistruct.__version__))

class Exif(ReadWriteKaitaiStruct):
    """Sample files (numbers in parentheses show how many files per extension contain
    Exif metadata out of the total):
    
    * <https://github.com/ianare/exif-py/tree/a69bf74770caf6b333221658f5092ed69f99faac/tests/resources/jpg> (84/93 .jpg, 1/1 .jpeg)
    * <https://github.com/exiftool/exiftool/tree/2200871d9cef988051d2a99d67df3bda6cbb30a8/t/images> (34/41 .jpg, 0/1 .png)
    * <https://github.com/Exiv2/exiv2/tree/648ada43dcb35ce6077f38183ace52d5e2071f64/test/data> (85/155 .jpg, 5/23 .png)
    * <https://github.com/python-pillow/Pillow/tree/807d689a83738027b6f6e0f219a6a6dd30e01c08/Tests/images> (36/55 .jpg, 3/420 .png)
    * <https://github.com/drewnoakes/metadata-extractor-images/tree/651ad0e67aa8d43d358ad05f9bc07b52d8b9ac6e/jpg> (335/430 .jpg)
    * <https://github.com/libexif/libexif-testsuite/tree/8c1f5bbc18d2cbc80b01b3f9b3eb29546310acf2> (15/18 .jpg)
    
    .. seealso::
       Exif Version 3.1 - https://www.cipa.jp/std/documents/download_e.html?CIPA_DC-008-2026-E
    
    
    .. seealso::
       Exif Version 3.0 - https://www.cipa.jp/std/documents/download_e.html?CIPA_DC-008-2024-E
    
    
    .. seealso::
       Exif Version 2.32 - https://web.archive.org/web/20190624045241id_/https://www.cipa.jp/std/documents/e/DC-008-Translation-2019-E.pdf
    
    
    .. seealso::
       Exif Version 2.31 - https://web.archive.org/web/20190712232333id_/https://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf
    
    
    .. seealso::
       Exif Version 2.3 (with Corrigendum at the end) - https://www.cipa.jp/std/documents/e/DC-008-2012_E_C.pdf
    
    
    .. seealso::
       Exif Version 2.21 (2003 draft) - https://web.archive.org/web/20051228234707id_/https://tsc.jeita.or.jp/avs/data/cp3451_1.pdf
    
    
    .. seealso::
       Exif Version 2.2 - https://web.archive.org/web/20131018091152id_/https://exif.org/Exif2-2.PDF
    
    
    .. seealso::
       Exif Version 2.1 - https://web.archive.org/web/20131111073619id_/https://exif.org/Exif2-1.PDF
    """

    class FieldType(IntEnum):
        byte = 1
        ascii = 2
        short = 3
        long = 4
        rational = 5
        sbyte = 6
        undefined = 7
        sshort = 8
        slong = 9
        srational = 10
        float = 11
        double = 12
        ifd = 13
        utf8 = 129

    class GpsTag(IntEnum):
        gps_version_id = 0
        gps_latitude_ref = 1
        gps_latitude = 2
        gps_longitude_ref = 3
        gps_longitude = 4
        gps_altitude_ref = 5
        gps_altitude = 6
        gps_time_stamp = 7
        gps_satellites = 8
        gps_status = 9
        gps_measure_mode = 10
        gps_dop = 11
        gps_speed_ref = 12
        gps_speed = 13
        gps_track_ref = 14
        gps_track = 15
        gps_img_direction_ref = 16
        gps_img_direction = 17
        gps_map_datum = 18
        gps_dest_latitude_ref = 19
        gps_dest_latitude = 20
        gps_dest_longitude_ref = 21
        gps_dest_longitude = 22
        gps_dest_bearing_ref = 23
        gps_dest_bearing = 24
        gps_dest_distance_ref = 25
        gps_dest_distance = 26
        gps_processing_method = 27
        gps_area_information = 28
        gps_date_stamp = 29
        gps_differential = 30
        gps_h_positioning_error = 31

    class Tag(IntEnum):
        interop_index = 1
        interop_version = 2
        image_width = 256
        image_height = 257
        bits_per_sample = 258
        compression = 259
        photometric_interpretation = 262
        thresholding = 263
        cell_width = 264
        cell_length = 265
        fill_order = 266
        document_name = 269
        image_description = 270
        make = 271
        model = 272
        strip_offsets = 273
        orientation = 274
        samples_per_pixel = 277
        rows_per_strip = 278
        strip_byte_counts = 279
        min_sample_value = 280
        max_sample_value = 281
        x_resolution = 282
        y_resolution = 283
        planar_configuration = 284
        page_name = 285
        x_position = 286
        y_position = 287
        free_offsets = 288
        free_byte_counts = 289
        gray_response_unit = 290
        gray_response_curve = 291
        t4_options = 292
        t6_options = 293
        resolution_unit = 296
        page_number = 297
        color_response_unit = 300
        transfer_function = 301
        software = 305
        modify_date = 306
        artist = 315
        host_computer = 316
        predictor = 317
        white_point = 318
        primary_chromaticities = 319
        color_map = 320
        halftone_hints = 321
        tile_width = 322
        tile_length = 323
        tile_offsets = 324
        tile_byte_counts = 325
        bad_fax_lines = 326
        clean_fax_data = 327
        consecutive_bad_fax_lines = 328
        sub_ifd = 330
        ink_set = 332
        ink_names = 333
        numberof_inks = 334
        dot_range = 336
        target_printer = 337
        extra_samples = 338
        sample_format = 339
        s_min_sample_value = 340
        s_max_sample_value = 341
        transfer_range = 342
        clip_path = 343
        x_clip_path_units = 344
        y_clip_path_units = 345
        indexed = 346
        jpeg_tables = 347
        opi_proxy = 351
        global_parameters_ifd = 400
        profile_type = 401
        fax_profile = 402
        coding_methods = 403
        version_year = 404
        mode_number = 405
        decode = 433
        default_image_color = 434
        t82_options = 435
        jpeg_tables2 = 437
        jpeg_proc = 512
        thumbnail_offset = 513
        thumbnail_length = 514
        jpeg_restart_interval = 515
        jpeg_lossless_predictors = 517
        jpeg_point_transforms = 518
        jpegq_tables = 519
        jpegdc_tables = 520
        jpegac_tables = 521
        y_cb_cr_coefficients = 529
        y_cb_cr_sub_sampling = 530
        y_cb_cr_positioning = 531
        reference_black_white = 532
        strip_row_counts = 559
        application_notes = 700
        uspto_miscellaneous = 999
        related_image_file_format = 4096
        related_image_width = 4097
        related_image_height = 4098
        rating = 18246
        xp_dip_xml = 18247
        stitch_info = 18248
        rating_percent = 18249
        sony_raw_file_type = 28672
        light_falloff_params = 28722
        chromatic_aberration_corr_params = 28725
        distortion_corr_params = 28727
        image_id = 32781
        wang_tag1 = 32931
        wang_annotation = 32932
        wang_tag3 = 32933
        wang_tag4 = 32934
        image_reference_points = 32953
        region_xform_tack_point = 32954
        warp_quadrilateral = 32955
        affine_transform_mat = 32956
        matteing = 32995
        data_type = 32996
        image_depth = 32997
        tile_depth = 32998
        image_full_width = 33300
        image_full_height = 33301
        texture_format = 33302
        wrap_modes = 33303
        fov_cot = 33304
        matrix_world_to_screen = 33305
        matrix_world_to_camera = 33306
        model2 = 33405
        cfa_repeat_pattern_dim = 33421
        cfa_pattern2 = 33422
        battery_level = 33423
        kodak_ifd = 33424
        copyright = 33432
        exposure_time = 33434
        f_number = 33437
        md_file_tag = 33445
        md_scale_pixel = 33446
        md_color_table = 33447
        md_lab_name = 33448
        md_sample_info = 33449
        md_prep_date = 33450
        md_prep_time = 33451
        md_file_units = 33452
        pixel_scale = 33550
        advent_scale = 33589
        advent_revision = 33590
        uic1_tag = 33628
        uic2_tag = 33629
        uic3_tag = 33630
        uic4_tag = 33631
        iptc_naa = 33723
        intergraph_packet_data = 33918
        intergraph_flag_registers = 33919
        intergraph_matrix = 33920
        ingr_reserved = 33921
        model_tie_point = 33922
        site = 34016
        color_sequence = 34017
        it8_header = 34018
        raster_padding = 34019
        bits_per_run_length = 34020
        bits_per_extended_run_length = 34021
        color_table = 34022
        image_color_indicator = 34023
        background_color_indicator = 34024
        image_color_value = 34025
        background_color_value = 34026
        pixel_intensity_range = 34027
        transparency_indicator = 34028
        color_characterization = 34029
        hc_usage = 34030
        trap_indicator = 34031
        cmyk_equivalent = 34032
        sem_info = 34118
        afcp_iptc = 34152
        pixel_magic_jbig_options = 34232
        jpl_carto_ifd = 34263
        model_transform = 34264
        wb_grgb_levels = 34306
        leaf_data = 34310
        photoshop_settings = 34377
        exif_offset = 34665
        icc_profile = 34675
        tiff_fx_extensions = 34687
        multi_profiles = 34688
        shared_data = 34689
        t88_options = 34690
        image_layer = 34732
        geo_tiff_directory = 34735
        geo_tiff_double_params = 34736
        geo_tiff_ascii_params = 34737
        jbig_options = 34750
        exposure_program = 34850
        spectral_sensitivity = 34852
        gps_info = 34853
        iso = 34855
        opto_electric_conv_factor = 34856
        interlace = 34857
        time_zone_offset = 34858
        self_timer_mode = 34859
        sensitivity_type = 34864
        standard_output_sensitivity = 34865
        recommended_exposure_index = 34866
        iso_speed = 34867
        iso_speed_latitudeyyy = 34868
        iso_speed_latitudezzz = 34869
        fax_recv_params = 34908
        fax_sub_address = 34909
        fax_recv_time = 34910
        fedex_edr = 34929
        leaf_sub_ifd = 34954
        exif_version = 36864
        date_time_original = 36867
        create_date = 36868
        google_plus_upload_code = 36873
        offset_time = 36880
        offset_time_original = 36881
        offset_time_digitized = 36882
        components_configuration = 37121
        compressed_bits_per_pixel = 37122
        shutter_speed_value = 37377
        aperture_value = 37378
        brightness_value = 37379
        exposure_compensation = 37380
        max_aperture_value = 37381
        subject_distance = 37382
        metering_mode = 37383
        light_source = 37384
        flash = 37385
        focal_length = 37386
        flash_energy = 37387
        spatial_frequency_response = 37388
        noise = 37389
        focal_plane_x_resolution = 37390
        focal_plane_y_resolution = 37391
        focal_plane_resolution_unit = 37392
        image_number = 37393
        security_classification = 37394
        image_history = 37395
        subject_area = 37396
        exposure_index = 37397
        tiff_ep_standard_id = 37398
        sensing_method = 37399
        cip3_data_file = 37434
        cip3_sheet = 37435
        cip3_side = 37436
        sto_nits = 37439
        maker_note = 37500
        user_comment = 37510
        sub_sec_time = 37520
        sub_sec_time_original = 37521
        sub_sec_time_digitized = 37522
        ms_document_text = 37679
        ms_property_set_storage = 37680
        ms_document_text_position = 37681
        image_source_data = 37724
        ambient_temperature = 37888
        humidity = 37889
        pressure = 37890
        water_depth = 37891
        acceleration = 37892
        camera_elevation_angle = 37893
        xp_title = 40091
        xp_comment = 40092
        xp_author = 40093
        xp_keywords = 40094
        xp_subject = 40095
        flashpix_version = 40960
        color_space = 40961
        exif_image_width = 40962
        exif_image_height = 40963
        related_sound_file = 40964
        interop_offset = 40965
        samsung_raw_pointers_offset = 40976
        samsung_raw_pointers_length = 40977
        samsung_raw_byte_order = 41217
        samsung_raw_unknown = 41218
        flash_energy2 = 41483
        spatial_frequency_response2 = 41484
        noise2 = 41485
        focal_plane_x_resolution2 = 41486
        focal_plane_y_resolution2 = 41487
        focal_plane_resolution_unit2 = 41488
        image_number2 = 41489
        security_classification2 = 41490
        image_history2 = 41491
        subject_location = 41492
        exposure_index2 = 41493
        tiff_ep_standard_id2 = 41494
        sensing_method2 = 41495
        file_source = 41728
        scene_type = 41729
        cfa_pattern = 41730
        custom_rendered = 41985
        exposure_mode = 41986
        white_balance = 41987
        digital_zoom_ratio = 41988
        focal_length_in35mm_format = 41989
        scene_capture_type = 41990
        gain_control = 41991
        contrast = 41992
        saturation = 41993
        sharpness = 41994
        device_setting_description = 41995
        subject_distance_range = 41996
        image_unique_id = 42016
        owner_name = 42032
        serial_number = 42033
        lens_info = 42034
        lens_make = 42035
        lens_model = 42036
        lens_serial_number = 42037
        gdal_metadata = 42112
        gdal_no_data = 42113
        gamma = 42240
        expand_software = 44992
        expand_lens = 44993
        expand_film = 44994
        expand_filter_lens = 44995
        expand_scanner = 44996
        expand_flash_lamp = 44997
        pixel_format = 48129
        transformation = 48130
        uncompressed = 48131
        image_type = 48132
        image_width2 = 48256
        image_height2 = 48257
        width_resolution = 48258
        height_resolution = 48259
        image_offset = 48320
        image_byte_count = 48321
        alpha_offset = 48322
        alpha_byte_count = 48323
        image_data_discard = 48324
        alpha_data_discard = 48325
        oce_scanjob_desc = 50215
        oce_application_selector = 50216
        oce_id_number = 50217
        oce_image_logic = 50218
        annotations = 50255
        print_im = 50341
        original_file_name = 50547
        uspto_original_content_type = 50560
        dng_version = 50706
        dng_backward_version = 50707
        unique_camera_model = 50708
        localized_camera_model = 50709
        cfa_plane_color = 50710
        cfa_layout = 50711
        linearization_table = 50712
        black_level_repeat_dim = 50713
        black_level = 50714
        black_level_delta_h = 50715
        black_level_delta_v = 50716
        white_level = 50717
        default_scale = 50718
        default_crop_origin = 50719
        default_crop_size = 50720
        color_matrix1 = 50721
        color_matrix2 = 50722
        camera_calibration1 = 50723
        camera_calibration2 = 50724
        reduction_matrix1 = 50725
        reduction_matrix2 = 50726
        analog_balance = 50727
        as_shot_neutral = 50728
        as_shot_white_xy = 50729
        baseline_exposure = 50730
        baseline_noise = 50731
        baseline_sharpness = 50732
        bayer_green_split = 50733
        linear_response_limit = 50734
        camera_serial_number = 50735
        dng_lens_info = 50736
        chroma_blur_radius = 50737
        anti_alias_strength = 50738
        shadow_scale = 50739
        sr2_private = 50740
        maker_note_safety = 50741
        raw_image_segmentation = 50752
        calibration_illuminant1 = 50778
        calibration_illuminant2 = 50779
        best_quality_scale = 50780
        raw_data_unique_id = 50781
        alias_layer_metadata = 50784
        original_raw_file_name = 50827
        original_raw_file_data = 50828
        active_area = 50829
        masked_areas = 50830
        as_shot_icc_profile = 50831
        as_shot_pre_profile_matrix = 50832
        current_icc_profile = 50833
        current_pre_profile_matrix = 50834
        colorimetric_reference = 50879
        s_raw_type = 50885
        panasonic_title = 50898
        panasonic_title2 = 50899
        camera_calibration_sig = 50931
        profile_calibration_sig = 50932
        profile_ifd = 50933
        as_shot_profile_name = 50934
        noise_reduction_applied = 50935
        profile_name = 50936
        profile_hue_sat_map_dims = 50937
        profile_hue_sat_map_data1 = 50938
        profile_hue_sat_map_data2 = 50939
        profile_tone_curve = 50940
        profile_embed_policy = 50941
        profile_copyright = 50942
        forward_matrix1 = 50964
        forward_matrix2 = 50965
        preview_application_name = 50966
        preview_application_version = 50967
        preview_settings_name = 50968
        preview_settings_digest = 50969
        preview_color_space = 50970
        preview_date_time = 50971
        raw_image_digest = 50972
        original_raw_file_digest = 50973
        sub_tile_block_size = 50974
        row_interleave_factor = 50975
        profile_look_table_dims = 50981
        profile_look_table_data = 50982
        opcode_list1 = 51008
        opcode_list2 = 51009
        opcode_list3 = 51022
        noise_profile = 51041
        time_codes = 51043
        frame_rate = 51044
        t_stop = 51058
        reel_name = 51081
        original_default_final_size = 51089
        original_best_quality_size = 51090
        original_default_crop_size = 51091
        camera_label = 51105
        profile_hue_sat_map_encoding = 51107
        profile_look_table_encoding = 51108
        baseline_exposure_offset = 51109
        default_black_render = 51110
        new_raw_image_digest = 51111
        raw_to_preview_gain = 51112
        default_user_crop = 51125
        padding = 59932
        offset_schema = 59933
        owner_name2 = 65000
        serial_number2 = 65001
        lens = 65002
        kdc_ifd = 65024
        raw_file = 65100
        converter = 65101
        white_balance2 = 65102
        exposure = 65105
        shadows = 65106
        brightness = 65107
        contrast2 = 65108
        saturation2 = 65109
        sharpness2 = 65110
        smoothness = 65111
        moire_filter = 65112
    def __init__(self, _io=None, _parent=None, _root=None):
        super(Exif, self).__init__(_io)
        self._parent = _parent
        self._root = _root or self

    def _read(self):
        self.endianness = self._io.read_u2le()
        self.body = Exif.ExifBody(self._io, self, self._root)
        self.body._read()
        self._dirty = False


    def _fetch_instances(self):
        pass
        self.body._fetch_instances()


    def _write__seq(self, io=None):
        super(Exif, self)._write__seq(io)
        self._io.write_u2le(self.endianness)
        self.body._write__seq(self._io)


    def _check(self):
        if self.body._root != self._root:
            raise kaitaistruct.ConsistencyError(u"body", self._root, self.body._root)
        if self.body._parent != self:
            raise kaitaistruct.ConsistencyError(u"body", self, self.body._parent)
        self._dirty = False

    class ExifBody(ReadWriteKaitaiStruct):
        def __init__(self, _io=None, _parent=None, _root=None):
            super(Exif.ExifBody, self).__init__(_io)
            self._parent = _parent
            self._root = _root
            self._should_write_ifd0 = False
            self.ifd0__enabled = True

        def _read(self):
            _on = self._root.endianness
            if _on == 18761:
                pass
                self._is_le = True
            elif _on == 19789:
                pass
                self._is_le = False
            if not hasattr(self, '_is_le'):
                raise kaitaistruct.UndecidedEndiannessError("/types/exif_body")
            elif self._is_le == True:
                self._read_le()
            elif self._is_le == False:
                self._read_be()
            self._dirty = False

        def _read_le(self):
            self.magic = self._io.read_u2le()
            if not self.magic == 42:
                raise kaitaistruct.ValidationNotEqualError(42, self.magic, self._io, u"/types/exif_body/seq/0")
            self.ofs_ifd0 = self._io.read_u4le()
            self._dirty = False

        def _read_be(self):
            self.magic = self._io.read_u2be()
            if not self.magic == 42:
                raise kaitaistruct.ValidationNotEqualError(42, self.magic, self._io, u"/types/exif_body/seq/0")
            self.ofs_ifd0 = self._io.read_u4be()
            self._dirty = False


        def _fetch_instances(self):
            pass
            _ = self.ifd0
            if hasattr(self, '_m_ifd0'):
                pass
                self._m_ifd0._fetch_instances()



        def _write__seq(self, io=None):
            super(Exif.ExifBody, self)._write__seq(io)
            if not hasattr(self, '_is_le'):
                raise kaitaistruct.UndecidedEndiannessError("/types/exif_body")
            elif self._is_le == True:
                self._write__seq_le()
            elif self._is_le == False:
                self._write__seq_be()


        def _write__seq_le(self):
            self._should_write_ifd0 = self.ifd0__enabled
            self._io.write_u2le(self.magic)
            self._io.write_u4le(self.ofs_ifd0)


        def _write__seq_be(self):
            self._should_write_ifd0 = self.ifd0__enabled
            self._io.write_u2be(self.magic)
            self._io.write_u4be(self.ofs_ifd0)


        def _check(self):
            if not self.magic == 42:
                raise kaitaistruct.ValidationNotEqualError(42, self.magic, None, u"/types/exif_body/seq/0")
            if self.ifd0__enabled:
                pass
                if self._m_ifd0._root != self._root:
                    raise kaitaistruct.ConsistencyError(u"ifd0", self._root, self._m_ifd0._root)
                if self._m_ifd0._parent != self:
                    raise kaitaistruct.ConsistencyError(u"ifd0", self, self._m_ifd0._parent)
                if self._m_ifd0.is_gps_ifd != False:
                    raise kaitaistruct.ConsistencyError(u"ifd0", False, self._m_ifd0.is_gps_ifd)

            self._dirty = False

        class AsciiString(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.AsciiString, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/ascii_string")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.value = self._io.read_bytes_term(0, False, True, False)
                self._dirty = False

            def _read_be(self):
                self.value = self._io.read_bytes_term(0, False, True, False)
                self._dirty = False


            def _fetch_instances(self):
                pass


            def _write__seq(self, io=None):
                super(Exif.ExifBody.AsciiString, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/ascii_string")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                self._io.write_bytes(self.value)
                if not self._io.is_eof():
                    self._io.write_u1(0)



            def _write__seq_be(self):
                self._io.write_bytes(self.value)
                if not self._io.is_eof():
                    self._io.write_u1(0)



            def _check(self):
                if KaitaiStream.byte_array_index_of(self.value, 0) != -1:
                    raise kaitaistruct.ConsistencyError(u"value", -1, KaitaiStream.byte_array_index_of(self.value, 0))
                self._dirty = False


        class Doubles(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Doubles, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/doubles")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_f8le())

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_f8be())

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Doubles, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/doubles")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_f8le(self.values[i])



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_f8be(self.values[i])



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass

                self._dirty = False


        class Floats(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Floats, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/floats")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_f4le())

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_f4be())

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Floats, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/floats")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_f4le(self.values[i])



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_f4be(self.values[i])



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass

                self._dirty = False


        class Ifd(ReadWriteKaitaiStruct):
            def __init__(self, is_gps_ifd, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Ifd, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le
                self.is_gps_ifd = is_gps_ifd
                self._should_write_next_ifd = False
                self.next_ifd__enabled = True

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/ifd")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.num_fields = self._io.read_u2le()
                self._raw_fields = []
                self.fields = []
                for i in range(self.num_fields):
                    self._raw_fields.append(self._io.read_bytes(12))
                    _io__raw_fields = KaitaiStream(BytesIO(self._raw_fields[i]))
                    _t_fields = Exif.ExifBody.IfdField(_io__raw_fields, self, self._root, self._is_le)
                    try:
                        _t_fields._read()
                    finally:
                        self.fields.append(_t_fields)

                self.ofs_next_ifd = self._io.read_u4le()
                self._dirty = False

            def _read_be(self):
                self.num_fields = self._io.read_u2be()
                self._raw_fields = []
                self.fields = []
                for i in range(self.num_fields):
                    self._raw_fields.append(self._io.read_bytes(12))
                    _io__raw_fields = KaitaiStream(BytesIO(self._raw_fields[i]))
                    _t_fields = Exif.ExifBody.IfdField(_io__raw_fields, self, self._root, self._is_le)
                    try:
                        _t_fields._read()
                    finally:
                        self.fields.append(_t_fields)

                self.ofs_next_ifd = self._io.read_u4be()
                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.fields)):
                    pass
                    self.fields[i]._fetch_instances()

                _ = self.next_ifd
                if hasattr(self, '_m_next_ifd'):
                    pass
                    self._m_next_ifd._fetch_instances()



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Ifd, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/ifd")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                self._should_write_next_ifd = self.next_ifd__enabled
                self._io.write_u2le(self.num_fields)
                self._raw_fields = []
                for i in range(len(self.fields)):
                    pass
                    _io__raw_fields = KaitaiStream(BytesIO(bytearray(12)))
                    self._io.add_child_stream(_io__raw_fields)
                    _pos2 = self._io.pos()
                    self._io.seek(self._io.pos() + (12))
                    def handler(parent, _io__raw_fields=_io__raw_fields, i=i):
                        self._raw_fields.append(_io__raw_fields.to_byte_array())
                        if len(self._raw_fields[i]) != 12:
                            raise kaitaistruct.ConsistencyError(u"raw(fields)", 12, len(self._raw_fields[i]))
                        parent.write_bytes(self._raw_fields[i])
                    _io__raw_fields.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                    self.fields[i]._write__seq(_io__raw_fields)

                self._io.write_u4le(self.ofs_next_ifd)


            def _write__seq_be(self):
                self._should_write_next_ifd = self.next_ifd__enabled
                self._io.write_u2be(self.num_fields)
                self._raw_fields = []
                for i in range(len(self.fields)):
                    pass
                    _io__raw_fields = KaitaiStream(BytesIO(bytearray(12)))
                    self._io.add_child_stream(_io__raw_fields)
                    _pos2 = self._io.pos()
                    self._io.seek(self._io.pos() + (12))
                    def handler(parent, _io__raw_fields=_io__raw_fields, i=i):
                        self._raw_fields.append(_io__raw_fields.to_byte_array())
                        if len(self._raw_fields[i]) != 12:
                            raise kaitaistruct.ConsistencyError(u"raw(fields)", 12, len(self._raw_fields[i]))
                        parent.write_bytes(self._raw_fields[i])
                    _io__raw_fields.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                    self.fields[i]._write__seq(_io__raw_fields)

                self._io.write_u4be(self.ofs_next_ifd)


            def _check(self):
                if len(self.fields) != self.num_fields:
                    raise kaitaistruct.ConsistencyError(u"fields", self.num_fields, len(self.fields))
                for i in range(len(self.fields)):
                    pass
                    if self.fields[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"fields", self._root, self.fields[i]._root)
                    if self.fields[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"fields", self, self.fields[i]._parent)

                if self.next_ifd__enabled:
                    pass
                    if self.ofs_next_ifd != 0:
                        pass
                        if self._m_next_ifd._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"next_ifd", self._root, self._m_next_ifd._root)
                        if self._m_next_ifd._parent != self:
                            raise kaitaistruct.ConsistencyError(u"next_ifd", self, self._m_next_ifd._parent)
                        if self._m_next_ifd.is_gps_ifd != self.is_gps_ifd:
                            raise kaitaistruct.ConsistencyError(u"next_ifd", self.is_gps_ifd, self._m_next_ifd.is_gps_ifd)


                self._dirty = False

            @property
            def next_ifd(self):
                if self._should_write_next_ifd:
                    self._write_next_ifd()
                if hasattr(self, '_m_next_ifd'):
                    return self._m_next_ifd

                if not self.next_ifd__enabled:
                    return None

                if self.ofs_next_ifd != 0:
                    pass
                    _pos = self._io.pos()
                    self._io.seek(self.ofs_next_ifd)
                    if self._is_le:
                        self._m_next_ifd = Exif.ExifBody.Ifd(self.is_gps_ifd, self._io, self, self._root, self._is_le)
                        self._m_next_ifd._read()
                    else:
                        self._m_next_ifd = Exif.ExifBody.Ifd(self.is_gps_ifd, self._io, self, self._root, self._is_le)
                        self._m_next_ifd._read()
                    self._io.seek(_pos)

                return getattr(self, '_m_next_ifd', None)

            @next_ifd.setter
            def next_ifd(self, v):
                self._dirty = True
                self._m_next_ifd = v

            def _write_next_ifd(self):
                self._should_write_next_ifd = False
                if self.ofs_next_ifd != 0:
                    pass
                    _pos = self._io.pos()
                    self._io.seek(self.ofs_next_ifd)
                    if self._is_le:
                        self._m_next_ifd._write__seq(self._io)
                    else:
                        self._m_next_ifd._write__seq(self._io)
                    self._io.seek(_pos)



        class IfdField(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.IfdField, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le
                self._should_write_data = False
                self.data__enabled = True
                self._should_write_sub_ifd = False
                self.sub_ifd__enabled = True

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/ifd_field")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.tag_raw = self._io.read_u2le()
                self.field_type = KaitaiStream.resolve_enum(Exif.FieldType, self._io.read_u2le())
                self.num_values = self._io.read_u4le()
                if (not (self.has_immediate_data)):
                    pass
                    self.ofs_data = self._io.read_u4le()

                self._dirty = False

            def _read_be(self):
                self.tag_raw = self._io.read_u2be()
                self.field_type = KaitaiStream.resolve_enum(Exif.FieldType, self._io.read_u2be())
                self.num_values = self._io.read_u4be()
                if (not (self.has_immediate_data)):
                    pass
                    self.ofs_data = self._io.read_u4be()

                self._dirty = False


            def _fetch_instances(self):
                pass
                if (not (self.has_immediate_data)):
                    pass

                _ = self.data
                if hasattr(self, '_m_data'):
                    pass
                    _on = self.field_type
                    if _on == Exif.FieldType.ascii:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.double:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.float:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.ifd:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.long:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.rational:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.sbyte:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.short:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.slong:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.srational:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.sshort:
                        pass
                        self._m_data._fetch_instances()
                    elif _on == Exif.FieldType.utf8:
                        pass
                        self._m_data._fetch_instances()
                    else:
                        pass

                _ = self.sub_ifd
                if hasattr(self, '_m_sub_ifd'):
                    pass
                    self._m_sub_ifd._fetch_instances()



            def _write__seq(self, io=None):
                super(Exif.ExifBody.IfdField, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/ifd_field")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                self._should_write_data = self.data__enabled
                self._should_write_sub_ifd = self.sub_ifd__enabled
                self._io.write_u2le(self.tag_raw)
                self._io.write_u2le(int(self.field_type))
                self._io.write_u4le(self.num_values)
                if (not (self.has_immediate_data)):
                    pass
                    self._io.write_u4le(self.ofs_data)



            def _write__seq_be(self):
                self._should_write_data = self.data__enabled
                self._should_write_sub_ifd = self.sub_ifd__enabled
                self._io.write_u2be(self.tag_raw)
                self._io.write_u2be(int(self.field_type))
                self._io.write_u4be(self.num_values)
                if (not (self.has_immediate_data)):
                    pass
                    self._io.write_u4be(self.ofs_data)



            def _check(self):
                if (not (self.has_immediate_data)):
                    pass

                if self.data__enabled:
                    pass
                    _on = self.field_type
                    if _on == Exif.FieldType.ascii:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.double:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.float:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.ifd:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.long:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.rational:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.sbyte:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.short:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.slong:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.srational:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.sshort:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    elif _on == Exif.FieldType.utf8:
                        pass
                        if self._m_data._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"data", self._root, self._m_data._root)
                        if self._m_data._parent != self:
                            raise kaitaistruct.ConsistencyError(u"data", self, self._m_data._parent)
                    else:
                        pass
                        if len(self._m_data) != self.len_data:
                            raise kaitaistruct.ConsistencyError(u"data", self.len_data, len(self._m_data))

                if self.sub_ifd__enabled:
                    pass

                self._dirty = False

            @property
            def bytes_per_value(self):
                """Size in bytes of a single value of type `field_type`, or 0 if
                `field_type` is not one of the known types (in which case the size
                cannot be determined and `data` will be empty).
                
                .. seealso::
                   Source - https://www.media.mit.edu/pia/Research/deepview/exif.html#DataForm
                """
                if hasattr(self, '_m_bytes_per_value'):
                    return self._m_bytes_per_value

                self._m_bytes_per_value = (1 if  ((self.field_type == Exif.FieldType.byte) or (self.field_type == Exif.FieldType.ascii) or (self.field_type == Exif.FieldType.sbyte) or (self.field_type == Exif.FieldType.undefined) or (self.field_type == Exif.FieldType.utf8))  else (2 if  ((self.field_type == Exif.FieldType.short) or (self.field_type == Exif.FieldType.sshort))  else (4 if  ((self.field_type == Exif.FieldType.long) or (self.field_type == Exif.FieldType.slong) or (self.field_type == Exif.FieldType.float) or (self.field_type == Exif.FieldType.ifd))  else (8 if  ((self.field_type == Exif.FieldType.rational) or (self.field_type == Exif.FieldType.srational) or (self.field_type == Exif.FieldType.double))  else 0))))
                return getattr(self, '_m_bytes_per_value', None)

            def _invalidate_bytes_per_value(self):
                del self._m_bytes_per_value
            @property
            def data(self):
                if self._should_write_data:
                    self._write_data()
                if hasattr(self, '_m_data'):
                    return self._m_data

                if not self.data__enabled:
                    return None

                io = (self._io if self.has_immediate_data else self._root._io)
                _pos = io.pos()
                io.seek((8 if self.has_immediate_data else self.ofs_data))
                if self._is_le:
                    _on = self.field_type
                    if _on == Exif.FieldType.ascii:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.AsciiString(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.double:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Doubles(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.float:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Floats(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.ifd:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Longs(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.long:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Longs(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.rational:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Rationals(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.sbyte:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Sbytes(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.short:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Shorts(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.slong:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Slongs(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.srational:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Srationals(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.sshort:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Sshorts(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.utf8:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Utf8String(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    else:
                        pass
                        self._m_data = io.read_bytes(self.len_data)
                else:
                    _on = self.field_type
                    if _on == Exif.FieldType.ascii:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.AsciiString(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.double:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Doubles(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.float:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Floats(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.ifd:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Longs(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.long:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Longs(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.rational:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Rationals(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.sbyte:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Sbytes(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.short:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Shorts(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.slong:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Slongs(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.srational:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Srationals(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.sshort:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Sshorts(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    elif _on == Exif.FieldType.utf8:
                        pass
                        self._raw__m_data = io.read_bytes(self.len_data)
                        _io__raw__m_data = KaitaiStream(BytesIO(self._raw__m_data))
                        self._m_data = Exif.ExifBody.Utf8String(_io__raw__m_data, self, self._root, self._is_le)
                        self._m_data._read()
                    else:
                        pass
                        self._m_data = io.read_bytes(self.len_data)
                io.seek(_pos)
                return getattr(self, '_m_data', None)

            @data.setter
            def data(self, v):
                self._dirty = True
                self._m_data = v

            def _write_data(self):
                self._should_write_data = False
                io = (self._io if self.has_immediate_data else self._root._io)
                _pos = io.pos()
                io.seek((8 if self.has_immediate_data else self.ofs_data))
                if self._is_le:
                    _on = self.field_type
                    if _on == Exif.FieldType.ascii:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.double:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.float:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.ifd:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.long:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.rational:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.sbyte:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.short:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.slong:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.srational:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.sshort:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.utf8:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    else:
                        pass
                        io.write_bytes(self._m_data)
                else:
                    _on = self.field_type
                    if _on == Exif.FieldType.ascii:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.double:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.float:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.ifd:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.long:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.rational:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.sbyte:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.short:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.slong:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.srational:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.sshort:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    elif _on == Exif.FieldType.utf8:
                        pass
                        _io__raw__m_data = KaitaiStream(BytesIO(bytearray(self.len_data)))
                        io.add_child_stream(_io__raw__m_data)
                        _pos2 = io.pos()
                        io.seek(io.pos() + (self.len_data))
                        def handler(parent, _io__raw__m_data=_io__raw__m_data):
                            self._raw__m_data = _io__raw__m_data.to_byte_array()
                            if len(self._raw__m_data) != self.len_data:
                                raise kaitaistruct.ConsistencyError(u"raw(data)", self.len_data, len(self._raw__m_data))
                            parent.write_bytes(self._raw__m_data)
                        _io__raw__m_data.write_back_handler = KaitaiStream.WriteBackHandler(_pos2, handler)
                        self._m_data._write__seq(_io__raw__m_data)
                    else:
                        pass
                        io.write_bytes(self._m_data)
                io.seek(_pos)

            @property
            def gps_tag(self):
                if hasattr(self, '_m_gps_tag'):
                    return self._m_gps_tag

                if self._parent.is_gps_ifd:
                    pass
                    self._m_gps_tag = KaitaiStream.resolve_enum(Exif.GpsTag, self.tag_raw)

                return getattr(self, '_m_gps_tag', None)

            def _invalidate_gps_tag(self):
                del self._m_gps_tag
            @property
            def has_immediate_data(self):
                if hasattr(self, '_m_has_immediate_data'):
                    return self._m_has_immediate_data

                self._m_has_immediate_data = self.len_data <= 4
                return getattr(self, '_m_has_immediate_data', None)

            def _invalidate_has_immediate_data(self):
                del self._m_has_immediate_data
            @property
            def len_data(self):
                if hasattr(self, '_m_len_data'):
                    return self._m_len_data

                self._m_len_data = self.bytes_per_value * self.num_values
                return getattr(self, '_m_len_data', None)

            def _invalidate_len_data(self):
                del self._m_len_data
            @property
            def sub_ifd(self):
                """All the "IFD Pointer" tags (as the core Exif standard calls them),
                i.e. `ExifOffset`, `InteropOffset` and `GPSInfo` (using the
                [ExifTool's
                names](https://exiftool.sourceforge.net/TagNames/EXIF.html)),
                should be of type `LONG` (`field_type::long`). However, the type
                `SLONG` (`field_type::slong`) type has also been observed:
                <https://github.com/Exiv2/exiv2/blob/2cd987a731236037b6b78cbff897d08685a8ef49/test/data/FurnaceCreekInn.jpg>
                
                Both ExifTool and Exiv2 accept `LONG`, `SLONG` and also `IFD`.
                Exiv2 specifically supports only these three types - see
                <https://github.com/Exiv2/exiv2/blob/2cd987a731236037b6b78cbff897d08685a8ef49/src/tiffvisitor_int.cpp#L1141>
                (Git tag "v0.28.8"). ExifTool is more lenient - it even accepts
                any integer type. In practice, real files most likely only use one
                of the three types supported by Exiv2, so we stick with that.
                """
                if self._should_write_sub_ifd:
                    self._write_sub_ifd()
                if hasattr(self, '_m_sub_ifd'):
                    return self._m_sub_ifd

                if not self.sub_ifd__enabled:
                    return None

                if  ((self.num_values == 1) and ( ((self.field_type == Exif.FieldType.long) or (self.field_type == Exif.FieldType.ifd) or ( ((self.field_type == Exif.FieldType.slong) and (self.data.values[0] >= 0)) )) ) and ( ((self.tag == Exif.Tag.exif_offset) or (self.tag == Exif.Tag.interop_offset) or (self.tag == Exif.Tag.gps_info)) )) :
                    pass
                    io = self._root._io
                    _pos = io.pos()
                    io.seek((self.data.values[0] if self.field_type == Exif.FieldType.slong else self.data.values[0]))
                    if self._is_le:
                        self._m_sub_ifd = Exif.ExifBody.Ifd(self.tag == Exif.Tag.gps_info, io, self, self._root, self._is_le)
                        self._m_sub_ifd._read()
                    else:
                        self._m_sub_ifd = Exif.ExifBody.Ifd(self.tag == Exif.Tag.gps_info, io, self, self._root, self._is_le)
                        self._m_sub_ifd._read()
                    io.seek(_pos)

                return getattr(self, '_m_sub_ifd', None)

            @sub_ifd.setter
            def sub_ifd(self, v):
                self._dirty = True
                self._m_sub_ifd = v

            def _write_sub_ifd(self):
                self._should_write_sub_ifd = False
                if  ((self.num_values == 1) and ( ((self.field_type == Exif.FieldType.long) or (self.field_type == Exif.FieldType.ifd) or ( ((self.field_type == Exif.FieldType.slong) and (self.data.values[0] >= 0)) )) ) and ( ((self.tag == Exif.Tag.exif_offset) or (self.tag == Exif.Tag.interop_offset) or (self.tag == Exif.Tag.gps_info)) )) :
                    pass
                    io = self._root._io
                    _pos = io.pos()
                    io.seek((self.data.values[0] if self.field_type == Exif.FieldType.slong else self.data.values[0]))
                    if self._is_le:
                        if self._m_sub_ifd._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"sub_ifd", self._root, self._m_sub_ifd._root)
                        if self._m_sub_ifd._parent != self:
                            raise kaitaistruct.ConsistencyError(u"sub_ifd", self, self._m_sub_ifd._parent)
                        if self._m_sub_ifd.is_gps_ifd != (self.tag == Exif.Tag.gps_info):
                            raise kaitaistruct.ConsistencyError(u"sub_ifd", self.tag == Exif.Tag.gps_info, self._m_sub_ifd.is_gps_ifd)
                        self._m_sub_ifd._write__seq(io)
                    else:
                        if self._m_sub_ifd._root != self._root:
                            raise kaitaistruct.ConsistencyError(u"sub_ifd", self._root, self._m_sub_ifd._root)
                        if self._m_sub_ifd._parent != self:
                            raise kaitaistruct.ConsistencyError(u"sub_ifd", self, self._m_sub_ifd._parent)
                        if self._m_sub_ifd.is_gps_ifd != (self.tag == Exif.Tag.gps_info):
                            raise kaitaistruct.ConsistencyError(u"sub_ifd", self.tag == Exif.Tag.gps_info, self._m_sub_ifd.is_gps_ifd)
                        self._m_sub_ifd._write__seq(io)
                    io.seek(_pos)


            @property
            def tag(self):
                if hasattr(self, '_m_tag'):
                    return self._m_tag

                if (not (self._parent.is_gps_ifd)):
                    pass
                    self._m_tag = KaitaiStream.resolve_enum(Exif.Tag, self.tag_raw)

                return getattr(self, '_m_tag', None)

            def _invalidate_tag(self):
                del self._m_tag

        class Longs(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Longs, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/longs")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_u4le())

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_u4be())

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Longs, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/longs")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_u4le(self.values[i])



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_u4be(self.values[i])



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass

                self._dirty = False


        class Rational(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Rational, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/rational")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.value_num = self._io.read_u4le()
                self.value_den = self._io.read_u4le()
                self._dirty = False

            def _read_be(self):
                self.value_num = self._io.read_u4be()
                self.value_den = self._io.read_u4be()
                self._dirty = False


            def _fetch_instances(self):
                pass


            def _write__seq(self, io=None):
                super(Exif.ExifBody.Rational, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/rational")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                self._io.write_u4le(self.value_num)
                self._io.write_u4le(self.value_den)


            def _write__seq_be(self):
                self._io.write_u4be(self.value_num)
                self._io.write_u4be(self.value_den)


            def _check(self):
                self._dirty = False

            @property
            def value(self):
                """If denominator is zero, this instance is disabled to prevent
                `ZeroDivisionError` in Python.
                
                Here's a sample file with a zero denominator in the IFD fields
                `tag::x_resolution` and `tag::y_resolution` (both of which are of
                type `field_type::rational`):
                <https://github.com/python-pillow/Pillow/blob/807d689a83738027b6f6e0f219a6a6dd30e01c08/Tests/images/exif-dpi-zerodivision.jpg>
                """
                if hasattr(self, '_m_value'):
                    return self._m_value

                if self.value_den != 0:
                    pass
                    self._m_value = (self.value_num + 0.0) / self.value_den

                return getattr(self, '_m_value', None)

            def _invalidate_value(self):
                del self._m_value

        class Rationals(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Rationals, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/rationals")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    _t_values = Exif.ExifBody.Rational(self._io, self, self._root, self._is_le)
                    try:
                        _t_values._read()
                    finally:
                        self.values.append(_t_values)

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    _t_values = Exif.ExifBody.Rational(self._io, self, self._root, self._is_le)
                    try:
                        _t_values._read()
                    finally:
                        self.values.append(_t_values)

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass
                    self.values[i]._fetch_instances()



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Rationals, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/rationals")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self.values[i]._write__seq(self._io)



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self.values[i]._write__seq(self._io)



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass
                    if self.values[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"values", self._root, self.values[i]._root)
                    if self.values[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"values", self, self.values[i]._parent)

                self._dirty = False


        class Sbytes(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Sbytes, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/sbytes")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_s1())

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_s1())

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Sbytes, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/sbytes")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_s1(self.values[i])



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_s1(self.values[i])



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass

                self._dirty = False


        class Shorts(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Shorts, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/shorts")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_u2le())

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_u2be())

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Shorts, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/shorts")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_u2le(self.values[i])



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_u2be(self.values[i])



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass

                self._dirty = False


        class Slongs(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Slongs, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/slongs")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_s4le())

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_s4be())

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Slongs, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/slongs")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_s4le(self.values[i])



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_s4be(self.values[i])



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass

                self._dirty = False


        class Srational(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Srational, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/srational")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.value_num = self._io.read_s4le()
                self.value_den = self._io.read_s4le()
                self._dirty = False

            def _read_be(self):
                self.value_num = self._io.read_s4be()
                self.value_den = self._io.read_s4be()
                self._dirty = False


            def _fetch_instances(self):
                pass


            def _write__seq(self, io=None):
                super(Exif.ExifBody.Srational, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/srational")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                self._io.write_s4le(self.value_num)
                self._io.write_s4le(self.value_den)


            def _write__seq_be(self):
                self._io.write_s4be(self.value_num)
                self._io.write_s4be(self.value_den)


            def _check(self):
                self._dirty = False

            @property
            def value(self):
                """If denominator is zero, this instance is disabled to prevent
                `ZeroDivisionError` in Python.
                
                Here's a sample file with a zero denominator in the IFD field
                `tag::exposure_compensation` of type `field_type::srational`:
                <https://github.com/drewnoakes/metadata-extractor-images/blob/651ad0e67aa8d43d358ad05f9bc07b52d8b9ac6e/jpg/Reconyx%20Hyperfire%20HP4K.jpg>
                """
                if hasattr(self, '_m_value'):
                    return self._m_value

                if self.value_den != 0:
                    pass
                    self._m_value = (self.value_num + 0.0) / self.value_den

                return getattr(self, '_m_value', None)

            def _invalidate_value(self):
                del self._m_value

        class Srationals(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Srationals, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/srationals")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    _t_values = Exif.ExifBody.Srational(self._io, self, self._root, self._is_le)
                    try:
                        _t_values._read()
                    finally:
                        self.values.append(_t_values)

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    _t_values = Exif.ExifBody.Srational(self._io, self, self._root, self._is_le)
                    try:
                        _t_values._read()
                    finally:
                        self.values.append(_t_values)

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass
                    self.values[i]._fetch_instances()



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Srationals, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/srationals")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self.values[i]._write__seq(self._io)



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self.values[i]._write__seq(self._io)



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass
                    if self.values[i]._root != self._root:
                        raise kaitaistruct.ConsistencyError(u"values", self._root, self.values[i]._root)
                    if self.values[i]._parent != self:
                        raise kaitaistruct.ConsistencyError(u"values", self, self.values[i]._parent)

                self._dirty = False


        class Sshorts(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Sshorts, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/sshorts")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_s2le())

                self._dirty = False

            def _read_be(self):
                self.values = []
                for i in range(self._parent.num_values):
                    self.values.append(self._io.read_s2be())

                self._dirty = False


            def _fetch_instances(self):
                pass
                for i in range(len(self.values)):
                    pass



            def _write__seq(self, io=None):
                super(Exif.ExifBody.Sshorts, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/sshorts")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_s2le(self.values[i])



            def _write__seq_be(self):
                for i in range(len(self.values)):
                    pass
                    self._io.write_s2be(self.values[i])



            def _check(self):
                if len(self.values) != self._parent.num_values:
                    raise kaitaistruct.ConsistencyError(u"values", self._parent.num_values, len(self.values))
                for i in range(len(self.values)):
                    pass

                self._dirty = False


        class Utf8String(ReadWriteKaitaiStruct):
            def __init__(self, _io=None, _parent=None, _root=None, _is_le=None):
                super(Exif.ExifBody.Utf8String, self).__init__(_io)
                self._parent = _parent
                self._root = _root
                self._is_le = _is_le

            def _read(self):
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/utf8_string")
                elif self._is_le == True:
                    self._read_le()
                elif self._is_le == False:
                    self._read_be()
                self._dirty = False

            def _read_le(self):
                self.value = (self._io.read_bytes_term(0, False, True, False)).decode(u"UTF-8")
                self._dirty = False

            def _read_be(self):
                self.value = (self._io.read_bytes_term(0, False, True, False)).decode(u"UTF-8")
                self._dirty = False


            def _fetch_instances(self):
                pass


            def _write__seq(self, io=None):
                super(Exif.ExifBody.Utf8String, self)._write__seq(io)
                if not hasattr(self, '_is_le'):
                    raise kaitaistruct.UndecidedEndiannessError("/types/exif_body/types/utf8_string")
                elif self._is_le == True:
                    self._write__seq_le()
                elif self._is_le == False:
                    self._write__seq_be()


            def _write__seq_le(self):
                self._io.write_bytes((self.value).encode(u"UTF-8"))
                if not self._io.is_eof():
                    self._io.write_u1(0)



            def _write__seq_be(self):
                self._io.write_bytes((self.value).encode(u"UTF-8"))
                if not self._io.is_eof():
                    self._io.write_u1(0)



            def _check(self):
                if KaitaiStream.byte_array_index_of((self.value).encode(u"UTF-8"), 0) != -1:
                    raise kaitaistruct.ConsistencyError(u"value", -1, KaitaiStream.byte_array_index_of((self.value).encode(u"UTF-8"), 0))
                self._dirty = False


        @property
        def ifd0(self):
            if self._should_write_ifd0:
                self._write_ifd0()
            if hasattr(self, '_m_ifd0'):
                return self._m_ifd0

            if not self.ifd0__enabled:
                return None

            _pos = self._io.pos()
            self._io.seek(self.ofs_ifd0)
            if self._is_le:
                self._m_ifd0 = Exif.ExifBody.Ifd(False, self._io, self, self._root, self._is_le)
                self._m_ifd0._read()
            else:
                self._m_ifd0 = Exif.ExifBody.Ifd(False, self._io, self, self._root, self._is_le)
                self._m_ifd0._read()
            self._io.seek(_pos)
            return getattr(self, '_m_ifd0', None)

        @ifd0.setter
        def ifd0(self, v):
            self._dirty = True
            self._m_ifd0 = v

        def _write_ifd0(self):
            self._should_write_ifd0 = False
            _pos = self._io.pos()
            self._io.seek(self.ofs_ifd0)
            if self._is_le:
                self._m_ifd0._write__seq(self._io)
            else:
                self._m_ifd0._write__seq(self._io)
            self._io.seek(_pos)