Exemple #1
0
        internal static unsafe void EncodeWebP(Stream writer, Texture2D texture, bool lossless, float quality)
        {
            bool hasAlpha = HasAlpha(texture);
            // Stream stream = fileInfo.Create();
            var format        = hasAlpha ? UnityEngine.TextureFormat.RGBA32 : UnityEngine.TextureFormat.RGB24;
            var outputTexture = BlitTexture(texture, format);

            WebPConfig  config  = new WebPConfig();
            WebPPicture picture = new WebPPicture();

            if (WebpEncoderNativeCalls.WebPConfigInitInternal(ref config, WebPPreset.WEBP_PRESET_DEFAULT, quality, WEBP_ENCODER_ABI_VERSION) == 0)
            {
                throw new Exception("Failed to initialize WebPConfig.");
            }
            if (lossless)
            {
                //TODO: refine the level value [0..9] we want to set. 6 seems a good default value
                WebpEncoderNativeCalls.WebPConfigLosslessPreset(ref config, 6);
            }

            if (WebpEncoderNativeCalls.WebPValidateConfig(ref config) == 0)
            {
                throw new Exception("Failed to validate WebPConfig.");
            }

            if (WebpEncoderNativeCalls.WebPPictureInitInternal(ref picture, WEBP_ENCODER_ABI_VERSION) == 0)
            {
                throw new Exception("Failed to initialize WebPPicture, version mismatch.");  // version mismatch error
            }
            picture.width  = outputTexture.width;
            picture.height = outputTexture.height;
            if (WebpEncoderNativeCalls.WebPPictureAlloc(ref picture) == 0)
            {
                throw new Exception("Failed to allocate WebPPicture");
            }

            GCHandle lPinnedArray = GCHandle.Alloc(outputTexture.GetRawTextureData(), GCHandleType.Pinned);

            fixed(byte *buffer = outputTexture.GetRawTextureData())
            {
                if (hasAlpha)
                {
                    int   stride      = picture.width * 4;
                    byte *lTmpDataPtr = buffer + (picture.height - 1) * stride;
                    WebpEncoderNativeCalls.WebPPictureImportRGBA(ref picture, lTmpDataPtr, -stride);
                }
                else
                {
                    int   stride      = picture.width * 3;
                    byte *lTmpDataPtr = buffer + (picture.height - 1) * stride;
                    WebpEncoderNativeCalls.WebPPictureImportRGB(ref picture, lTmpDataPtr, -stride);
                }
            }

            //Write the compressed data in WebPWriterFunction
            picture.writer = (IntPtr data, UIntPtr size, ref WebPPicture pPicture) =>
            {
                byte[] res = new byte[size.ToUInt32()];
                Marshal.Copy(data, res, 0, (int)size.ToUInt32());
                try
                {
                    writer.Write(res, 0, res.Length);
                }
                catch (Exception e)
                {
                    throw new Exception("Failed in writing a WebP compressed image to a stream." + e.Message);
                }
                return(1);
            };

            if (WebpEncoderNativeCalls.WebPEncode(ref config, ref picture) == 0)
            {
                WebpEncoderNativeCalls.WebPPictureFree(ref picture);
                throw new Exception($"Failed to encode webp image error: {picture.error_code.ToString()}");
            }

            WebpEncoderNativeCalls.WebPPictureFree(ref picture);

            writer.Dispose();
            lPinnedArray.Free();
        }
Exemple #2
0
        internal int MyFileWriter([In] IntPtr data, [param: MarshalAs(UnmanagedType.SysUInt)] UIntPtr data_size, ref WebPPicture picture)
        {
            int blocksize = (int)data_size;

            if (this._preallocateOnDisk)
            {
                this._preallocateOnDisk = false;

                // The first memory block that decoder push will be the webp file header (which contains the WebPContent size in bytes).
                // Total of 12 bytes:
                // 4: ASCII "RIFF"
                // 4: WebP Content Size
                // 4: ASCII "WEBP"

                // Get the WebPContent size in bytes
                int contentSizeWithoutRIFFHeader = Marshal.ReadInt32(data, 4);
                contentSizeWithoutRIFFHeader += 8; // Because the we got above is starting from offset 8 of the real file.
                try
                {
                    this.fs.SetLength(contentSizeWithoutRIFFHeader);
                }
                catch
                {
                    // Pre-allocate size on disk failed. Either not enough space or I don't know.
                    return(0);
                }
            }

            unsafe
            {
                byte *b = (byte *)(data.ToPointer());
                try
                {
                    for (int i = 0; i < blocksize; i++)
                    {
                        // WriteByte may cause overhead but Marshal.Copy to use Write(byte[], int, int) is not good in case, either.
                        // WriteByte method still uses FileStream's buffer, by the way.
                        this.fs.WriteByte(b[i]);
                    }
                }
                catch
                {
                    // Tell the native library to stop because we got an error here.
                    // Either the file has been removed or the write permission has been cut off by someone (in case it's a network file)
                    // Or locked by anti-virus or anything.
                    return(0);
                }
            }

            return(1);
        }