/// <summary> /// Attempts to read 16 bytes of the stream. /// </summary> internal static ActlChunk Read(Stream stream) { var chunk = new ActlChunk { Length = BitHelper.ConvertEndian(stream.ReadUInt32()), //Chunk length, 4 bytes. ChunkType = Encoding.ASCII.GetString(stream.ReadBytes(4)) //Chunk type, 4 bytes. }; //If the second chunk is not the animation control (acTL), it means that this is a normal PNG. if (chunk.ChunkType != "acTL") { return(null); } //var pos = stream.Position; //chunk.ChunkData = stream.ReadBytes(chunk.Length); //stream.Position = pos; //Chunk details + CRC, 8 bytes + 4 bytes. chunk.NumFrames = BitHelper.ConvertEndian(stream.ReadUInt32()); chunk.NumPlays = BitHelper.ConvertEndian(stream.ReadUInt32()); chunk.Crc = BitHelper.ConvertEndian(stream.ReadUInt32()); return(chunk); }
internal bool ReadFrames() { //Png header, 8 bytes. if (!InternalStream.ReadBytes(8).SequenceEqual(new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 })) { throw new Exception("Invalid file format, expected PNG signature not found."); } //IHDR chunk, 25 bytes. Ihdr = IhdrChunk.Read(InternalStream); //aCTl chunk, 16 bytes. Actl = ActlChunk.Read(InternalStream); //If there's no animation control chunk, it's a normal Png. if (Actl == null) { return(false); } var masterSequence = 0; var frameGroupId = -1; //Read frames. while (InternalStream.CanRead) { //Tries to read any chunk, except IEND. var chunk = Chunk.Read(InternalStream, masterSequence++); //End reached, prematurely or not. if (chunk == null || chunk.ChunkType == "IEND") { break; } //Chunks can be grouped into frames. if (new[] { "fcTL", "fdAT", "IDAT" }.Contains(chunk.ChunkType)) { if (chunk.ChunkType == "fcTL") { frameGroupId++; } chunk.FrameGroupId = frameGroupId; } Chunks.Add(chunk); } return(true); }