在Linux环境下转换IPA包里的PNG图

网上许多关于这个问题的回答都归结为两个:

  1. 提供一段不能正确处理多段IDAT情况的代码,无法处理Xcode7(以前的版本是否同样,未考究)打包生成的IPA包里的PNG文件。
  2. 使用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。
这样基本就没有出现错误转换的情况了。

你可能感兴趣的:(在Linux环境下转换IPA包里的PNG图)