private byte[] ReadChunkType(PngChunk chunk) { byte[] typeBuffer = new byte[4]; int numBytes = _stream.Read(typeBuffer, 0, 4); if (numBytes >= 1 && numBytes <= 3) { throw new ImageFormatException("Image stream is not valid!"); } char[] chars = new char[4]; chars[0] = (char)typeBuffer[0]; chars[1] = (char)typeBuffer[1]; chars[2] = (char)typeBuffer[2]; chars[3] = (char)typeBuffer[3]; chunk.Type = new string(chars); return(typeBuffer); }
public Image Decode(Stream stream) { _stream = stream; _stream.Seek(8, SeekOrigin.Current); bool isEndChunckReached = false; PngChunk currentChunk = null; byte[] palette = null; byte[] paletteAlpha = null; using (MemoryStream dataStream = new MemoryStream()) { while ((currentChunk = ReadChunk()) != null) { if (isEndChunckReached) { throw new ImageFormatException("Image does not end with end chunk."); } if (currentChunk.Type == PngChunkTypes.Header) { ReadHeaderChunk(currentChunk.Data); ValidateHeader(); } else if (currentChunk.Type == PngChunkTypes.Data) { dataStream.Write(currentChunk.Data, 0, currentChunk.Data.Length); } else if (currentChunk.Type == PngChunkTypes.Palette) { palette = currentChunk.Data; } else if (currentChunk.Type == PngChunkTypes.PaletteAlpha) { paletteAlpha = currentChunk.Data; } else if (currentChunk.Type == PngChunkTypes.End) { isEndChunckReached = true; } } if (_header.Width > Image.MaxWidth || _header.Height > Image.MaxHeight) { throw new ArgumentOutOfRangeException( $"The input png '{ _header.Width }x{ _header.Height }' is bigger then the max allowed size '{ Image.MaxWidth }x{ Image.MaxHeight }'"); } byte[] pixels = new byte[_header.Width * _header.Height * 4]; PngColorTypeInformation colorTypeInformation = _colorTypes[_header.ColorType]; if (colorTypeInformation != null) { IColorReader colorReader = colorTypeInformation.CreateColorReader(palette, paletteAlpha); ReadScanlines(dataStream, pixels, colorReader, colorTypeInformation); } return(new Image(_header.Width, _header.Height, pixels)); } }
private int ReadChunkLength(PngChunk chunk) { byte[] lengthBuffer = new byte[4]; int numBytes = _stream.Read(lengthBuffer, 0, 4); if (numBytes >= 1 && numBytes <= 3) { throw new ImageFormatException("Image stream is not valid!"); } Array.Reverse(lengthBuffer); chunk.Length = BitConverter.ToInt32(lengthBuffer, 0); return numBytes; }
private byte[] ReadChunkType(PngChunk chunk) { byte[] typeBuffer = new byte[4]; int numBytes = _stream.Read(typeBuffer, 0, 4); if (numBytes >= 1 && numBytes <= 3) { throw new ImageFormatException("Image stream is not valid!"); } char[] chars = new char[4]; chars[0] = (char)typeBuffer[0]; chars[1] = (char)typeBuffer[1]; chars[2] = (char)typeBuffer[2]; chars[3] = (char)typeBuffer[3]; chunk.Type = new string(chars); return typeBuffer; }
private void ReadChunkData(PngChunk chunk) { if (chunk.Length > MaxChunkSize) { throw new ArgumentOutOfRangeException($"Png chunk size '{ chunk.Length }' excceeds the '{ MaxChunkSize }'"); } chunk.Data = new byte[chunk.Length]; _stream.Read(chunk.Data, 0, chunk.Length); }
private void ReadChunkCrc(PngChunk chunk, byte[] typeBuffer) { byte[] crcBuffer = new byte[4]; int numBytes = _stream.Read(crcBuffer, 0, 4); if (numBytes >= 1 && numBytes <= 3) { throw new ImageFormatException("Image stream is not valid!"); } Array.Reverse(crcBuffer); chunk.Crc = BitConverter.ToUInt32(crcBuffer, 0); Crc32 crc = new Crc32(); crc.Update(typeBuffer); crc.Update(chunk.Data); if (crc.Value != chunk.Crc) { throw new ImageFormatException("CRC Error. PNG Image chunk is corrupt!"); } }
private PngChunk ReadChunk() { PngChunk chunk = new PngChunk(); if (ReadChunkLength(chunk) == 0) { return null; } byte[] typeBuffer = ReadChunkType(chunk); ReadChunkData(chunk); ReadChunkCrc(chunk, typeBuffer); return chunk; }