예제 #1
0
        /// <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);
        }
예제 #2
0
        /// <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);
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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;
        }
예제 #5
0
        /// <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);
        }