TIFF file format#
The TIFF v6.0 format described by FLML.
[# TIFF v6.0]
#Image File Header
[2]<char>(name="byte order"; id="byte_oder"; choices={['I','I'], ['M','M']})
[1]<uint16; =42>(name="magic number")
[1]<uint32; :offset_to_first_IFD>(id="offset_to_first_IFD")
if (offset_to_first_IFD >= 8) {
tag_info = {}
goto (offset_to_first_IFD) {
[1]<uint16; :entry_num>(name="entry number")
[entry_num]{
[1]<uint16; :tag_id>
[1]<uint16; :tag_data_type>
[1]<uint32; :tag_data_type_count>
[4]<byte; :value_or_offset>
key, value = get_tag_info(tag_id, tag_data_type, tag_data_type_count, value_or_offset);
tag_info[key] = value;
}
[1]<uint32; offset_to_next_IFD>
}
i = 0;
for (stripoffset in tag_info["StripOffsets"]) {
goto (stripoffset) {
[tag_info["StripByteCounts"][i] / (sum(tag_info["BitsPerSample"]) / 8) / tag_info["ImageWidth"]]{
[tag_info[ImageWidth]]{
[sum(tag_info["BitsPerSample"]) / 8]<byte>
}
}
[tag_info["StripByteCounts"][i]] {
[3]<byte>
}
}
i += 1;
}
}
fun get_tag_data_type(data_type) {
if (data_type == 1) {
data_type = [1, 1, "uint8"];
} elif (data_type == 2) {
data_type = [1, 1, "char"];
} elif (data_type == 3) {
data_type = [2, 2, "uint16"];
} elif (data_type == 4) {
data_type = [4, 4, "uint32"];
} elif (data_type == 5) {
data_type = [8, 4, "uint32"];
} elif (data_type == 6) {
data_type = [1, 1, "int8"];
} elif (data_type == 7) {
data_type = [1, 1, "byte"];
} elif (data_type == 8) {
data_type = [2, 2, "int16"];
} elif (data_type == 9) {
data_type = [4, 4, "int32"];
} elif (data_type == 10) {
data_type = [8, 4, "int32"];
} elif (data_type == 11) {
data_type = [4, 4, "float"];
} elif (data_type == 12) {
data_type == [8, 8, "double"];
} else {
raise Exception("unkown data type");
}
return data_type;
}
fun byte_to_int(bytes_arr, int_type, int_bytes_len, int_num) {
int_s = [];
if (int_type == "uint") {
for (i = 0; i < int_num; i++) {
n = 0;
for (j = 0; j < int_bytes_len; j++) {
n += byte_arr[i * int_bytes_len + j] * 255**j;
}
}
}
return int_s;
}
fun get_tag_info(tag_id, tag_data_type, tag_data_type_count, value_or_offset) {
if (tag_id == 256) {
tag_data_type = get_tag_data_type(tag_data_type); #[2, 2, "uint16"]
return "ImageWidth", byte_to_int(value_or_offset, "uint", tag_data_type[1], 1)[0]
}
elif (tag_id == 257) {
tag_data_type = get_tag_data_type(tag_data_type);
return "ImageLength", byte_to_int(value_or_offset, "uint", tag_data_type[1], 1)[0];
}
elif (tag_id == 258) {
tag_data_type = get_tag_data_type(tag_data_type);
if (tag_data_type[0] * tag_data_type_count > 4) {
seek_pos = byte_to_int(value_or_offset, "uint", tag_data_type[1], 1)[0];
fileself.seek(seek_pos);
return "BitsPerSample", fileself.read(tag_data_type[1] * tag_data_type_count);
}
else {
return "BitsPerSample", byte_to_int(value_or_offset, "uint", tag_data_type[1], tag_data_type_count);
}
}
elif (tag_id == 259) {
return "Compression", byte_to_int(value_or_offset, "uint", 2, 1)[0];
}
elif (tag_id == 262) {
return "PhotometricInterpretation", byte_to_int(value_or_offset, "uint", 2, 1)[0];
}
elif (tag_id == 273) {
tag_data_type = get_tag_data_type(tag_data_type);
if (tag_data_type[0] * tag_data_type_count > 4) {
seek_pos = byte_to_int(value_or_offset, "uint" tag_data_type[1], 1)[0];
fileself.seek(seek_pos);
bytes_arr = fileself.read(tag_data_type[1] * tag_data_type_count);
return "StripOffsets", byte_to_int(bytes_arr, "uint", tag_data_type[1], tag_data_type_count);
}
else {
return "StripOffsets", byte_to_int("uint", value_or_offset, 2, tag_data_type_count);
}
}
elif (tag_id == 274) {
return "SamplesPerPixel", byte_to_int(value_or_offset, "uint", 2, 1)[0];
}
elif (tag_id == 278) {
return "RowsPerStrip", byte_to_int(value_or_offset, "uint", 2, 1)[0];
}
elif (tag_id == 279) {
tag_data_type = get_tag_data_type(tag_data_type);
if (tag_data_type[0] * tag_data_type_count > 4) {
seek_pos = byte_to_int("uint", value_or_offset, tag_data_type[1], 1)[0];
fileself.seek(seek_pos);
byte_arr = fileself.read(tag_data_type[1] * tag_data_type_count);
return "StripOffsets", byte_to_int(byte_arr, "uint", tag_data_type[1], tag_data_type_count);
}
else {
return "StripOffsets", byte_to_int(value_or_offset, "uint", 2, tag_data_type_count);
}
}
}
[#Notes
byte_oder:
Two char to indicate byte order, can be "II" for little ednian
or "MM" for big endian.
offset_to_first_IFD:
The offset to the first IFD(Image File Directory).
]
[#Reference
1. https://www.fileformat.info/format/tiff/egff.htm
]