/// <summary> /// Creates an FDAT Chunk from an IDAT Chunk. /// </summary> /// <returns>The FDAT chunk.</returns> /// <param name="idatChunk">IDAT chunk.</param> /// <param name="sequenceNumber">Sequence number.</param> public static fdATChunk FromIDATChunk(IDATChunk idatChunk, uint sequenceNumber) { uint newCrc; byte[] frameData; fdATChunk fdat = null; using (var msCrc = new MemoryStream()) { msCrc.WriteBytes(new[] { (byte)'f', (byte)'d', (byte)'A', (byte)'T' }); byte[] seqNum = BitConverter.GetBytes(Helper.ConvertEndian(sequenceNumber)); frameData = new byte[seqNum.Length + idatChunk.ChunkData.Length]; Buffer.BlockCopy(seqNum, 0, frameData, 0, seqNum.Length); Buffer.BlockCopy(idatChunk.ChunkData, 0, frameData, seqNum.Length, idatChunk.ChunkData.Length); msCrc.WriteBytes(frameData); newCrc = CrcHelper.Calculate(msCrc.ToArray()); } using (var ms = new MemoryStream()) { ms.WriteUInt32((uint)Helper.ConvertEndian(idatChunk.ChunkData.Length + 4)); ms.WriteBytes(new[] { (byte)'f', (byte)'d', (byte)'A', (byte)'T' }); ms.WriteBytes(frameData); ms.WriteUInt32(Helper.ConvertEndian(newCrc)); ms.Position = 0; fdat = new fdATChunk(ms); } return(fdat); }
/// <summary> /// Save the APNG to file. /// </summary> /// <param name="filename">The filename to output to.</param> public void Save(string filename) { using (BinaryWriter writer = new BinaryWriter(new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write))) { int frameWriteStartIndex = 0; //Write signature writer.Write(Frame.Signature); //Write header writer.Write(this.IHDRChunk.RawData); //If acTL exists if (acTLChunk != null) { //write actl. writer.Write(acTLChunk.RawData); } //Write all other chunks. (NOTE: These should be consistently the same for all frames) foreach (OtherChunk otherChunk in defaultImage.OtherChunks) { writer.Write(otherChunk.RawData); } uint sequenceNumber = 0; //If Default Image is not animated if (!DefaultImageIsAnimated) { //write IDAT defaultImage.IDATChunks.ForEach(i => writer.Write(i.RawData)); } else { frames[0].fcTLChunk.SequenceNumber = sequenceNumber++; //Write fcTL writer.Write(frames[0].fcTLChunk.RawData); //Write IDAT of first frame. frames[0].IDATChunks.ForEach(i => writer.Write(i.RawData)); //Set start frame indes to 1 frameWriteStartIndex = 1; } //Foreach frame for (int i = frameWriteStartIndex; i < frames.Count; ++i) { frames[i].fcTLChunk.SequenceNumber = sequenceNumber++; //write fcTL writer.Write(frames[i].fcTLChunk.RawData); //Write fDAT for (int j = 0; j < frames[i].IDATChunks.Count; ++j) { fdATChunk fdat = fdATChunk.FromIDATChunk(frames[i].IDATChunks[j], sequenceNumber++); writer.Write(fdat.RawData); } } //Write IEnd writer.Write(defaultImage.IENDChunk.RawData); writer.Close(); } }