从多页TIFF文件中删除页面

2 投票
1 回答
4826 浏览
提问于 2025-04-16 13:10

我需要从一个多页的TIFF文件中删除一页。目前我在使用.NET,但如果有人知道其他语言怎么做,我也可以换语言。

我想删除的页面要么是倒数第二页,要么是最后一页。而且我需要在不解压缩前面页面的情况下完成这个操作,也就是说,不想新建一个TIFF文件然后把我还想要的所有页面复制过去。

我已经有可以做到这一点的代码,但我现在处理的TIFF文件大约有1.0GB到3.0GB,而且压缩得很厉害,这样做非常耗时间。如果我能直接删除我想要的部分,而不需要新建一个文件,那样会快很多。

我需要删除的页面相对于整个文件来说非常小,可能只有500*500像素,而它后面可能有的页面也是如此。

我尝试过使用LibTiff.Net这个库,链接在这里:

http://bitmiracle.com/libtiff/

我研究了一段时间后,问了开发者我的问题,他们说目前不支持这样做。我也稍微研究了一下ImageMagick,但到现在为止我还没能搞明白怎么在那儿做到这一点。

有没有人有好的建议呢?

1 个回答

3

好的,我在Python中找到了一个可行的解决方案。

import mmap
from struct import *

def main():
    filename = raw_input("Input file name: ")
    f = open(filename, "r+b")
    offList, compList = getOffsets(f)
    for i in range(len(offList)):
        print "offset: ", offList[i], "\t Compression: ", compList[i]
    print "ran right"
    stripLabelAndMacro(f, offList, 3)
    offList, compList = getOffsets(f)
    for i in range(len(offList)):
        print "offset: ", offList[i], "\t Compression: ", compList[i]
    f.close()
    #test stripping end crap

def getOffsets(f):
    fmap = mmap.mmap(f.fileno(),0)
    offsets = []
    compressions = []
    #get TIFF version
    ver = int(unpack('H', fmap[2:4])[0])
    if ver == 42:
        #get first IDF
        offset = long(unpack('L', fmap[4:8])[0])
        while (offset != 0):
            offsets.append(offset)
            #get number of tags in this IDF
            tags = int(unpack('H', fmap[offset:offset+2])[0])
            i = 0
            while (i<tags):
                tagID = int(unpack('H',fmap[offset+2:offset+4])[0])
                #if the tag is a compression, get the compression SHORT value and
                #if recognized use a string representation
                if tagID == 259:
                    tagValue = int(unpack('H', fmap[offset+10:offset+12])[0])
                    if tagValue == 1:
                        compressions.append("None")
                    elif tagValue == 5:
                        compressions.append("LZW")
                    elif tagValue == 6:
                        compressions.append("JPEG")
                    elif tagValue == 7:
                        compressions.append("JPEG")
                    elif tagValue == 34712 or tagValue == 33003 or tagValue == 33005:
                        compressions.append("JP2K")
                    else:
                        compressions.append("Unknown")
                i+=1
                offset += 12

            offset = long(unpack('L', fmap[offset+2:offset+6])[0])
    return offsets, compressions

#Tested, Doesn't break TIFF
def stripLabel(f, offsetList, labelIndex):
    fmap = mmap.mmap(f.fileno(),0)
    offsetLabel = offsetList[labelIndex]
    offsetMacro = offsetList[labelIndex+1]
    offsetEnd = fmap.size()
    macroSize = offsetEnd - offsetMacro
    for i in range(macroSize):
        fmap[offsetLabel+i] = fmap[offsetMacro+i]
    fmap.flush()
    fmap.resize(offsetLabel+macroSize-1)
    fmap.close()

我测试过了,效果不错。这个stripLabel方法主要是用来去掉倒数第二个页面或目录,并把最后一个页面上移。不过理论上,它也可以用在其他任何不是最后一个的目录上,而且也可以很容易地修改成去掉最后一个目录。使用这个方法时,你的电脑至少需要有和你正在处理的文件大小一样多的空闲内存,但运行速度很快,对于大多数TIFF文件来说,文件大小不是问题。这种方法可能不是最优雅的,如果有人有更好的方法,请分享一下。

撰写回答