private int CalculateScanlineStep(PngColorTypeInformation colorTypeInformation) { int scanlineStep = 1; if (header.BitDepth >= 8) { scanlineStep = (colorTypeInformation.ChannelsPerColor * header.BitDepth) / 8; } return(scanlineStep); }
private int CalculateScanlineLength(PngColorTypeInformation colorTypeInformation) { int scanlineLength = header.Width * header.BitDepth * colorTypeInformation.ChannelsPerColor; int amount = scanlineLength % 8; if (amount != 0) { scanlineLength += 8 - amount; } return(scanlineLength / 8); }
public void Decode(Image2 image, Stream stream) { Image2 currentImage = image; currentStream = stream; currentStream.Seek(8, SeekOrigin.Current); bool isEndChunkReached = false; byte[] palette = null; byte[] paletteAlpha = null; using (MemoryStream dataStream = new MemoryStream()){ PngChunk currentChunk; while ((currentChunk = ReadChunk()) != null) { if (isEndChunkReached) { throw new Exception("Image does not end with end chunk."); } if (currentChunk.Type == PngChunkTypes.Header) { ReadHeaderChunk(currentChunk.Data); ValidateHeader(); } else if (currentChunk.Type == PngChunkTypes.Physical) { ReadPhysicalChunk(currentImage, currentChunk.Data); } 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.Text) { ReadTextChunk(currentImage, currentChunk.Data); } else if (currentChunk.Type == PngChunkTypes.End) { isEndChunkReached = true; } } if (header.Width > image.MaxWidth || header.Height > image.MaxHeight) { throw new ArgumentOutOfRangeException($"The input png '{header.Width}x{header.Height}' is bigger than the " + $"max allowed size '{image.MaxWidth}x{image.MaxHeight}'"); } Color2[] pixels = new Color2[header.Width * header.Height]; PngColorTypeInformation colorTypeInformation = colorTypes[header.ColorType]; if (colorTypeInformation != null) { IColorReader colorReader = colorTypeInformation.CreateColorReader(palette, paletteAlpha); ReadScanlines(dataStream, pixels, colorReader, colorTypeInformation); } image.SetPixels(header.Width, header.Height, pixels); } }
private void ReadScanlines(MemoryStream dataStream, Color2[] pixels, IColorReader colorReader, PngColorTypeInformation colorTypeInformation) { dataStream.Position = 0; int scanlineLength = CalculateScanlineLength(colorTypeInformation); int scanlineStep = CalculateScanlineStep(colorTypeInformation); byte[] lastScanline = new byte[scanlineLength]; byte[] currentScanline = new byte[scanlineLength]; int filter = 0, column = -1; using (ZlibInflateStream compressedStream = new ZlibInflateStream(dataStream)){ int readByte; while ((readByte = compressedStream.ReadByte()) >= 0) { if (column == -1) { filter = readByte; column++; } else { currentScanline[column] = (byte)readByte; byte a; byte c; if (column >= scanlineStep) { a = currentScanline[column - scanlineStep]; c = lastScanline[column - scanlineStep]; } else { a = 0; c = 0; } byte b = lastScanline[column]; if (filter == 1) { currentScanline[column] = (byte)(currentScanline[column] + a); } else if (filter == 2) { currentScanline[column] = (byte)(currentScanline[column] + b); } else if (filter == 3) { currentScanline[column] = (byte)(currentScanline[column] + (byte)((a + b) / 2)); } else if (filter == 4) { currentScanline[column] = (byte)(currentScanline[column] + PaethPredicator(a, b, c)); } column++; if (column == scanlineLength) { colorReader.ReadScanline(currentScanline, pixels, header); column = -1; Swap(ref currentScanline, ref lastScanline); } } } } }