<p>0x0132不是偏移量,而是日期的标记号。CR2或TIFF分别是基于目录的格式。你必须根据你正在寻找的(已知的)标签来查找条目。</p>
<p><strong>编辑</strong>:
好的,首先,您必须读取文件数据是使用小端格式还是大端格式保存的。前八个字节指定头,头的前两个字节指定尾数。Python的struct模块允许您通过在格式字符串前面加上“<;”或“>;”来处理小数据和大数据。因此,假设<code>data</code>是包含CR2图像的缓冲区,您可以通过</p>
<pre><code>header = data[:8]
endian_flag = "<" if header[:2] == "II" else ">"
</code></pre>
<p>格式规范指出,第一个图像文件目录以相对于文件开头的偏移量开始,偏移量在头的最后4个字节中指定。因此,要获得第一个IFD的偏移量,可以使用类似于此的行:</p>
<pre><code>ifd_offset = struct.unpack("{0}I".format(endian_flag), header[4:])[0]
</code></pre>
<p>你现在可以继续读第一本IFD了。您将在目录中指定的文件偏移量处找到条目数,该偏移量为两个字节宽。因此,您可以使用以下方法读取第一个IFD中的条目数:</p>
<pre><code>number_of_entries = struct.unpack("{0}H".format(endian_flag), data[ifd_offset:ifd_offset+2])[0]
</code></pre>
<p>字段项的长度为12字节,因此可以计算IFD的长度。在条目数*12字节后,还有一个4字节长的偏移量,告诉您在哪里查找下一个目录。这基本上就是你处理TIFF和CR2图像的方式。</p>
<p>这里的“魔力”是要注意,对于12字节字段条目中的每一个,前两个字节将是标记ID,这就是您寻找标记0x0132的地方。因此,如果您知道第一个IFD从文件中的IFD_偏移开始,您可以通过以下方式扫描第一个目录:</p>
<pre><code>current_position = ifd_offset + 2
for field_offset in xrange(current_position, number_of_entries*12, 12):
field_tag = struct.unpack("{0}H".format(endian_flag), data[field_offset:field_offset+2])[0]
field_type = struct.unpack("{0}H".format(endian_flag), data[field_offset+2:field_offset+4])[0]
value_count = struct.unpack("{0}I".format(endian_flag), data[field_offset+4:field_offset+8])[0]
value_offset = struct.unpack("{0}I".format(endian_flag), data[field_offset+8:field_offset+12])[0]
if field_tag == 0x0132:
# You are now reading a field entry containing the date and time
assert field_type == 2 # Type 2 is ASCII
assert value_count == 20 # You would expect a string length of 20 here
date_time = struct.unpack("20s", data[value_offset:value_offset+20])
print date_time
</code></pre>
<p>很明显,您需要将该解包重构为一个公共函数,并可能将整个格式包装成一个好的类,但这超出了本例的范围。您还可以通过将多个格式字符串组合成一个字符串来缩短解包过程,生成一个更大的元组,其中包含可以解包到不同变量中的所有字段,为了清楚起见,我省略了这些字段。</p>