网上许多关于这个问题的回答都归结为两个:
- 提供一段不能正确处理多段IDAT情况的代码,无法处理Xcode7(以前的版本是否同样,未考究)打包生成的IPA包里的PNG文件。
- 使用Apple自己的转换命令
xcrun pngcrush -revert-iphone-optimizations
,这个命令在Mac上当然是好用的,但是,并不能在Linux上使用。
Linux下的pngcrush能识别IPA格式的PNG图,然后也并不能正确处理。
最后深挖了一轮之后找到这段实现。这段实现和网上流传的一个版本的实现很像,但是能够正确的处理多段IDAT的情况(原谅我,找到之后做了一轮测试,无意中关闭了浏览器,却再也找不回出处了)
下面的代码并非我原创,有知道原著地址的朋友,请帮忙告知一下
def getNormalizedPNG(filename):
pngheader = "\\\\x89PNG\\\\r\\\\n\\\\x1a\\\\n"
file = open(filename, "rb")
oldPNG = file.read()
file.close()
if oldPNG[:8] != pngheader:
return None
newPNG = oldPNG[:8]
chunkPos = len(newPNG)
idatAcc = ""
breakLoop = False
foundCgBI = False
# For each chunk in the PNG file
while chunkPos < len(oldPNG):
skip = False
# Reading chunk
chunkLength = oldPNG[chunkPos:chunkPos+4]
chunkLength = unpack(">L", chunkLength)[0]
chunkType = oldPNG[chunkPos+4 : chunkPos+8]
chunkData = oldPNG[chunkPos+8:chunkPos+8+chunkLength]
chunkCRC = oldPNG[chunkPos+chunkLength+8:chunkPos+chunkLength+12]
chunkCRC = unpack(">L", chunkCRC)[0]
chunkPos += chunkLength + 12
# Parsing the header chunk
if chunkType == "IHDR":
width = unpack(">L", chunkData[0:4])[0]
height = unpack(">L", chunkData[4:8])[0]
# Parsing the image chunk
if chunkType == "IDAT":
# Store the chunk data for later decompression
idatAcc += chunkData
skip = True
# Removing CgBI chunk
if chunkType == "CgBI":
skip = True
foundCgBI = True
# Add all accumulated IDATA chunks
if chunkType == "IEND":
try:
# Uncompressing the image chunk
bufSize = width * height * 4 + height
chunkData = decompress( idatAcc, -15, bufSize)
except Exception, e:
# The PNG image is normalized
print "Decompress exception:%s" % e
return None
chunkType = "IDAT"
# Swapping red & blue bytes for each pixel
newdata = ""
for y in xrange(height):
i = len(newdata)
newdata += chunkData[i]
for x in xrange(width):
i = len(newdata)
newdata += chunkData[i+2]
newdata += chunkData[i+1]
newdata += chunkData[i+0]
newdata += chunkData[i+3]
# Compressing the image chunk
chunkData = newdata
chunkData = compress( chunkData )
chunkLength = len( chunkData )
chunkCRC = crc32(chunkType)
chunkCRC = crc32(chunkData, chunkCRC)
chunkCRC = (chunkCRC + 0x100000000) % 0x100000000
breakLoop = True
if not skip:
newPNG += pack(">L", chunkLength)
newPNG += chunkType
if chunkLength > 0:
newPNG += chunkData
newPNG += pack(">L", chunkCRC)
if breakLoop:
break
if not foundCgBI:
# It shout be not Xcode PNG format
return None
return newPNG```
###然后上面的代码还是有一些小问题,使用时候需要注意的:
###它不能正确的判断文件的格式,一律按IPA的格式处理。当原文件并不是IPA的格式的时候,它会处理出一个错误的文件——而不是报错退出。
----
总算到我了的贡献了:
* 在分析每个Chunk的时候记录一下是否有CgBI类型的Chunk,如果整个文件都木有这个类型的块,那么我认为它肯定不是Xcode处理过的PNG格式,返回None。
这样基本就没有出现错误转换的情况了。