public void Load(Stream stream) { chunks = new List <APNGChunk>(); pngs = new List <PNG>(); // Create a new header (should be 1 per file) and // read it from the stream var header = new APNGHeader(); try { header.Read(stream); } catch (Exception) { stream.Close(); throw; } APNGChunk chunk; PNG png = null; // Read chunks from the stream until we reach the MEND chunk do { // Read a generic Chunk chunk = new APNGChunk(); try { chunk.Read(stream); } catch (Exception) { stream.Close(); throw; } // Take a look at the chunk type and decide what derived class to // use to create a specific chunk switch (chunk.ChunkType) { case acTLChunk.NAME: if (headerChunk != null) { throw new ApplicationException(String.Format( "Only one chunk of type {0} is allowed", chunk.ChunkType)); } chunk = headerChunk = new acTLChunk(chunk); break; case MENDChunk.NAME: chunk = new MENDChunk(chunk); break; case TERMChunk.NAME: chunk = new TERMChunk(chunk); break; case BACKChunk.NAME: chunk = new BACKChunk(chunk); break; case BKGDChunk.NAME: chunk = new BKGDChunk(chunk); break; case fcTLChunk.NAME: // This is the beginning of a new embedded PNG chunk = new fcTLChunk(chunk); png = new PNG { FCTL = chunk as fcTLChunk, IHDR = ihdrChunk }; pngs.Add(png); break; case IHDRChunk.NAME: chunk = new IHDRChunk(chunk); ihdrChunk = chunk as IHDRChunk; break; case IDATChunk.NAME: chunk = new IDATChunk(chunk); if (png != null) { png.IDAT = chunk as IDATChunk; } break; case fdATChunk.NAME: chunk = new fdATChunk(chunk); if (png != null) { chunk.ChunkType = IDATChunk.NAME; png.IDAT = new IDATChunk(chunk); } break; case IENDChunk.NAME: chunk = new IENDChunk(chunk); for (var i = 0; i < pngs.Count; i++) { pngs[i].IEND = chunk as IENDChunk; } break; default: break; } // Add the chunk to our list of chunks chunks.Add(chunk); }while (chunk.ChunkType != IENDChunk.NAME); }
/// <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(); }