/// <summary> /// Decodes per-row delta-encoded and then Deflate-compressed data from a source stream and writes the decoded /// data to a target stream. /// </summary> /// <remarks><paramref name="source"/> must already be at the correct position.</remarks> /// <param name="source">The stream from which to copy the data.</param> /// <param name="dest">The stream to which to copy the data.</param> /// <param name="length"> /// The number of bytes to copy from the source stream, or <c>null</c> to copy all data until the source stream /// ends. /// </param> /// <param name="depth">The depth of the image in bits per pixel color component.</param> /// <param name="imageWidth">The width of the image in pixels.</param> /// <param name="cancelToken"> /// A cancellation token which allows copying to be cancelled before it completes. /// </param> public static void DecodeZipPredicted(Stream source, Stream dest, long?length, int depth, int imageWidth, CancellationToken cancelToken = default(CancellationToken)) { if (depth == 1 || depth == 8) { // no prediction here DecodeZip(source, dest, length, cancelToken); return; } Stream actualSource = length.HasValue ? new PartialStream(source, source.Position, length.Value) : source; // skip zlib header source.ReadBytes(2); var buf = new byte[imageWidth * (depth / 8)]; using (var inflater = new DeflateStream(actualSource, CompressionMode.Decompress, leaveOpen: true)) { for (;;) { try { inflater.ReadBytes(buf); } catch (EndOfStreamException) { break; } if (depth == 16) { DeltaEncoding.DeltaDecodeBigEndian16(buf); dest.Write(buf, 0, buf.Length); } else if (depth == 32) { DeltaEncoding.DeltaDecodeBigEndian32(buf); dest.Write(buf, 0, buf.Length); } cancelToken.ThrowIfCancellationRequested(); } } }
public byte[] GetTrueBytes(FileEntry entry) { if (!entry.IsCompressed) { return(GetRawBytes(entry)); } if (entry.OriginalData != null) { using (var ms = new MemoryStream(entry.OriginalData)) using (var ds = new DeflateStream(ms, CompressionMode.Decompress)) { return(ds.ReadBytes(entry.Length)); } } using (Stream s = GetStream(entry)) using (DeflateStream ds = new DeflateStream(s, CompressionMode.Decompress)) { return(ds.ReadBytes(entry.Length)); } }
public Png(Stream s) { if (!Verify(s)) { throw new InvalidDataException("PNG Signature is bogus"); } s.Position += 8; var headerParsed = false; var data = new List <byte>(); for (;;) { var length = IPAddress.NetworkToHostOrder(s.ReadInt32()); var type = Encoding.UTF8.GetString(s.ReadBytes(4)); var content = s.ReadBytes(length); /*var crc = */ s.ReadInt32(); if (!headerParsed && type != "IHDR") { throw new InvalidDataException("Invalid PNG file - header does not appear first."); } using (var ms = new MemoryStream(content)) { switch (type) { case "IHDR": { if (headerParsed) { throw new InvalidDataException("Invalid PNG file - duplicate header."); } Width = IPAddress.NetworkToHostOrder(ms.ReadInt32()); Height = IPAddress.NetworkToHostOrder(ms.ReadInt32()); Data = new byte[Width * Height]; var bitDepth = ms.ReadUInt8(); var colorType = (PngColorType)ms.ReadByte(); PixelFormat = MakePixelFormat(bitDepth, colorType); var compression = ms.ReadByte(); /*var filter = */ ms.ReadByte(); var interlace = ms.ReadByte(); if (compression != 0) { throw new InvalidDataException("Compression method not supported"); } if (interlace != 0) { throw new InvalidDataException("Interlacing not supported"); } headerParsed = true; break; } case "PLTE": { Palette = new Color[256]; for (var i = 0; i < length / 3; i++) { var r = ms.ReadByte(); var g = ms.ReadByte(); var b = ms.ReadByte(); Palette[i] = Color.FromArgb(r, g, b); } break; } case "tRNS": { if (Palette == null) { throw new InvalidDataException("Non-Palette indexed PNG are not supported."); } for (var i = 0; i < length; i++) { Palette[i] = Color.FromArgb(ms.ReadByte(), Palette[i]); } break; } case "IDAT": { data.AddRange(content); break; } case "tEXt": { var key = ms.ReadASCIIZ(); EmbeddedData.Add(key, ms.ReadASCII(length - key.Length - 1)); break; } case "IEND": { using (var ns = new MemoryStream(data.ToArray())) { // 'zlib' flags bytes; confuses the DeflateStream. /*var flags = (byte)*/ ns.ReadByte(); /*var moreFlags = (byte)*/ ns.ReadByte(); using (var ds = new DeflateStream(ns, CompressionMode.Decompress)) { var prevLine = new byte[Width]; // all zero for (var y = 0; y < Height; y++) { var filter = (PngFilter)ds.ReadByte(); var line = ds.ReadBytes(Width); for (var i = 0; i < Width; i++) { line[i] = i > 0 ? UnapplyFilter(filter, line[i], line[i - 1], prevLine[i], prevLine[i - 1]) : UnapplyFilter(filter, line[i], 0, prevLine[i], 0); } Array.Copy(line, 0, Data, y * Width, line.Length); prevLine = line; } } } if (Palette == null) { throw new InvalidDataException("Non-Palette indexed PNG are not supported."); } return; } } } } }