/// <summary> /// Applies all PNG filters to the given scanline and returns the filtered scanline that is deemed /// to be most compressible, using lowest total variation as proxy for compressibility. /// </summary> /// <param name="rawScanline">The raw scanline</param> /// <param name="previousScanline">The previous scanline</param> /// <param name="byteCount">The number of bytes per pixel</param> /// <returns></returns> private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, int byteCount) { List <Tuple <byte[], int> > candidates = new List <Tuple <byte[], int> >(); byte[] sub = SubFilter.Encode(rawScanline, byteCount); candidates.Add(new Tuple <byte[], int>(sub, CalculateTotalVariation(sub))); byte[] up = UpFilter.Encode(rawScanline, previousScanline); candidates.Add(new Tuple <byte[], int>(up, CalculateTotalVariation(up))); byte[] average = AverageFilter.Encode(rawScanline, previousScanline, byteCount); candidates.Add(new Tuple <byte[], int>(average, CalculateTotalVariation(average))); byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, byteCount); candidates.Add(new Tuple <byte[], int>(paeth, CalculateTotalVariation(paeth))); int lowestTotalVariation = int.MaxValue; int lowestTotalVariationIndex = 0; for (int i = 0; i < candidates.Count; i++) { if (candidates[i].Item2 < lowestTotalVariation) { lowestTotalVariationIndex = i; lowestTotalVariation = candidates[i].Item2; } } return(candidates[lowestTotalVariationIndex].Item1); }
/// <summary> /// Decodes the raw pixel data row by row /// </summary> /// <typeparam name="T">The pixel format.</typeparam> /// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam> /// <param name="pixelData">The pixel data.</param> /// <param name="pixels">The image pixels.</param> private void DecodePixelData <T, TP>(byte[] pixelData, T[] pixels) where T : IPackedVector <TP> where TP : struct { byte[] previousScanline = new byte[this.bytesPerScanline]; for (int y = 0; y < this.header.Height; y++) { byte[] scanline = new byte[this.bytesPerScanline]; Array.Copy(pixelData, y * this.bytesPerScanline, scanline, 0, this.bytesPerScanline); FilterType filterType = (FilterType)scanline[0]; byte[] defilteredScanline; switch (filterType) { case FilterType.None: defilteredScanline = NoneFilter.Decode(scanline); break; case FilterType.Sub: defilteredScanline = SubFilter.Decode(scanline, bytesPerPixel); break; case FilterType.Up: defilteredScanline = UpFilter.Decode(scanline, previousScanline); break; case FilterType.Average: defilteredScanline = AverageFilter.Decode(scanline, previousScanline, bytesPerPixel); break; case FilterType.Paeth: defilteredScanline = PaethFilter.Decode(scanline, previousScanline, bytesPerPixel); break; default: throw new ImageFormatException("Unknown filter type."); } previousScanline = defilteredScanline; ProcessDefilteredScanline <T, TP>(defilteredScanline, y, pixels); } }