/// <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"></param> /// <param name="previousScanline"></param> /// <param name="bytesPerPixel"></param> /// <returns></returns> private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, int bytesPerPixel) { var candidates = new List <Tuple <byte[], int> >(); var sub = SubFilter.Encode(rawScanline, bytesPerPixel); candidates.Add(new Tuple <byte[], int>(sub, CalculateTotalVariation(sub))); var up = UpFilter.Encode(rawScanline, previousScanline); candidates.Add(new Tuple <byte[], int>(up, CalculateTotalVariation(up))); var average = AverageFilter.Encode(rawScanline, previousScanline, bytesPerPixel); candidates.Add(new Tuple <byte[], int>(average, CalculateTotalVariation(average))); var paeth = PaethFilter.Encode(rawScanline, previousScanline, bytesPerPixel); candidates.Add(new Tuple <byte[], int>(paeth, CalculateTotalVariation(paeth))); int lowestTotalVariation = Int32.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); }
private void DecodePixelData(byte[][] pixelData) { data = new Color[width * height]; byte[] previousScanline = new byte[bytesPerScanline]; for (int y = 0; y < height; y++) { var scanline = pixelData[y]; 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 Exception("Unknown filter type."); } previousScanline = defilteredScanline; ProcessDefilteredScanline(defilteredScanline, y); } }