Перенос скрипта в python 2 в python 3.x - PullRequest
0 голосов
/ 04 декабря 2018

После этого прошлого вопроса: Как я могу заставить этот скрипт Python работать с Python 3?

Я бы хотел, чтобы этот скрипт работал в Python 3. Мне удалось исправитьнекоторые детали, но это все еще не работает .. теперь, кажется, выдает ошибку при распаковке данных чанка.

Вот текущая ошибка, которую я имею: Ошибка -5 при распаковке данных: неполный или усеченный поток

Я использую Python 3.6.2

А вот сценарий с вещами, уже перенесенными в Python 3. Сценарий в основном нормализует PNG с пользовательским форматом iphone.

import pdb
from struct import *
from zlib import *
import stat
import sys
import os
import zlib

def getNormalizedPNG(filename):
    pngheader = b"\x89PNG\r\n\x1a\n"

    pdb.set_trace()

    file = open(filename, "rb")
    oldPNG = file.read()
    file.close()

    if oldPNG[:8] != pngheader:
        return None

    newPNG = oldPNG[:8]

    chunkPos = len(newPNG)

    # For each chunk in the PNG file
    while chunkPos < len(oldPNG):

        # 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 == b"IHDR":
            width = unpack(">L", chunkData[0:4])[0]
            height = unpack(">L", chunkData[4:8])[0]

        # Parsing the image chunk
        if chunkType == b"IDAT":
            try:
                pdb.set_trace()
                # Uncompressing the image chunk
                bufSize = width * height * 4 + height

                chunkData = decompress(chunkData, -8, bufSize)

            except Exception as e:
                print("Already normalized")
                print(e)
                # The PNG image is normalized
                return None

            # Swapping red & blue bytes for each pixel
            newdata = b""
            for y in range(height):
                i = len(newdata)
                newdata += chunkData[i]
                for x in range(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

        # Removing CgBI chunk
        if chunkType != b"CgBI":
            newPNG += pack(">L", chunkLength)
            newPNG += chunkType
            if chunkLength > 0:
                newPNG += chunkData
            newPNG += pack(">L", chunkCRC)

        # Stopping the PNG file parsing
        if chunkType == b"IEND":
            break

    return newPNG


def updatePNG(filename):
    data = getNormalizedPNG(filename)

    if data != None:
        file = open(filename, "wb")
        file.write(data)
        file.close()
        return True
    return data

Любая подсказка будет оценена.Спасибо!:)

1 Ответ

0 голосов
/ 05 декабря 2018

Исходный код не обрабатывает сразу несколько IDAT фрагментов;он делает правильные вещи ™ и объединяет их в один большой объект, а затем распаковывает его целиком.IDAT чанки не сжимаются отдельно, но ваш код предполагает, что они это делают, и поэтому происходит сбой, когда их несколько.

Может быть несколько чанков IDAT;если это так, они должны появляться последовательно без каких-либо других промежуточных фрагментов.Затем сжатый поток данных является конкатенацией содержимого полей данных всех блоков IDAT.
11.2.4 Данные изображения IDAT

Повторное подключение цикла кСначала соберите все исправления IDAT.Только при обнаружении чанка IEND эти данные распаковываются, меняются байты и создается новый чанк IDAT.Последний шаг, добавление IEND, закрывает файл.

from struct import *
from zlib import *
import stat
import sys
import os
import zlib

def getNormalizedPNG(filename):
    pngheader = b"\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)
    chunkD = bytearray()

    foundCGBi = False

    # For each chunk in the PNG file
    while chunkPos < len(oldPNG):

        # 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 == b"IHDR":
            width = unpack(">L", chunkData[0:4])[0]
            height = unpack(">L", chunkData[4:8])[0]

        # Parsing the image chunk
        if chunkType == b"IDAT":
            # Concatename all image data chunks
            chunkD += chunkData
            continue

        # Stopping the PNG file parsing
        if chunkType == b"IEND":
            if not foundCGBi:
                print ('Already normalized')
                return None

            bufSize = width * height * 4 + height
            chunkData = decompress(chunkD, -8, bufSize)

            # Swapping red & blue bytes for each pixel
            chunkData = bytearray(chunkData)
            offset = 1
            for y in range(height):
                for x in range(width):
                    chunkData[offset+4*x],chunkData[offset+4*x+2] = chunkData[offset+4*x+2],chunkData[offset+4*x]
                offset += 1+4*width

            # Compressing the image chunk
            #chunkData = newdata
            chunkData = compress( chunkData )
            chunkLength = len( chunkData )
            chunkCRC = crc32(b'IDAT')
            chunkCRC = crc32(chunkData, chunkCRC)
            chunkCRC = (chunkCRC + 0x100000000) % 0x100000000

            newPNG += pack(">L", chunkLength)
            newPNG += b'IDAT'
            newPNG += chunkData
            newPNG += pack(">L", chunkCRC)

            chunkCRC = crc32(chunkType)
            newPNG += pack(">L", 0)
            newPNG += b'IEND'
            newPNG += pack(">L", chunkCRC)
            break

        # Removing CgBI chunk
        if chunkType == b"CgBI":
            foundCGBi = True
        else:
            newPNG += pack(">L", chunkLength)
            newPNG += chunkType
            if chunkLength > 0:
                newPNG += chunkData
            newPNG += pack(">L", chunkCRC)

    return newPNG


def updatePNG(filename):
    data = getNormalizedPNG(filename)

    if data != None:
        file = open(filename+'_fixed.png', "wb")
        file.write(data)
        file.close()
        return True
    return data

updatePNG("broken_image.png")

, что приводит к правильному исправленному файлу.

Этот код не восстанавливает поврежденный файлCgBI альфа-канал!Если вам нужна правильная альфа-прозрачность, вам нужно применить фильтры строк, чтобы получить прямые значения RGB, инвертировать альфа, а затем применить инверсию фильтров строк перед повторным сжатием.

Вы можете использовать Оболочка Python для PNGDefry , которая является программой на C, которая действительно выполняет эти пропущенные шаги.

Отказ от ответственности: я пишу PNGdefry.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...