Ejemplo n.º 1
0
        /// <summary>
        /// Encodes the image to the specified stream from the <see cref="Image{TPixel}"/>.
        /// </summary>
        /// <typeparam name="TPixel">The pixel format.</typeparam>
        /// <param name="image">The <see cref="Image{TPixel}"/> to encode from.</param>
        /// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
        public void Encode <TPixel>(Image <TPixel> image, Stream stream)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            int         width  = image.Width;
            int         height = image.Height;
            Span <byte> y      = this.Y.GetSpan();
            Span <byte> u      = this.U.GetSpan();
            Span <byte> v      = this.V.GetSpan();

            YuvConversion.ConvertRgbToYuv(image, this.configuration, this.memoryAllocator, y, u, v);

            int yStride  = width;
            int uvStride = (yStride + 1) >> 1;

            var it = new Vp8EncIterator(this.YTop, this.UvTop, this.Nz, this.MbInfo, this.Preds, this.TopDerr, this.Mbw, this.Mbh);

            int[] alphas = new int[WebpConstants.MaxAlpha + 1];
            this.alpha = this.MacroBlockAnalysis(width, height, it, y, u, v, yStride, uvStride, alphas, out this.uvAlpha);
            int totalMb = this.Mbw * this.Mbw;

            this.alpha   /= totalMb;
            this.uvAlpha /= totalMb;

            // Analysis is done, proceed to actual encoding.
            this.SegmentHeader = new Vp8EncSegmentHeader(4);
            this.AssignSegments(alphas);
            this.SetLoopParams(this.quality);

            // Initialize the bitwriter.
            int averageBytesPerMacroBlock = this.averageBytesPerMb[this.BaseQuant >> 4];
            int expectedSize = this.Mbw * this.Mbh * averageBytesPerMacroBlock;

            this.bitWriter = new Vp8BitWriter(expectedSize, this);

            // TODO: EncodeAlpha();
            bool hasAlpha = false;

            // Stats-collection loop.
            this.StatLoop(width, height, yStride, uvStride);
            it.Init();
            it.InitFilter();
            var info     = new Vp8ModeScore();
            var residual = new Vp8Residual();

            do
            {
                bool dontUseSkip = !this.Proba.UseSkipProba;
                info.Clear();
                it.Import(y, u, v, yStride, uvStride, width, height, false);

                // Warning! order is important: first call VP8Decimate() and
                // *then* decide how to code the skip decision if there's one.
                if (!this.Decimate(it, ref info, this.rdOptLevel) || dontUseSkip)
                {
                    this.CodeResiduals(it, info, residual);
                }
                else
                {
                    it.ResetAfterSkip();
                }

                it.SaveBoundary();
            }while (it.Next());

            // Store filter stats.
            this.AdjustFilterStrength();

            // Write bytes from the bitwriter buffer to the stream.
            image.Metadata.SyncProfiles();
            this.bitWriter.WriteEncodedImageToStream(stream, image.Metadata.ExifProfile, (uint)width, (uint)height, hasAlpha);
        }