namespace Uwaa.PNG; internal static class Adam7 { /// /// For a given pass number (1 indexed) the scanline indexes of the lines included in that pass in the 8x8 grid. /// static readonly IReadOnlyDictionary PassToScanlineGridIndex = new Dictionary { { 1, [ 0 ] }, { 2, [ 0 ] }, { 3, [ 4 ] }, { 4, [ 0, 4 ] }, { 5, [ 2, 6 ] }, { 6, [ 0, 2, 4, 6 ] }, { 7, [ 1, 3, 5, 7 ] } }; static readonly IReadOnlyDictionary PassToScanlineColumnIndex = new Dictionary { { 1, [ 0 ] }, { 2, [ 4 ] }, { 3, [ 0, 4 ] }, { 4, [ 2, 6 ] }, { 5, [ 0, 2, 4, 6 ] }, { 6, [ 1, 3, 5, 7 ] }, { 7, [ 0, 1, 2, 3, 4, 5, 6, 7 ] } }; /* * To go from raw image data to interlaced: * * An 8x8 grid is repeated over the image. There are 7 passes and the indexes in this grid correspond to the * pass number including that pixel. Each row in the grid corresponds to a scanline. * * 1 6 4 6 2 6 4 6 - Scanline 0: pass 1 has pixel 0, 8, 16, etc. pass 2 has pixel 4, 12, 20, etc. * 7 7 7 7 7 7 7 7 * 5 6 5 6 5 6 5 6 * 7 7 7 7 7 7 7 7 * 3 6 4 6 3 6 4 6 * 7 7 7 7 7 7 7 7 * 5 6 5 6 5 6 5 6 * 7 7 7 7 7 7 7 7 * * * */ public static int GetNumberOfScanlinesInPass(ImageHeader header, int pass) { int[] indices = PassToScanlineGridIndex[pass + 1]; int mod = header.Height % 8; if (mod == 0) //fits exactly return indices.Length * (header.Height / 8); int additionalLines = 0; for (int i = 0; i < indices.Length; i++) if (indices[i] < mod) additionalLines++; return (indices.Length * (header.Height / 8)) + additionalLines; } public static int GetPixelsPerScanlineInPass(ImageHeader header, int pass) { int[] indices = PassToScanlineColumnIndex[pass + 1]; int mod = header.Width % 8; if (mod == 0) //fits exactly return indices.Length * (header.Width / 8); int additionalColumns = 0; for (int i = 0; i < indices.Length; i++) if (indices[i] < mod) additionalColumns++; return (indices.Length * (header.Width / 8)) + additionalColumns; } public static (int x, int y) GetPixelIndexForScanlineInPass(int pass, int scanlineIndex, int indexInScanline) { int[] columnIndices = PassToScanlineColumnIndex[pass + 1]; int[] rows = PassToScanlineGridIndex[pass + 1]; int actualRow = scanlineIndex % rows.Length; int actualCol = indexInScanline % columnIndices.Length; int precedingRows = 8 * (scanlineIndex / rows.Length); int precedingCols = 8 * (indexInScanline / columnIndices.Length); return (precedingCols + columnIndices[actualCol], precedingRows + rows[actualRow]); } }