/// <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="bytesPerScanline">The number of bytes per scanline</param> /// <param name="bytesPerPixel">The number of bytes per pixel</param> /// <returns>The <see cref="T:byte[]"/></returns> private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel) { Tuple <byte[], int>[] candidates = new Tuple <byte[], int> [4]; byte[] sub = SubFilter.Encode(rawScanline, bytesPerPixel, bytesPerScanline); candidates[0] = new Tuple <byte[], int>(sub, this.CalculateTotalVariation(sub)); byte[] up = UpFilter.Encode(rawScanline, bytesPerScanline, previousScanline); candidates[1] = new Tuple <byte[], int>(up, this.CalculateTotalVariation(up)); byte[] average = AverageFilter.Encode(rawScanline, previousScanline, bytesPerPixel, bytesPerScanline); candidates[2] = new Tuple <byte[], int>(average, this.CalculateTotalVariation(average)); byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, bytesPerPixel, bytesPerScanline); candidates[3] = new Tuple <byte[], int>(paeth, this.CalculateTotalVariation(paeth)); int lowestTotalVariation = int.MaxValue; int lowestTotalVariationIndex = 0; for (int i = 0; i < 4; i++) { if (candidates[i].Item2 < lowestTotalVariation) { lowestTotalVariationIndex = i; lowestTotalVariation = candidates[i].Item2; } } return(candidates[lowestTotalVariationIndex].Item1); }
/// <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> /// <returns>The <see cref="T:byte[]"/></returns> private Buffer <byte> GetOptimalFilteredScanline() { Span <byte> scanSpan = this.rawScanline.Span; Span <byte> prevSpan = this.previousScanline.Span; // Palette images don't compress well with adaptive filtering. if (this.pngColorType == PngColorType.Palette || this.bitDepth < 8) { NoneFilter.Encode(this.rawScanline, this.result); return(this.result); } // This order, while different to the enumerated order is more likely to produce a smaller sum // early on which shaves a couple of milliseconds off the processing time. UpFilter.Encode(scanSpan, prevSpan, this.up); int currentSum = this.CalculateTotalVariation(this.up, int.MaxValue); int lowestSum = currentSum; Buffer <byte> actualResult = this.up; PaethFilter.Encode(scanSpan, prevSpan, this.paeth, this.bytesPerPixel); currentSum = this.CalculateTotalVariation(this.paeth, currentSum); if (currentSum < lowestSum) { lowestSum = currentSum; actualResult = this.paeth; } SubFilter.Encode(scanSpan, this.sub, this.bytesPerPixel); currentSum = this.CalculateTotalVariation(this.sub, int.MaxValue); if (currentSum < lowestSum) { lowestSum = currentSum; actualResult = this.sub; } AverageFilter.Encode(scanSpan, prevSpan, this.average, this.bytesPerPixel); currentSum = this.CalculateTotalVariation(this.average, currentSum); if (currentSum < lowestSum) { actualResult = this.average; } return(actualResult); }
/// <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="result">The filtered scanline result.</param> /// <returns>The <see cref="T:byte[]"/></returns> private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, byte[] result) { // Palette images don't compress well with adaptive filtering. if (this.PngColorType == PngColorType.Palette) { NoneFilter.Encode(rawScanline, result); return(result); } SubFilter.Encode(rawScanline, this.sub, this.bytesPerPixel); int currentTotalVariation = this.CalculateTotalVariation(this.sub); int lowestTotalVariation = currentTotalVariation; result = this.sub; UpFilter.Encode(rawScanline, previousScanline, this.up); currentTotalVariation = this.CalculateTotalVariation(this.up); if (currentTotalVariation < lowestTotalVariation) { lowestTotalVariation = currentTotalVariation; result = this.up; } AverageFilter.Encode(rawScanline, previousScanline, this.average, this.bytesPerPixel); currentTotalVariation = this.CalculateTotalVariation(this.average); if (currentTotalVariation < lowestTotalVariation) { lowestTotalVariation = currentTotalVariation; result = this.average; } PaethFilter.Encode(rawScanline, previousScanline, this.paeth, this.bytesPerPixel); currentTotalVariation = this.CalculateTotalVariation(this.paeth); if (currentTotalVariation < lowestTotalVariation) { result = this.paeth; } return(result); }
/// <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="result">The filtered scanline result</param> /// <param name="bytesPerScanline">The number of bytes per scanline</param> private void GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, byte[] result, int bytesPerScanline) { // Palette images don't compress well with adaptive filtering. if (this.PngColorType == PngColorType.Palette) { NoneFilter.Encode(rawScanline, result, bytesPerScanline); return; } Tuple <byte[], int>[] candidates = new Tuple <byte[], int> [4]; byte[] sub = SubFilter.Encode(rawScanline, this.bytesPerPixel, bytesPerScanline); candidates[0] = new Tuple <byte[], int>(sub, this.CalculateTotalVariation(sub)); byte[] up = UpFilter.Encode(rawScanline, previousScanline, result, bytesPerScanline); candidates[1] = new Tuple <byte[], int>(up, this.CalculateTotalVariation(up)); byte[] average = AverageFilter.Encode(rawScanline, previousScanline, result, this.bytesPerPixel, bytesPerScanline); candidates[2] = new Tuple <byte[], int>(average, this.CalculateTotalVariation(average)); byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, result, this.bytesPerPixel, bytesPerScanline); candidates[3] = new Tuple <byte[], int>(paeth, this.CalculateTotalVariation(paeth)); int lowestTotalVariation = int.MaxValue; int lowestTotalVariationIndex = 0; for (int i = 0; i < candidates.Length; i++) { if (candidates[i].Item2 < lowestTotalVariation) { lowestTotalVariationIndex = i; lowestTotalVariation = candidates[i].Item2; } } // ReSharper disable once RedundantAssignment result = candidates[lowestTotalVariationIndex].Item1; }
/// <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>The <see cref="T:byte[]"/></returns> private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, int byteCount) { List <Tuple <byte[], int> > candidates = new List <Tuple <byte[], int> >(); if (this.PngColorType == PngColorType.Palette) { byte[] none = NoneFilter.Encode(rawScanline); candidates.Add(new Tuple <byte[], int>(none, this.CalculateTotalVariation(none))); } else { byte[] sub = SubFilter.Encode(rawScanline, byteCount); candidates.Add(new Tuple <byte[], int>(sub, this.CalculateTotalVariation(sub))); byte[] up = UpFilter.Encode(rawScanline, previousScanline); candidates.Add(new Tuple <byte[], int>(up, this.CalculateTotalVariation(up))); byte[] average = AverageFilter.Encode(rawScanline, previousScanline, byteCount); candidates.Add(new Tuple <byte[], int>(average, this.CalculateTotalVariation(average))); byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, byteCount); candidates.Add(new Tuple <byte[], int>(paeth, this.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); }