如何修复一张损坏的tiff图像文件?

634 阅读6分钟

image.png 今天有朋友发了个tiff文件,说是损坏了,之前能打开,现在不知道为啥打不开了。问能不能帮忙修复。那得看看啊,图形图像相关的问题我都有兴趣看看。

先在网上找了几个工具,尝试了下万兴易修,没修复成功。

在网上找存在类似问题的文章看了下,提到有一种情况是磁盘坏道导致图像丢失部分数据,如果丢失的数据在头信息里面会导致整个图像读取不出来,如果丢失的数据是图像数据会导致图像缺行。

这个tiff文件能在文件信息里面能展示图像分辨率(1360x1024),但是图像打开是一片黑色。有分辨率信息说明部分头信息是正常的,图像全黑,说明部分关键头信息应该丢失了,图像数据大概率还是正常的。

那没办法了,只能对照tiff文件格式,逐个字节看文件的头信息了。大概看了眼TIFF的头信息文档,整体结构感觉比较简单,感觉可以分析一把。

文件用sublime打开,对照TIFF文档逐个查数据,遇到的第一个问题是低字节序和高字节序。之前当然知道这个概念,人工解码的时候发现还是容易混淆。

一图胜千言,下面两张图来自blog,简直救了命了:blog.gtwang.org/programming…

这个文件字节顺序是II(4949),低字节顺序,可读性比高字节顺序MM要差,需要人脑换位。

重点看IFD(图像文件目录),IFD里面每个12字节分四段记录一个图像目录项(DE,其实就是一个图像属性数据):tag、type、count、value/offset。

这个文件只有一个IFD,18个DE。挑几个代表性的属性记录:

tagtypecountvalue/offset
DE1000104000100 00005005 0000
imageWidthLONG11360
DE2010104000100 00000004 0000
imageLengthLONG11024
DE3020103000300 00001a02 0000
BitsPerSampleSHORT3538
DE10170104004000 0000e600 0000
stripByteCountsLONG64230

一开始没太理解value/offset的意思,“如果占用的字节数少于等于4, 则数据直接存于此。如果超过4个,则这里存放的是指向实际数据的指针”。

我们以DE1和DE3为例子:

DE1的type是long,count是1,占用字节数是4*1(一个long四个字节,乘以count),而value/offset段刚好是4字节,存得下所以DE1的value/offset段直接存储数据

DE3的type是short,count是3,占用字节数是2*3(一个short两个字节,乘以count),因此value/offset段4字节存不下,因此存的是offset。从文件头开始数538个字节,然后读取3个short就是DE3的值。

最后汇总DE里面的文件信息

imageWidth=1360   图像宽度是1360

imageLength=1024  图像高度是1024

Compression=uncompressed    图像数据未压缩

photometricInterpretation=RGB   图像数据RGB格式

SamplesPerPixel=3    每个像素点占用3个字节

RowsPerStrip=16 每个条带内有16行

PlanarConfiguration=1   how the components of each pixel are stored  1:having all samples for a pixel next to each other within a single strip/tile     这个等于1说明每个像素的RGB是存储一起,不是像YUV那样每个sample一个条带。

查看了下文件大小,4178722字节,图像无压缩存储,136010243=4177920, 4178722-4177920=802,因此这个文件大概有802字节的头信息,剩下的刚好全部是图像数据。因此这个文件基本的文件头信息都是正确的,大概率图像数据都在,基本确定是能修复的。

这里有个条带的概念,其实就是图像被分成小块存储,这个文件就是每十六行一个小块,所以1024行应该有64个小块,这个值也叫StripsPerImage,后面偏移量信息里面需要用到这个数值。

看偏移量信息:

BitsPerSample=538  每个分量的Bit数,偏移538读取3个short:0800 0800 0800,说明图像每个分量用8bit。

StripOffsets=546  每个条带数据在文件中的偏移量,count=64=StripsPerImage,存储的是64个条带的实际图像数据在文件中的偏移量:

偏移量1:2203 0000 =31616+216+2=802=5016+2

偏移量2:2202 0100 =116^4+216^2+216+2=66082   和偏移量1的值相隔65280=161360*3

...

偏移量64:22c4 3e00 = 316^5+1416^4+1216^3+416^2+2*16+2=4113442  

这个地方对偏移量数据简单做了验证:

首先偏移量1=802,还记得上面我们算过图像文件大小和整个图像数据大小的差别吗?刚好是802,因此第一个偏移量大概率是正确的。

偏移量2和偏移量1相差65280=1613603,刚好是一个strip的存储大小,而最后一个偏移量64=4113442,文件总大小4178722-4113442=65280。

因此文件从802开始全是条带图像数据。偏移量数据大概率没问题

stripByteCounts=230   每个条带内的字节数,count=64。这个其实根据上面的计算,不需要配置了(就是65280嘛),但是看了眼文件里面的数据,全是0,因此这块数据要么是走的老规范,要么就是被损坏了,因此这64个long数值,全替换成65280(00ff 0000)尝试下。

修改了stripByteCounts的64个long数值,文件就展示正常了。

参考资料:

blog.csdn.net/oYinHeZhiGu…

blog.csdn.net/weixin_4487…

blog.csdn.net/chuyou6773/…

blog.gtwang.org/programming…