This page hosts a formal specification of exif using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
-- This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
--
-- This file is compatible with Lua 5.3
local class = require("class")
require("kaitaistruct")
local enum = require("enum")
local utils = require("utils")
Exif = class.class(KaitaiStruct)
function Exif:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function Exif:_read()
self.endianness = self._io:read_u2le()
self.body = Exif.ExifBody(self._io, self, self._root)
end
Exif.ExifBody = class.class(KaitaiStruct)
function Exif.ExifBody:_init(io, parent, root)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self:_read()
end
function Exif.ExifBody:_read()
local _on = self._root.endianness
if _on == 18761 then
self._is_le = true
elseif _on == 19789 then
self._is_le = false
end
if self._is_le == true then
self:_read_le()
elseif self._is_le == false then
self:_read_be()
else
error("unable to decide endianness")
end
end
function Exif.ExifBody:_read_le()
self.version = self._io:read_u2le()
self.ifd0_ofs = self._io:read_u4le()
end
function Exif.ExifBody:_read_be()
self.version = self._io:read_u2be()
self.ifd0_ofs = self._io:read_u4be()
end
Exif.ExifBody.property.ifd0 = {}
function Exif.ExifBody.property.ifd0:get()
if self._m_ifd0 ~= nil then
return self._m_ifd0
end
local _pos = self._io:pos()
self._io:seek(self.ifd0_ofs)
if self._is_le then
self._m_ifd0 = Exif.ExifBody.Ifd(self._io, self, self._root, self._is_le)
else
self._m_ifd0 = Exif.ExifBody.Ifd(self._io, self, self._root, self._is_le)
end
self._io:seek(_pos)
return self._m_ifd0
end
Exif.ExifBody.Ifd = class.class(KaitaiStruct)
function Exif.ExifBody.Ifd:_init(io, parent, root, is_le)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self._is_le = is_le
self:_read()
end
function Exif.ExifBody.Ifd:_read()
if self._is_le == true then
self:_read_le()
elseif self._is_le == false then
self:_read_be()
else
error("unable to decide endianness")
end
end
function Exif.ExifBody.Ifd:_read_le()
self.num_fields = self._io:read_u2le()
self.fields = {}
for i = 0, self.num_fields - 1 do
self.fields[i + 1] = Exif.ExifBody.IfdField(self._io, self, self._root, self._is_le)
end
self.next_ifd_ofs = self._io:read_u4le()
end
function Exif.ExifBody.Ifd:_read_be()
self.num_fields = self._io:read_u2be()
self.fields = {}
for i = 0, self.num_fields - 1 do
self.fields[i + 1] = Exif.ExifBody.IfdField(self._io, self, self._root, self._is_le)
end
self.next_ifd_ofs = self._io:read_u4be()
end
Exif.ExifBody.Ifd.property.next_ifd = {}
function Exif.ExifBody.Ifd.property.next_ifd:get()
if self._m_next_ifd ~= nil then
return self._m_next_ifd
end
if self.next_ifd_ofs ~= 0 then
local _pos = self._io:pos()
self._io:seek(self.next_ifd_ofs)
if self._is_le then
self._m_next_ifd = Exif.ExifBody.Ifd(self._io, self, self._root, self._is_le)
else
self._m_next_ifd = Exif.ExifBody.Ifd(self._io, self, self._root, self._is_le)
end
self._io:seek(_pos)
end
return self._m_next_ifd
end
Exif.ExifBody.IfdField = class.class(KaitaiStruct)
Exif.ExifBody.IfdField.FieldTypeEnum = enum.Enum {
byte = 1,
ascii_string = 2,
word = 3,
dword = 4,
rational = 5,
undefined = 7,
slong = 9,
srational = 10,
}
Exif.ExifBody.IfdField.TagEnum = enum.Enum {
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,
}
function Exif.ExifBody.IfdField:_init(io, parent, root, is_le)
KaitaiStruct._init(self, io)
self._parent = parent
self._root = root or self
self._is_le = is_le
self:_read()
end
function Exif.ExifBody.IfdField:_read()
if self._is_le == true then
self:_read_le()
elseif self._is_le == false then
self:_read_be()
else
error("unable to decide endianness")
end
end
function Exif.ExifBody.IfdField:_read_le()
self.tag = Exif.ExifBody.IfdField.TagEnum(self._io:read_u2le())
self.field_type = Exif.ExifBody.IfdField.FieldTypeEnum(self._io:read_u2le())
self.length = self._io:read_u4le()
self.ofs_or_data = self._io:read_u4le()
end
function Exif.ExifBody.IfdField:_read_be()
self.tag = Exif.ExifBody.IfdField.TagEnum(self._io:read_u2be())
self.field_type = Exif.ExifBody.IfdField.FieldTypeEnum(self._io:read_u2be())
self.length = self._io:read_u4be()
self.ofs_or_data = self._io:read_u4be()
end
Exif.ExifBody.IfdField.property.type_byte_length = {}
function Exif.ExifBody.IfdField.property.type_byte_length:get()
if self._m_type_byte_length ~= nil then
return self._m_type_byte_length
end
self._m_type_byte_length = utils.box_unwrap((self.field_type == Exif.ExifBody.IfdField.FieldTypeEnum.word) and utils.box_wrap(2) or (utils.box_unwrap((self.field_type == Exif.ExifBody.IfdField.FieldTypeEnum.dword) and utils.box_wrap(4) or (1))))
return self._m_type_byte_length
end
Exif.ExifBody.IfdField.property.byte_length = {}
function Exif.ExifBody.IfdField.property.byte_length:get()
if self._m_byte_length ~= nil then
return self._m_byte_length
end
self._m_byte_length = (self.length * self.type_byte_length)
return self._m_byte_length
end
Exif.ExifBody.IfdField.property.is_immediate_data = {}
function Exif.ExifBody.IfdField.property.is_immediate_data:get()
if self._m_is_immediate_data ~= nil then
return self._m_is_immediate_data
end
self._m_is_immediate_data = self.byte_length <= 4
return self._m_is_immediate_data
end
Exif.ExifBody.IfdField.property.data = {}
function Exif.ExifBody.IfdField.property.data:get()
if self._m_data ~= nil then
return self._m_data
end
if not(self.is_immediate_data) then
local _io = self._root._io
local _pos = _io:pos()
_io:seek(self.ofs_or_data)
if self._is_le then
self._m_data = _io:read_bytes(self.byte_length)
else
self._m_data = _io:read_bytes(self.byte_length)
end
_io:seek(_pos)
end
return self._m_data
end