Domanda

Sto lavorando su una soluzione mia altra domanda che è la lettura del dati nei pezzi 'zTXt' di un PNG. Sono per quanto riguarda la localizzazione dei pezzi nel file, e la lettura parola chiave del zTXt. Sto avendo difficoltà a leggere la porzione compressa della zTXt. Non ho mai lavorato con l'oggetto DeflateStream prima, e sto avendo qualche problema con esso. Durante la lettura, sembra aspettarsi che il parametro della lunghezza di essere in byte 'non compressi. Nel mio caso però, so solo la lunghezza dei dati in byte 'compressi'. Per ottenere spera intorno a questo, ho messo tutti i dati che doveva essere decompresso in una MemoryStream, e quindi 'leggere per terminare' con un DeflateStream. Ora che è solo peachy, tranne che genera InvalidDataException con il messaggio "Lunghezza blocco non corrisponde con il suo complemento". Ora non ho idea di che cosa questo significa. Che cosa potrebbe andare storto?

Il formato di un pezzo è di 4 byte per l'ID ( "zTXt"), un big-endian a 32 bit int per la lunghezza dei dati, i dati, e, infine, un checksum CRC32 che sto ignorando per ora.

Il formato del blocco zTXt è innanzitutto un terminazione Null (stringa come parola chiave), quindi un byte per il metodo di compressione (sempre 0, il metodo DEFLATE), con il resto dei dati compressi testo.

Il mio metodo prende in un FileStream fresco, e restituisce un dizionario con le parole chiave zTXt e dei dati.

Ecco il mostro ora:

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;
}

Una volta che questo è affrontato, avrò bisogno di scrivere una funzione che consente di aggiungere questi pezzi zTXt al file. Quindi spero di capire come funziona il DeflateStream una volta che questo è risolto.

Grazie, tanto !!

È stato utile?

Soluzione

Dopo tutto questo tempo, ho finalmente trovato il problema. I dati sono in formato zlib, che ha un po 'di più i dati memorizzati non solo utilizzando DEFLATE solo. Il file viene letto correttamente se ho appena letto i 2 byte supplementari destra prima di arrivare i dati compressi.

questa pagina Feedback . (Io non sostengo che uno.)

Mi chiedo ora. Il valore di tali due byte sono 0x78 e 0x9C rispettivamente. Se trovo valori diversi da quelli, dovrei assumere la DEFLATE sta per fallire?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top