Beispiel #1
0
        public static unsafe void LoadTexture2DFromWebP(byte[] webpBytes, Texture2D texture, bool lMipmaps, bool lLinear, byte[] bytePool, int numBytesRequired, ScalingFunction scalingFunction = null)
        {
            Debug.Assert(bytePool.Length >= numBytesRequired);
            Array.Clear(bytePool, 0, numBytesRequired);

            int width  = texture.width;
            int height = texture.height;

            fixed(byte *lDataPtr = webpBytes)
            {
                fixed(byte *lRawDataPtr = bytePool)
                {
                    int lStride = 4 * width;

                    // As we have to reverse the y order of the data, we pass through a negative stride and
                    // pass through a pointer to the last line of the data.
                    byte *lTmpDataPtr = lRawDataPtr + (height - 1) * lStride;

                    WebPDecoderConfig config = new WebPDecoderConfig();

                    if (NativeLibwebp.WebPInitDecoderConfig(&config) == 0)
                    {
                        throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
                    }

                    // Set up decode options
                    config.options.use_threads = 1;
                    if (scalingFunction != null)
                    {
                        config.options.use_scaling = 1;
                    }
                    config.options.scaled_width  = width;
                    config.options.scaled_height = height;

                    // read the .webp input file information
                    VP8StatusCode result = NativeLibwebp.WebPGetFeatures(lDataPtr, (UIntPtr)webpBytes.Length, &config.input);

                    if (result != VP8StatusCode.VP8_STATUS_OK)
                    {
                        throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result.ToString()));
                    }

                    // specify the output format
                    config.output.colorspace         = WEBP_CSP_MODE.MODE_RGBA;
                    config.output.u.RGBA.rgba        = lTmpDataPtr;
                    config.output.u.RGBA.stride      = -lStride;
                    config.output.u.RGBA.size        = (UIntPtr)(height * lStride);
                    config.output.height             = height;
                    config.output.width              = width;
                    config.output.is_external_memory = 1;

                    // Decode
                    result = NativeLibwebp.WebPDecode(lDataPtr, (UIntPtr)webpBytes.Length, &config);
                    if (result != VP8StatusCode.VP8_STATUS_OK)
                    {
                        throw new Exception(string.Format("Failed WebPDecode with error {0}.", result.ToString()));
                    }

                    texture.LoadRawTextureData((IntPtr)lRawDataPtr, numBytesRequired);
                    texture.Apply(lMipmaps, true);
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Loads an image from webp into a byte array in RGBA format.
        /// </summary>
        /// <returns>The RGBA from web p.</returns>
        /// <param name="lData">L data.</param>
        /// <param name="lWidth">L width.</param>
        /// <param name="lHeight">L height.</param>
        /// <param name="lMipmaps">If set to <c>true</c> l mipmaps.</param>
        /// <param name="lError">L error.</param>
        /// <param name="scalingFunction">Scaling function.</param>
        public static unsafe byte[] LoadRGBAFromWebP(byte[] lData, ref int lWidth, ref int lHeight, bool lMipmaps, out Error lError, ScalingFunction scalingFunction = null)
        {
            lError = 0;
            byte[] lRawData = null;
            int    lLength  = lData.Length;

            fixed(byte *lDataPtr = lData)
            {
                // If we've been supplied a function to alter the width and height, use that now.
                scalingFunction?.Invoke(ref lWidth, ref lHeight);

                // If mipmaps are requested we need to create 1/3 more memory for the mipmaps to be generated in.
                int numBytesRequired = lWidth * lHeight * 4;

                if (lMipmaps)
                {
                    numBytesRequired = Mathf.CeilToInt((numBytesRequired * 4.0f) / 3.0f);
                }

                lRawData = new byte[numBytesRequired];
                fixed(byte *lRawDataPtr = lRawData)
                {
                    int lStride = 4 * lWidth;

                    // As we have to reverse the y order of the data, we pass through a negative stride and
                    // pass through a pointer to the last line of the data.
                    byte *lTmpDataPtr = lRawDataPtr + (lHeight - 1) * lStride;

                    WebPDecoderConfig config = new WebPDecoderConfig();

                    if (NativeLibwebp.WebPInitDecoderConfig(&config) == 0)
                    {
                        throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
                    }

                    // Set up decode options
                    config.options.use_threads = 1;
                    if (scalingFunction != null)
                    {
                        config.options.use_scaling = 1;
                    }
                    config.options.scaled_width  = lWidth;
                    config.options.scaled_height = lHeight;

                    // read the .webp input file information
                    VP8StatusCode result = NativeLibwebp.WebPGetFeatures(lDataPtr, (UIntPtr)lLength, &config.input);

                    if (result != VP8StatusCode.VP8_STATUS_OK)
                    {
                        throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result.ToString()));
                    }

                    // specify the output format
                    config.output.colorspace         = WEBP_CSP_MODE.MODE_RGBA;
                    config.output.u.RGBA.rgba        = lTmpDataPtr;
                    config.output.u.RGBA.stride      = -lStride;
                    config.output.u.RGBA.size        = (UIntPtr)(lHeight * lStride);
                    config.output.height             = lHeight;
                    config.output.width              = lWidth;
                    config.output.is_external_memory = 1;

                    // Decode
                    result = NativeLibwebp.WebPDecode(lDataPtr, (UIntPtr)lLength, &config);
                    if (result != VP8StatusCode.VP8_STATUS_OK)
                    {
                        throw new Exception(string.Format("Failed WebPDecode with error {0}.", result.ToString()));
                    }
                }

                lError = Error.Success;
            }

            return(lRawData);
        }
    private unsafe List <(Texture2D, int)> LoadAnimation2(string loadPath)
    {
        List <ValueTuple <Texture2D, int> > ret = new List <ValueTuple <Texture2D, int> >();

        TextAsset textasset = Resources.Load <TextAsset>(loadPath);

        byte[] bytes = textasset.bytes;

        WebPDecoderConfig config = new WebPDecoderConfig();

        if (NativeLibwebp.WebPInitDecoderConfig(&config) == 0)
        {
            throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
        }

        WebPIterator iter = new WebPIterator();

        fixed(byte *p = bytes)
        {
            WebPData webpdata = new WebPData
            {
                bytes = p,
                size  = new UIntPtr((uint)bytes.Length)
            };
            WebPDemuxer *webPDemuxer = NativeLibwebpdemux.WebPDemuxInternal(&webpdata, 0, (WebPDemuxState *)IntPtr.Zero, NativeLibwebpdemux.WEBP_DEMUX_ABI_VERSION);

            VP8StatusCode result = NativeLibwebp.WebPGetFeatures(webpdata.bytes, webpdata.size, &config.input);

            if (result != VP8StatusCode.VP8_STATUS_OK)
            {
                throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result.ToString()));
            }

            int height = config.input.height;
            int width  = config.input.height;

            config.options.bypass_filtering    = 0;
            config.options.use_threads         = 1;
            config.options.no_fancy_upsampling = 0;
            config.options.use_cropping        = 0;
            config.options.use_scaling         = 1;
            config.options.scaled_width        = width;
            config.options.scaled_height       = height;
            config.options.flip = 1;
            config.options.dithering_strength = 0;
            config.output.colorspace          = WEBP_CSP_MODE.MODE_RGBA;
            config.output.width  = width;
            config.output.height = height;

            //byte[] bbb = new byte[width * height];
            //fixed (byte* ppp = bbb)
            //{
            //    config.output.u.RGBA.rgba = (IntPtr)ppp;
            //}
            //config.output.u.RGBA.stride = width * 4;
            //config.output.u.RGBA.size = (UIntPtr)(width * height);
            //config.output.is_external_memory = 1;
            //config.output.is_external_memory = 1;

            int success = NativeLibwebpdemux.WebPDemuxGetFrame(webPDemuxer, 1, &iter);

            if (success != 1)
            {
                return(ret);
            }

            int timestamp = 0;
            int size      = width * height * 4;

            do
            {
                WebPData      frame  = iter.fragment;
                VP8StatusCode status = NativeLibwebp.WebPDecode(frame.bytes, frame.size, &config);
                if (status != VP8StatusCode.VP8_STATUS_OK)
                {
                    Debug.LogError(status);
                    break;
                }

                Texture2D texture = Texture2DExt.CreateWebpTexture2D(width, height, isUseMipmap: false, isLinear: false);
                texture.LoadRawTextureData((IntPtr)config.output.u.RGBA.rgba, size);
                texture.Apply(updateMipmaps: false, makeNoLongerReadable: true);
                timestamp += iter.duration;
                ret.Add((texture, timestamp));
            }while (NativeLibwebpdemux.WebPDemuxNextFrame(&iter) == 1);

            NativeLibwebpdemux.WebPDemuxDelete(webPDemuxer);
            NativeLibwebpdemux.WebPDemuxReleaseIterator(&iter);
        }

        return(ret);
    }
Beispiel #4
0
        /// <summary>
        /// Loads an image from webp into a byte array in RGBA format.
        /// </summary>
        /// <returns>The RGBA from web p.</returns>
        /// <param name="lData">L data.</param>
        /// <param name="lWidth">L width.</param>
        /// <param name="lHeight">L height.</param>
        /// <param name="lMipmaps">If set to <c>true</c> l mipmaps.</param>
        /// <param name="lError">L error.</param>
        /// <param name="scalingFunction">Scaling function.</param>
        public static Status DecodeWebP(byte[] lInput, ref int lWidth, ref int lHeight, ref WEBP_CSP_MODE lColorSpace,
                                        bool lMipmaps, out byte[] lOutput, bool lReducedColorRange = false,
                                        bool lReducedScale = false)
        {
            Status lStatus        = 0;
            int    lLength        = lInput.Length;
            int    lBytesPerTexel = 4;

            GCHandle lHandle = GCHandle.Alloc(lInput, GCHandleType.Pinned);

            {
                IntPtr lDataPtr = lHandle.AddrOfPinnedObject();

                WebPDecoderConfig config = new WebPDecoderConfig();

                if (NativeBindings.WebPInitDecoderConfig(ref config) == 0)
                {
                    throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
                }

                if (lReducedScale == true)
                {
                    lWidth  /= 2;
                    lHeight /= 2;
                }

                // Set up decode options
                config.options.use_threads = 0;
                if (lReducedScale == true)
                {
                    config.options.use_scaling   = 1;
                    config.options.scaled_width  = lWidth;
                    config.options.scaled_height = lHeight;
                }

                // read the .webp input file information
                VP8StatusCode result = NativeBindings.WebPGetFeatures((IntPtr)lDataPtr, (UIntPtr)lLength, ref config.input);
                if (result != VP8StatusCode.VP8_STATUS_OK)
                {
                    throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result.ToString()));
                }

                //  confirm colorspace.
                if (config.input.has_alpha > 0)
                {
                    if (lReducedColorRange == true)
                    {
                        lColorSpace    = WEBP_CSP_MODE.MODE_RGBA_4444;
                        lBytesPerTexel = 2;
                    }
                    else
                    {
                        lColorSpace    = WEBP_CSP_MODE.MODE_RGBA;
                        lBytesPerTexel = 4;
                    }
                }
                else
                {
                    if (lReducedColorRange == true)
                    {
                        lColorSpace    = WEBP_CSP_MODE.MODE_RGB_565;
                        lBytesPerTexel = 2;
                    }
                    else
                    {
                        lColorSpace    = WEBP_CSP_MODE.MODE_RGB;
                        lBytesPerTexel = 3;
                    }
                }

                // Bytes per texel can only be calculated at this point...
                int lStride = lBytesPerTexel * lWidth;

                // If mipmaps are requested we need to create 1/3 more memory for the mipmaps to be generated in.
                int lSize = lHeight * lStride;
                if (lMipmaps)   //  don't do this here..
                {
                    //  bit shift instead of this crude approach.,...
                    lSize += Mathf.CeilToInt((float)lSize / 3.0f);
                }

                lOutput = new byte[lSize];
                GCHandle lOutHandle = GCHandle.Alloc(lOutput, GCHandleType.Pinned);
                IntPtr   lOutputPtr = lOutHandle.AddrOfPinnedObject();
                {
                    // As we have to reverse the y order of the data, we pass through a negative stride and
                    // pass through a pointer to the last line of the data.
                    IntPtr lTmpDataPtr = new IntPtr(lOutputPtr.ToInt64() + (lSize - lStride));

                    // specify the output format
                    config.output.colorspace         = lColorSpace;
                    config.output.u.RGBA.rgba        = lTmpDataPtr;
                    config.output.u.RGBA.stride      = -lStride;
                    config.output.u.RGBA.size        = (UIntPtr)lSize;
                    config.output.height             = lHeight;
                    config.output.width              = lWidth;
                    config.output.is_external_memory = 1;

                    // Decode
                    result = NativeBindings.WebPDecode((IntPtr)lDataPtr, (UIntPtr)lLength, ref config);
                    if (result != VP8StatusCode.VP8_STATUS_OK)
                    {
                        throw new Exception(string.Format("Failed WebPDecode with error {0}.", result.ToString()));
                    }
                }
                lOutHandle.Free();
                lStatus = Status.SUCCESS;
            }
            lHandle.Free();

            return(lStatus);
        }
    private unsafe List <(Texture2D, int)> LoadAnimation2(string loadPath)
    {
        List <ValueTuple <Texture2D, int> > ret = new List <ValueTuple <Texture2D, int> >();

        TextAsset textasset = Resources.Load <TextAsset>(loadPath);

        byte[] bytes = textasset.bytes;

        var config = new WebPDecoderConfig();

        if (Decode.WebPInitDecoderConfig(ref config) == 0)
        {
            throw new Exception("WebPInitDecoderConfig failed. Wrong version?");
        }

        var    iter        = new WebPIterator();
        IntPtr webpDataPtr = Marshal.AllocHGlobal(sizeof(WebPData));
        IntPtr configPtr   = Marshal.AllocHGlobal(Marshal.SizeOf(config));
        IntPtr iterPtr     = Marshal.AllocHGlobal(Marshal.SizeOf(iter));

        try
        {
            fixed(byte *p = bytes)
            {
                IntPtr   ptr      = (IntPtr)p;
                WebPData webpdata = new WebPData
                {
                    bytes = ptr,
                    size  = new UIntPtr((uint)bytes.Length)
                };

                Marshal.StructureToPtr(webpdata, webpDataPtr, false);
                Marshal.StructureToPtr(config, configPtr, false);
                Marshal.StructureToPtr(iter, iterPtr, false);
                IntPtr webPDemuxer = Demux.WebPDemuxInternal(webpDataPtr, 0, (IntPtr)0, Demux.WEBP_DEMUX_ABI_VERSION);

                VP8StatusCode result = Decode.WebPGetFeatures(webpdata.bytes, webpdata.size, ref config.input);

                if (result != VP8StatusCode.VP8_STATUS_OK)
                {
                    throw new Exception(string.Format("Failed WebPGetFeatures with error {0}.", result.ToString()));
                }

                var height = config.input.height;
                var width  = config.input.height;

                config.options.bypass_filtering    = 0;
                config.options.use_threads         = 1;
                config.options.no_fancy_upsampling = 0;
                config.options.use_cropping        = 0;
                config.options.use_scaling         = 1;
                config.options.scaled_width        = width;
                config.options.scaled_height       = height;
                config.options.flip = 1;
                config.options.dithering_strength = 0;
                config.output.colorspace          = WEBP_CSP_MODE.MODE_RGBA;
                config.output.width  = width;
                config.output.height = height;

                //byte[] bbb = new byte[width * height];
                //fixed (byte* ppp = bbb)
                //{
                //    config.output.u.RGBA.rgba = (IntPtr)ppp;
                //}
                //config.output.u.RGBA.stride = width * 4;
                //config.output.u.RGBA.size = (UIntPtr)(width * height);
                //config.output.is_external_memory = 1;
                //config.output.is_external_memory = 1;

                int success = Demux.WebPDemuxGetFrame(webPDemuxer, 1, ref iter);

                if (success != 1)
                {
                    return(ret);
                }

                int timestamp = 0;
                int size      = width * height * 4;

                do
                {
                    WebPData      frame  = iter.fragment;
                    VP8StatusCode status = Decode.WebPDecode(frame.bytes, frame.size, ref config);
                    if (status != VP8StatusCode.VP8_STATUS_OK)
                    {
                        Debug.LogError(status);
                        break;
                    }

                    var texture = new Texture2D(width, height, TextureFormat.RGBA32, mipChain: false, linear: false);
                    texture.LoadRawTextureData(config.output.u.RGBA.rgba, size);
                    texture.Apply(updateMipmaps: false, makeNoLongerReadable: true);
                    timestamp += iter.duration;
                    ret.Add((texture, timestamp));
                }while (Demux.WebPDemuxNextFrame(ref iter) == 1);

                Demux.WebPDemuxDelete(webPDemuxer);
                Demux.WebPDemuxReleaseIterator(ref iter);
            }
        }
        finally
        {
            Marshal.FreeHGlobal(webpDataPtr);
            Marshal.FreeHGlobal(configPtr);
            Marshal.FreeHGlobal(iterPtr);
        }

        return(ret);
    }