Pergunta

Eu estou trabalhando em uma solução para minha outra pergunta que está lendo o dados nos pedaços 'zTXt' de um PNG. Estou tão longe como localizar os pedaços no arquivo, e leitura de palavras-chave do zTXt. Estou tendo problemas para ler a porção comprimida de zTXt. Eu nunca trabalhei com o objeto DeflateStream antes, e estou tendo alguns problemas com ele. Ao ler, parece que esperar o parâmetro de comprimento para estar em bytes 'descompactado'. No meu caso no entanto, só sei o comprimento dos dados em 'comprimido' bytes. Para esperamos contornar esta situação, eu coloquei todos os dados que precisavam ser descompactado em um MemoryStream e, em seguida, 'ler para acabar' com um DeflateStream. Agora isso é apenas peachy, exceto ele lança uma InvalidDataException com a mensagem "Bloco de comprimento não coincide com o seu complemento." Agora eu não tenho idéia o que isso significa. O que poderia estar acontecendo de errado?

O formato de um pedaço é de 4 bytes para o ID ( "zTXt"), um int de 32 bits big-endian para o comprimento de dados, os dados e, finalmente, um checksum CRC32 que estou ignorando por agora.

O formato do pedaço zTXt é o primeiro de uma terminada em nulo (string como palavra-chave), então um byte para o método de compressão (sempre 0, o método DEFLATE), com o resto dos dados sendo compactados texto.

Meu método leva em um FileStream fresco, e retorna um dicionário com as palavras-chave e dados zTXt.

Aqui está o monstro agora:

public static List<KeyValuePair<string, string>> GetZtxt(FileStream stream)
{
    var ret = new List<KeyValuePair<string, string>>();
    try {
        stream.Position = 0;
        var br = new BinaryReader(stream, Encoding.ASCII);
        var head = br.ReadBytes(8); // The header is the same for all PNGs.
        if (!head.SequenceEqual(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A })) return null; // Not a PNG.
        while (stream.Position < stream.Length) {
            int len; // Length of chunk data.
            if (BitConverter.IsLittleEndian)
                len = BitConverter.ToInt32(br.ReadBytes(4).Reverse().ToArray(), 0);
            else
                len = br.ReadInt32();

            char[] cName = br.ReadChars(4); // The chunk type.
            if (cName.SequenceEqual(new[] { 'z', 'T', 'X', 't' })) {
                var sb = new StringBuilder(); // Builds the null-terminated keyword associated with the chunk.
                char c = br.ReadChar();
                do {
                    sb.Append(c);
                    c = br.ReadChar();
                }
                while (c != '\0');
                byte method = br.ReadByte(); // The compression method.  Should always be 0. (DEFLATE method.)
                if (method != 0) {
                    stream.Seek(len - sb.Length + 3, SeekOrigin.Current); // If not 0, skip the rest of the chunk.
                    continue;
                }
                var data = br.ReadBytes(len - sb.Length - 1); // Rest of the chunk data...
                var ms = new MemoryStream(data, 0, data.Length); // ...in a MemoryStream...
                var ds = new DeflateStream(ms, CompressionMode.Decompress); // ...read by a DeflateStream...
                var sr = new StreamReader(ds); // ... and a StreamReader.  Yeesh.
                var str = sr.ReadToEnd(); // !!! InvalidDataException !!!
                ret.Add(new KeyValuePair<string, string>(sb.ToString(), str));
                stream.Seek(4, SeekOrigin.Current); // Skip the CRC check.
            }
            else {
                stream.Seek(len + 4, SeekOrigin.Current); // Skip the rest of the chunk.
            }
        }
    }
    catch (IOException) { }
    catch (InvalidDataException) { }
    catch (ArgumentOutOfRangeException) { }
    return ret;
}

Uma vez que este é abordado, eu vou ter de escrever uma função que adiciona esses pedaços zTXt para o arquivo. Então espero que eu vou entender como o DeflateStream funciona quando isso for resolvido.

Obrigado, muito !!

Foi útil?

Solução

Depois de todo esse tempo, eu finalmente encontrei o problema. Os dados estão no formato zlib, que tem um pouco mais dados armazenados do que apenas usando DEFLATE sozinho. O arquivo é lido corretamente, se eu apenas ler os 2 bytes extra no direito antes de eu chegar os dados comprimidos.

desta página comentários . (Eu não consideram que um.)

Eu estou querendo saber agora. O valor destes dois bytes são 0x78 e 0x9C respectivamente. Se eu achar que não os valores, eu deveria assumir o DEFLATE vai falhar?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top