private static void ParseInterlaced(byte[] data, PngFileHeader fileHeader, int bytesPerPixel, IColorReader reader, byte[] pixels) { const int passes = 7; var readOffset = 0; var done = false; var r = new Span <byte>(data); for (var i = 0; i < passes; i++) { int columns = Adam7.ComputeColumns(fileHeader.Width, i); if (columns == 0) { continue; } int rowSize = GetScanlineLength(columns, fileHeader) + 1; // Read rows. Span <byte> prevRowData = null; for (int row = Adam7.FirstRow[i]; row < fileHeader.Height; row += Adam7.RowIncrement[i]) { // Early out if invalid pass. if (r.Length - readOffset < rowSize) { done = true; break; } var rowData = new Span <byte>(new byte[rowSize]); r.Slice(readOffset, rowSize).CopyTo(rowData); int filter = rowData[0]; rowData = rowData.Slice(1); readOffset += rowSize; // Apply filter to the whole row. for (var column = 0; column < rowData.Length; column++) { rowData[column] = ApplyFilter(rowData, prevRowData, filter, column, bytesPerPixel); } reader.ReadScanlineInterlaced(rowData, pixels, fileHeader, row, i); prevRowData = rowData; } if (done) { break; } } }
private static byte[] ParseInterlaced(byte[] pureData, PngFileHeader fileHeader, int bytesPerPixel, int channelsPerColor, ColorReader reader) { PerfProfiler.ProfilerEventStart("PNG Parse Interlaced", "Loading"); // Combine interlaced pixels into one image here. var width = (int)fileHeader.Size.X; var height = (int)fileHeader.Size.Y; var combination = new byte[width * height * channelsPerColor]; var pixels = new byte[width * height * 4]; const int passes = 7; var readOffset = 0; var done = false; var data = new Span <byte>(pureData); for (var i = 0; i < passes; i++) { int columns = Adam7.ComputeColumns(width, i); if (columns == 0) { continue; } int scanlineLength = GetScanlineLengthInterlaced(columns, fileHeader, channelsPerColor) + 1; int length = scanlineLength - 1; int pixelsInLine = Adam7.ComputeBlockWidth(width, i); // Read scanlines in this pass. var previousScanline = Span <byte> .Empty; for (int row = Adam7.FirstRow[i]; row < height; row += Adam7.RowIncrement[i]) { // Early out if invalid pass. if (data.Length - readOffset < scanlineLength) { done = true; break; } Span <byte> scanLine = data.Slice(readOffset + 1, length); int filter = data[readOffset]; readOffset += scanlineLength; ApplyFilter(scanLine, previousScanline, filter, bytesPerPixel); // Dump the row into the combined image. Span <byte> convertedLine = ConvertBitArray(scanLine, fileHeader); for (var pixel = 0; pixel < pixelsInLine; pixel++) { int offset = row * bytesPerPixel * width + (Adam7.FirstColumn[i] + pixel * Adam7.ColumnIncrement[i]) * bytesPerPixel; int offsetSrc = pixel * bytesPerPixel; for (var p = 0; p < bytesPerPixel; p++) { combination[offset + p] = convertedLine[offsetSrc + p]; } } previousScanline = scanLine; } if (done) { break; } } // Read the combined image. int stride = width * bytesPerPixel; int scanlineCount = combination.Length / stride; for (var i = 0; i < scanlineCount; i++) { Span <byte> row = new Span <byte>(combination).Slice(stride * i, stride); reader(width, row, pixels, i); } PerfProfiler.ProfilerEventEnd("PNG Parse Interlaced", "Loading"); return(pixels); }