static PNG_Chunk[] ReadChunks(MemoryStream data) { List <PNG_Chunk> chunkList = new List <PNG_Chunk>(); if (ReadInt64LE(data) != PNG_Header) { return(chunkList.ToArray()); } int i = 0; do { PNG_Chunk chunk = new PNG_Chunk(); int length = ReadInt32BE(data); chunk.Name = ReadString4(data); chunk.Data = ReadData(data, length); chunk.CRC = ReadUInt32BE(data); chunkList.Add(chunk); if (chunk.Name.Equals(PNG_EndChunk)) { break; } } while (i++ < MAX_CHUNKS); return(chunkList.ToArray()); }
static PNG_Chunk[] ProcessChunks(PNG_Chunk[] chunks) { List <PNG_Chunk> result = new List <PNG_Chunk>(); PNG_IHDR header = new PNG_IHDR(); using (MemoryStream rawData = new MemoryStream()) { foreach (PNG_Chunk chunk in chunks) { if (chunk.Name.Equals(PNG_CgBIChunk)) { continue; } if (chunk.Name.Equals(PNG_HeaderChunk)) { header = PNG_IHDR.FromBytes(chunk.Data); } if (chunk.Name.Equals(PNG_DataChunk)) { rawData.Write(chunk.Data, 0, chunk.Data.Length); continue; } if (chunk.Name.Equals(PNG_EndChunk)) { const int dataChunkSize = 16 * 1024; rawData.Position = 0; using (MemoryStream buffer = new MemoryStream()) { using (InflaterInputStream inflate = new InflaterInputStream(rawData, new Inflater(true))) { inflate.IsStreamOwner = false; IPATools.Utilities.Utils.CopyStream(inflate, buffer); //inflate.CopyTo(buffer); } buffer.Position = 0; rawData.SetLength(0); IPATools.Utilities.Utils.CopyStream(buffer, rawData); //buffer.CopyTo(rawData); } { byte[] imageData = rawData.GetBuffer(); int scanlineSize = header.Width * 4 + 1; int scanlinePos = 0; int bpp = 4; for (int y = 0; y < header.Height; ++y, scanlinePos += scanlineSize) { PNG_Filter filter = (PNG_Filter)imageData[scanlinePos]; switch (filter) { case PNG_Filter.Sub: for (int x = 1 + bpp; x < scanlineSize; ++x) { imageData[scanlinePos + x] = (byte)((int)imageData[scanlinePos + x] + (int)imageData[scanlinePos + x - bpp]); } break; case PNG_Filter.Up: if (y > 0) { for (int x = 1; x < scanlineSize; ++x) { imageData[scanlinePos + x] = (byte)((int)imageData[scanlinePos + x] + (int)imageData[scanlinePos + x - bpp - scanlineSize]); } } break; case PNG_Filter.Average: if (y > 0) { for (int x = 1 + bpp; x < scanlineSize; ++x) { imageData[scanlinePos + x] = (byte) (((int)imageData[scanlinePos + x - bpp] + (int)imageData[scanlinePos + x - bpp - scanlineSize]) >> 1); } } break; case PNG_Filter.Paeth: if (y > 0) { for (int x = 1 + bpp; x < scanlineSize; ++x) { imageData[scanlinePos + x] = (byte)FilterPaethPredictor( imageData[scanlinePos + x - bpp], imageData[scanlinePos + x - bpp - scanlineSize], imageData[scanlinePos + x - scanlineSize]); } } break; } for (int x = 0; x < header.Width; ++x) { byte r = imageData[scanlinePos + x * 4 + 1]; byte g = imageData[scanlinePos + x * 4 + 2]; byte b = imageData[scanlinePos + x * 4 + 3]; byte a = imageData[scanlinePos + x * 4 + 4]; if (a > 0) { r = (byte)(255 * r / a); g = (byte)(255 * g / a); b = (byte)(255 * b / a); } imageData[scanlinePos + x * 4 + 1] = b; imageData[scanlinePos + x * 4 + 2] = g; imageData[scanlinePos + x * 4 + 3] = r; imageData[scanlinePos + x * 4 + 4] = a; } imageData[scanlinePos] = (byte)PNG_Filter.None; //imageData[scanlinePos] = (byte)PNG_Filter.Sub; //for (int x = 1 + bpp; x < scanlineSize; ++x) //{ // byte c = imageData[scanlinePos + x]; // byte l = imageData[scanlinePos + x - bpp]; // imageData[scanlinePos + x] = (byte)(l - c); //} } } Deflater deflater = new Deflater(9); Crc32 crc32 = new Crc32(); rawData.Position = 0; long dataLeft = rawData.Length; while (dataLeft > 0) { byte[] chunkData = new byte[dataChunkSize]; int dataInChunk = rawData.Read(chunkData, 0, dataChunkSize); dataLeft -= dataInChunk; byte[] deflatedChunkData = new byte[dataChunkSize]; deflater.SetInput(chunkData, 0, dataInChunk); if (dataLeft > 0) { deflater.Flush(); } else { deflater.Finish(); } int deflatedBytes = deflater.Deflate(deflatedChunkData, 0, dataInChunk); PNG_Chunk dataChunk = new PNG_Chunk(); dataChunk.Name = PNG_DataChunk; dataChunk.Data = new byte[deflatedBytes]; for (int i = 0; i < deflatedBytes; ++i) { dataChunk.Data[i] = deflatedChunkData[i]; } crc32.Reset(); crc32.Update(ASCIIEncoding.ASCII.GetBytes(dataChunk.Name)); crc32.Update(dataChunk.Data); dataChunk.CRC = (uint)crc32.Value; result.Add(dataChunk); } } result.Add(chunk); } } return(result.ToArray()); }