python修改压缩文件_如何在python中修改现有文件的压缩itxt记录?

本文介绍了如何使用Python的PyPNG库来修改现有PNG文件中的iTXt块,包括理解iTXt块的结构,创建自定义类处理压缩和解压缩,以及通过迭代、修改和写回块来更新PNG文件。
摘要由CSDN通过智能技术生成

这并不像你看到的那么简单。如果是的话,你可能会发现有一个简单的解决方案。在

让我们从基础知识开始。在

PyPNG能读所有的块吗?在

一个重要的问题,因为修改一个现有的PNG文件是一个很大的任务。读了它的文档,它的开头并不好:PNG: Chunk by Chunk

Ancillary Chunks

..

iTXt

Ignored when reading. Not generated.

但在下面那一页,救赎!在Non-standard Chunks

Generally it is not possible to generate PNG images with any other chunk types. When reading a PNG image, processing it using the chunk interface, png.Reader.chunks, will allow any chunk to be processed (by user code).

所以我所要做的就是编写这个“用户代码”,PyPNG可以完成剩下的工作。(Oof.)

那么iTXt块呢?在

让我们看看你感兴趣的是什么。在4.2.3.3. iTXt International textual data

.. the textual data is in the UTF-8 encoding of the Unicode character set instead of Latin-1. This chunk contains:Keyword: 1-79 bytes (character string)

Null separator: 1 byte

Compression flag: 1 byte

Compression method: 1 byte

Language tag: 0 or more bytes (character string)

Null separator: 1 byte

Translated keyword: 0 or more bytes

Null separator: 1 byte

Text: 0 or more bytes

我看清楚了。可选压缩不应该是个问题,因为.. [t]he only value presently defined for the compression method byte is 0, meaning zlib ..

我很有信心Python的某些东西可以为我做到这一点。在

回到PyPNG的块处理。在

我们能看到数据块吗?在

{eem>如果PNG确实包含一个,那么PNG可以很容易地进行检查:chunks()

Return an iterator that will yield each chunk as a (chunktype, content) pair.

所以让我们在交互模式下编写一些代码并检查。我从http://pmt.sourceforge.net/itxt/获得了一个示例图像,为了方便起见,这里重复了这个示例。(如果iTXt数据未在此处保存,请下载并使用原始数据。)

>>> import png

>>> imageFile = png.Reader("itxt.png")

>>> print imageFile

>>> for c in imageFile.chunks():

... print c[0],len(c[1])

...

IHDR 13

gAMA 4

sBIT 4

pCAL 44

tIME 7

bKGD 6

pHYs 9

tEXt 9

iTXt 39

IDAT 4000

IDAT 831

zTXt 202

iTXt 111

IEND 0

成功!在

回信怎么样?PyPNG通常用于创建完整的图像,但幸运的是,它还提供了一种从自定义块显式创建图像的方法:png.write_chunks(out, chunks)

Create a PNG file by writing out the chunks.

因此,我们可以迭代块,更改所需的块,然后写回修改后的PNG。在

解包和打包iTXt数据

这本身就是一项任务。数据格式描述得很好,但不适合Python的本机unpack和{}方法。所以我们必须自己发明一些东西。在

文本字符串以ASCIIZ格式存储:以零字节结尾的字符串。我们需要一个小函数来拆分第一个0:

^{pr2}$

这个快速而脏的函数返回一个数组,其中包含一对[在之前,在]之后,并丢弃0本身。在

为了尽可能透明地处理iTXt数据,我将其设为一个类:class Chunk_iTXt:

def __init__(self, chunk_data):

tmp = cutASCIIZ(chunk_data)

self.keyword = tmp[0]

if len(tmp[1]):

self.compressed = ord(tmp[1][0])

else:

self.compressed = 0

if len(tmp[1]) > 1:

self.compressionMethod = ord(tmp[1][1])

else:

self.compressionMethod = 0

tmp = tmp[1][2:]

tmp = cutASCIIZ(tmp)

self.languageTag = tmp[0]

tmp = tmp[1]

tmp = cutASCIIZ(tmp)

self.languageTagTrans = tmp[0]

if self.compressed:

if self.compressionMethod != 0:

raise TypeError("Unknown compression method")

self.text = zlib.decompress(tmp[1])

else:

self.text = tmp[1]

def pack (self):

result = self.keyword+chr(0)

result += chr(self.compressed)

result += chr(self.compressionMethod)

result += self.languageTag+chr(0)

result += self.languageTagTrans+chr(0)

if self.compressed:

if self.compressionMethod != 0:

raise TypeError("Unknown compression method")

result += zlib.compress(self.text)

else:

result += self.text

return result

def show (self):

print 'iTXt chunk contents:'

print ' keyword: "'+self.keyword+'"'

print ' compressed: '+str(self.compressed)

print ' compression method: '+str(self.compressionMethod)

print ' language: "'+self.languageTag+'"'

print ' tag translation: "'+self.languageTagTrans+'"'

print ' text: "'+self.text+'"'

因为它使用zlib,所以它需要在程序顶部有一个import zlib。在

类构造函数接受“太短”字符串,在这种情况下,它将对所有未定义的字符串使用默认值。在

show方法列出用于调试的数据。在

使用我的自定义类

有了所有这些,现在检查、修改和添加iTXt块最终是简单的:import png

import zlib

# insert helper and class here

sourceImage = png.Reader("itxt.png")

chunkList = []

for chunk in sourceImage.chunks():

if chunk[0] == 'iTXt':

itxt = Chunk_iTXt(chunk[1])

itxt.show()

# modify existing data

if itxt.keyword == 'Author':

itxt.text = 'Rad Lexus'

itxt.compressed = 1

chunk = [chunk[0], itxt.pack()]

chunkList.append (chunk)

# append new data

newData = Chunk_iTXt('')

newData.keyword = 'Custom'

newData.languageTag = 'nl'

newData.languageTagTrans = 'Aangepast'

newData.text = 'Dat was leuk.'

chunkList.insert (-1, ['iTXt', newData.pack()])

with open("foo.png", "wb") as file:

png.write_chunks(file, chunkList)

当添加一个全新的块时,请小心而不是到append它,因为它将出现在所需的最后一个IEND块之后,这是一个错误。我没有尝试,但您也可能不应该将它插入所需的第一个IHDR块之前,或者(正如Glenn Randers Pehrson所评论的那样)在连续的IDAT块之间插入。在

注意,根据规范,iTXt中的所有文本都应该是UTF8编码的。在

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值