Example #1
0
        /// <summary>Decodes Webp data buffer to <seealso cref="BitmapSource"/>.</summary>
        /// <param name="data">The data buffer which contains WebP image.</param>
        /// <param name="data_size">The size of the data buffer which contains WebP image.</param>
        /// <param name="options">The decoder options for webp decoder.</param>
        /// <returns><seealso cref="BitmapSource"/> which contains the image data.</returns>
        /// <exception cref="WebpDecodeException">Thrown when the decoder has wrong options or the buffer contains invalid data for Webp Image.</exception>
        public BitmapSource Decode(IntPtr data, int data_size, WindowsDecoderOptions options)
        {
            ReadOnlySpan <byte> buffer;

            unsafe
            {
                buffer = new ReadOnlySpan <byte>(data.ToPointer(), data_size);
            }
            var features = new WebPBitstreamFeatures();

            if (this.webp.TryGetImageHeaderInfo(buffer, ref features) == VP8StatusCode.VP8_STATUS_OK)
            {
                var height       = features.height;
                var decidedPxFmt = Helper.DecideOutputPixelFormat(options.PixelFormat, features.has_alpha != 0);
                var wbm          = new WriteableBitmap(features.width, height, 96, 96, Helper.GetPixelFormat(decidedPxFmt), null);
                wbm.Lock();
                try
                {
                    uint inputSize  = Convert.ToUInt32(data_size),
                         outputSize = Convert.ToUInt32(wbm.BackBufferStride * height);
                    this.webp.DecodeRGB(data, new UIntPtr(inputSize), wbm.BackBuffer, new UIntPtr(outputSize), Helper.GetWebpPixelFormat(decidedPxFmt), options);
                }
                finally
                {
                    wbm.Unlock();
                }
                return(wbm);
            }
            else
            {
                throw new WebpDecodeException(VP8StatusCode.VP8_STATUS_BITSTREAM_ERROR);
            }
        }
Example #2
0
 /// <summary>Decodes Webp data buffer to <seealso cref="BitmapSource"/>.</summary>
 /// <param name="data">The data buffer which contains WebP image.</param>
 /// <param name="options">The decoder options for webp decoder.</param>
 /// <returns><seealso cref="BitmapSource"/> which contains the image data.</returns>
 /// <exception cref="WebpDecodeException">Thrown when the decoder has wrong options or the buffer contains invalid data for Webp Image.</exception>
 public BitmapSource Decode(ReadOnlySpan <byte> data, WindowsDecoderOptions options)
 {
     unsafe
     {
         fixed(byte *b = data)
         {
             return(this.Decode(new IntPtr(b), data.Length, options));
         }
     }
 }
Example #3
0
 /// <summary>Decodes Webp data buffer to <seealso cref="BitmapSource"/>.</summary>
 /// <param name="data">The data buffer which contains WebP image.</param>
 /// <param name="options">The decoder options for webp decoder.</param>
 /// <returns><seealso cref="BitmapSource"/> which contains the image data.</returns>
 /// <exception cref="WebpDecodeException">Thrown when the decoder has wrong options or the buffer contains invalid data for Webp Image.</exception>
 public BitmapSource Decode(ReadOnlyMemory <byte> data, WindowsDecoderOptions options)
 {
     using (var pinned = data.Pin())
     {
         IntPtr pointer;
         unsafe
         {
             pointer = new IntPtr(pinned.Pointer);
         }
         return(this.Decode(pointer, data.Length, options));
     }
 }
Example #4
0
        public void Test_WinForms()
        {
            using (var webp = new Webp(this.factory, false))
            {
                string[] test_files = { "Test_lossless.webp" };

                foreach (var filename in test_files)
                {
                    using (var fs = File.OpenRead(filename))
                    {
                        var decoderOpts = new WindowsDecoderOptions()
                        {
                            PixelFormat = OutputPixelFormat.PreferSmallSize
                        };
                        var encoderOpts = new EncoderOptions(CompressionType.Lossy, CompressionLevel.Highest, WebPPreset.Default, 90f);
                        using (var bitmap = webp.Decode(fs, decoderOpts))
                        {
                            using (var output = File.Create(Path.GetFileNameWithoutExtension(filename) + "_re-encode-stream.webp"))
                            {
                                webp.Encode(bitmap, output, encoderOpts);
                                output.Flush();
                            }
                        }

                        fs.Position = 0;
                        var length = (int)fs.Length;
                        var buffer = ArrayPool <byte> .Shared.Rent(length);

                        try
                        {
                            if (fs.Read(buffer, 0, buffer.Length) == length)
                            {
                                using (var bitmap = webp.Decode(new ReadOnlyMemory <byte>(buffer, 0, length), decoderOpts))
                                {
                                    using (var output = File.Create(Path.GetFileNameWithoutExtension(filename) + "_re-encode-buffer.webp"))
                                    {
                                        webp.Encode(bitmap, output, encoderOpts);
                                        output.Flush();
                                    }
                                }
                            }
                        }
                        finally
                        {
                            ArrayPool <byte> .Shared.Return(buffer);
                        }
                    }
                }
            }
        }
Example #5
0
        /// <summary>Decodes Webp data stream to <seealso cref="BitmapSource"/>.</summary>
        /// <param name="dataStream">The data stream which contains WebP image.</param>
        /// <param name="options">The decoder options for webp decoder.</param>
        /// <returns><seealso cref="BitmapSource"/> which contains the image data.</returns>
        /// <remarks>Incomplete API. Therefore, in case when decoder is progressive, only <seealso cref="WindowsDecoderOptions.PixelFormat"/> will be used, all other options will be ignored.</remarks>
        /// <exception cref="WebpDecodeException">Thrown when the decoder has wrong options or the stream contains invalid data for Webp Image.</exception>
        public BitmapSource Decode(Stream dataStream, WindowsDecoderOptions options)
        {
            if (dataStream == null)
            {
                throw new ArgumentNullException(nameof(dataStream));
            }
            if (!dataStream.CanRead)
            {
                throw new ArgumentException("The stream must be readable.", nameof(dataStream));
            }

            if (dataStream is MemoryStream memStream)
            {
                if (memStream.TryGetBuffer(out var segment))
                {
                    var mem = new ReadOnlyMemory <byte>(segment.Array, segment.Offset, segment.Count);
                    return(this.Decode(mem, options));
                }
            }

            bool canEvenSeek = false;

            try
            {
                canEvenSeek = dataStream.CanSeek;
            }
            catch (NotSupportedException) { }
            catch (NotImplementedException) { }

            if (canEvenSeek)
            {
                int  length;
                long currentPos = -1;
                try
                {
                    currentPos = dataStream.Position;
                    // Try get length if it supports.
                    length = (int)dataStream.Length;
                }
                catch (NotSupportedException) { length = -1; }
                // Length is longer than int.MaxValue
                catch { length = -2; }
                if (length != -2)
                {
                    // Try to get the webp's data length starting from the current position of the stream (if possible)
                    var bytes = ArrayPool <byte> .Shared.Rent(4096);

                    try
                    {
                        if (dataStream.Read(bytes, 0, 12) == 12)
                        {
                            if (WebpFactory.TryGetFileSizeFromImage(new ReadOnlyMemory <byte>(bytes), out length))
                            {
                                length += 8; // full image file's length.
                                if (length > bytes.Length)
                                {
                                    ArrayPool <byte> .Shared.Return(bytes);

                                    bytes = ArrayPool <byte> .Shared.Rent(length);
                                }
                                dataStream.Position = currentPos;
                                if (dataStream.Read(bytes, 0, length) == length)
                                {
                                    var mem = new ReadOnlyMemory <byte>(bytes, 0, length);
                                    return(this.Decode(mem, options));
                                }
                            }
                        }
                    }
                    catch (NotSupportedException)
                    {
                        if (currentPos != -1)
                        {
                            dataStream.Position = currentPos;
                        }
                    }
                    finally
                    {
                        ArrayPool <byte> .Shared.Return(bytes);
                    }
                }
            }

            byte[] currentBuffer = ArrayPool <byte> .Shared.Rent(4096);

            var memBuffer = new ReadOnlyMemory <byte>(currentBuffer);

            try
            {
                int streamRead = dataStream.Read(currentBuffer, 0, currentBuffer.Length);
                if (streamRead > 0)
                {
                    var features = new WebPBitstreamFeatures();
                    if (this.webp.TryGetImageHeaderInfo(new ReadOnlyMemory <byte>(currentBuffer), ref features) == VP8StatusCode.VP8_STATUS_OK)
                    {
                        int width = features.width, height = features.height;
                        var decodedBuffer = this.webp.CreateDecodeBuffer();
                        var decidedPxFmt  = Helper.DecideOutputPixelFormat(options.PixelFormat, features.has_alpha != 0);
                        decodedBuffer.colorspace         = Helper.GetWebpPixelFormat(decidedPxFmt);
                        decodedBuffer.is_external_memory = 1;
                        decodedBuffer.width  = width;
                        decodedBuffer.height = height;

                        var pixelFmt = Helper.GetPixelFormat(decidedPxFmt);
                        var result   = new WriteableBitmap(width, height, 96, 96, pixelFmt, null);
                        result.Lock();
                        try
                        {
                            decodedBuffer.u.RGBA.rgba   = result.BackBuffer;
                            decodedBuffer.u.RGBA.size   = new UIntPtr((uint)(result.BackBufferStride * result.PixelHeight));
                            decodedBuffer.u.RGBA.stride = result.BackBufferStride;
                            using (var decoder = this.webp.CreateDecoder(ref decodedBuffer))
                            {
                                VP8StatusCode status = VP8StatusCode.VP8_STATUS_NOT_ENOUGH_DATA;
                                while (streamRead != 0)
                                {
                                    status = decoder.AppendEncodedData(memBuffer.Slice(0, streamRead));
                                    // if (decoder.GetDecodedImage(out last_scanline_index, out var width, out var height, out var stride, out IntPtr pointer) == VP8StatusCode.VP8_STATUS_OK) { }
                                    if (status != VP8StatusCode.VP8_STATUS_SUSPENDED)
                                    {
                                        break;
                                    }
                                    streamRead = dataStream.Read(currentBuffer, 0, currentBuffer.Length);
                                }

                                if (status == VP8StatusCode.VP8_STATUS_OK)
                                {
                                    return(result);
                                }
                                else
                                {
                                    throw new WebpDecodeException(status);
                                }
                            }
                        }
                        finally
                        {
                            result.Unlock();
                            this.webp.Free(ref decodedBuffer);
                        }
                    }
                    else
                    {
                        var decidedPxFmt = Helper.DecideOutputPixelFormat(options.PixelFormat, null);
                        using (var decoder = this.webp.CreateDecoderForRGBX(Helper.GetWebpPixelFormat(decidedPxFmt)))
                        {
                            int           last_scanline_index = 0;
                            VP8StatusCode status = VP8StatusCode.VP8_STATUS_NOT_ENOUGH_DATA;
                            while (streamRead != 0)
                            {
                                status = decoder.AppendEncodedData(memBuffer.Slice(0, streamRead));
                                // if (decoder.GetDecodedImage(out last_scanline_index, out var width, out var height, out var stride, out IntPtr pointer) == VP8StatusCode.VP8_STATUS_OK) { }
                                if (status != VP8StatusCode.VP8_STATUS_SUSPENDED)
                                {
                                    break;
                                }
                                streamRead = dataStream.Read(currentBuffer, 0, currentBuffer.Length);
                            }
                            if (status == VP8StatusCode.VP8_STATUS_OK)
                            {
                                status = decoder.GetDecodedImage(ref last_scanline_index, out var width, out var height, out var stride, out IntPtr pointer);
                                if (status == VP8StatusCode.VP8_STATUS_OK)
                                {
                                    var result = new WriteableBitmap(width, height, 96, 96, Helper.GetPixelFormat(decidedPxFmt), null);
                                    result.Lock();
                                    try
                                    {
                                        var backBufferSize = stride * height;
                                        unsafe
                                        {
                                            Buffer.MemoryCopy(pointer.ToPointer(), result.BackBuffer.ToPointer(), backBufferSize, backBufferSize);
                                        }
                                        return(result);
                                    }
                                    finally
                                    {
                                        result.Unlock();
                                    }
                                }
                                else
                                {
                                    throw new WebpDecodeException(status);
                                }
                            }
                            else
                            {
                                throw new WebpDecodeException(status);
                            }
                        }
                    }
                }
                else
                {
                    throw new WebpDecodeException(VP8StatusCode.VP8_STATUS_BITSTREAM_ERROR);
                }
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(currentBuffer);
            }
        }