private static void CheckError(VP8StatusCode code) { if (code != VP8StatusCode.OK) { throw new InvalidOperationException($"VP8StatusCode not OK: {code}"); } }
/// <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); }
/// <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); } }
bool ReadHuffmanCodeLengths(int[] code_length_code_lengths, int num_symbols, int[] code_lengths) { int prev_code_len = Huffman.DefaultCodeLength; var table = new HuffmanCode[1 << Huffman.LengthsTableBits]; if (0 == Huffman.BuildTable (table, 0, Huffman.LengthsTableBits, code_length_code_lengths, NumCodeLengthCodes)) { status_ = VP8StatusCode.BitstreamError; return false; } int max_symbol; if (0 != br_.ReadBits (1)) // use length { int length_nbits = 2 + 2 * (int)br_.ReadBits (3); max_symbol = 2 + (int)br_.ReadBits (length_nbits); if (max_symbol > num_symbols) { status_ = VP8StatusCode.BitstreamError; return false; } } else { max_symbol = num_symbols; } int symbol = 0; while (symbol < num_symbols) { if (max_symbol-- == 0) break; br_.FillBitWindow(); int p = (int)br_.PrefetchBits() & Huffman.LengthsTableMask; br_.SkipBits (table[p].bits); int code_len = table[p].value; if (code_len < kCodeLengthLiterals) { code_lengths[symbol++] = code_len; if (code_len != 0) prev_code_len = code_len; } else { bool use_prev = (code_len == kCodeLengthRepeatCode); int slot = code_len - kCodeLengthLiterals; int extra_bits = kCodeLengthExtraBits[slot]; int repeat_offset = kCodeLengthRepeatOffsets[slot]; int repeat = (int)br_.ReadBits(extra_bits) + repeat_offset; if (symbol + repeat > num_symbols) { status_ = VP8StatusCode.BitstreamError; return false; } else { int length = use_prev ? prev_code_len : 0; while (repeat-- > 0) code_lengths[symbol++] = length; } } } return true; }
int VP8SetError(VP8Decoder* dec, VP8StatusCode error, char * msg) { dec.status_ = error; dec.error_msg_ = msg; dec.ready_ = 0; return 0; }
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); }
int ReadHuffmanCode(int alphabet_size, int[] code_lengths, HuffmanCode[] table, int index) { bool ok = false; int size = 0; bool simple_code = br_.ReadBits (1) != 0; for (int i = 0; i < alphabet_size; ++i) code_lengths[i] = 0; if (simple_code) // Read symbols, codes & code lengths directly. { int num_symbols = (int)br_.ReadBits (1) + 1; int first_symbol_len_code = (int)br_.ReadBits (1); // The first code is either 1 bit or 8 bit code. int symbol = (int)br_.ReadBits ((first_symbol_len_code == 0) ? 1 : 8); code_lengths[symbol] = 1; // The second code (if present), is always 8 bit long. if (2 == num_symbols) { symbol = (int)br_.ReadBits (8); code_lengths[symbol] = 1; } ok = true; } else // Decode Huffman-coded code lengths. { var code_length_code_lengths = new int[NumCodeLengthCodes]; int num_codes = (int)br_.ReadBits (4) + 4; if (num_codes > NumCodeLengthCodes) { status_ = VP8StatusCode.BitstreamError; return 0; } for (int i = 0; i < num_codes; ++i) { code_length_code_lengths[kCodeLengthCodeOrder[i]] = (int)br_.ReadBits (3); } ok = ReadHuffmanCodeLengths (code_length_code_lengths, alphabet_size, code_lengths); } ok = ok && !br_.EoS; if (ok) size = Huffman.BuildTable (table, index, Huffman.TableBits, code_lengths, alphabet_size); if (!ok || size == 0) { status_ = VP8StatusCode.BitstreamError; return 0; } return size; }
public bool DecodeImageData(uint[] data, int width, int height, int last_row, ProcessRowsFunc process_func) { int row = last_pixel_ / width; int col = last_pixel_ % width; var htree_group = GetHtreeGroupForPos (col, row); int src = last_pixel_; int last_cached = src; int src_end = width * height; // End of data int src_last = width * last_row; // Last pixel to decode int len_code_limit = Huffman.NumLiteralCodes + Huffman.NumLengthCodes; int color_cache_limit = len_code_limit + hdr_.color_cache_size_; int next_sync_row = incremental_ ? row : 1 << 24; var color_cache = (hdr_.color_cache_size_ > 0) ? hdr_.color_cache_ : null; int mask = hdr_.huffman_mask_; while (src < src_last) { int code; if (row >= next_sync_row) { SaveState (src); next_sync_row = row + SyncEveryNRows; } // Only update when changing tile. Note we could use this test: // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed // but that's actually slower and needs storing the previous col/row. if ((col & mask) == 0) htree_group = GetHtreeGroupForPos (col, row); if (htree_group.is_trivial_code) { data[src] = htree_group.literal_arb; goto AdvanceByOne; } br_.FillBitWindow(); if (htree_group.use_packed_table) { code = ReadPackedSymbols (htree_group, data, src); if (code == PackedNonLiteralCode) goto AdvanceByOne; } else { code = ReadSymbol (htree_group.Tables, htree_group.GetMeta (HuffIndex.Green)); } if (br_.EoS) break; // early out if (code < Huffman.NumLiteralCodes) // Literal { if (htree_group.is_trivial_literal) { data[src] = htree_group.literal_arb | (uint)(code << 8); } else { int red, blue, alpha; red = ReadSymbol (htree_group.Tables, htree_group.GetMeta (HuffIndex.Red)); br_.FillBitWindow(); blue = ReadSymbol (htree_group.Tables, htree_group.GetMeta (HuffIndex.Blue)); alpha = ReadSymbol (htree_group.Tables, htree_group.GetMeta (HuffIndex.Alpha)); if (br_.EoS) break; data[src] = ((uint)alpha << 24) | ((uint)red << 16) | ((uint)code << 8) | (uint)blue; } } else if (code < len_code_limit) // Backward reference { int length_sym = code - Huffman.NumLiteralCodes; int length = GetCopyLength (length_sym); int dist_symbol = ReadSymbol (htree_group.Tables, htree_group.GetMeta (HuffIndex.Dist)); br_.FillBitWindow(); int dist_code = GetCopyDistance (dist_symbol); int dist = PlaneCodeToDistance (width, dist_code); if (br_.EoS) break; if (src < dist || src_end - src < length) { status_ = VP8StatusCode.BitstreamError; return false; } else { int dst = src; int s = dst - dist; for (int i = 0; i < length; ++i) data[dst+i] = data[s+i]; } src += length; col += length; while (col >= width) { col -= width; ++row; if ((row % NumARGBCacheRows == 0) && (process_func != null)) process_func (this, row); } if (0 != (col & mask)) htree_group = GetHtreeGroupForPos (col, row); if (color_cache != null) { while (last_cached < src) color_cache.Insert (data[last_cached++]); } continue; } else if (code < color_cache_limit) // Color cache { int key = code - len_code_limit; while (last_cached < src) color_cache.Insert (data[last_cached++]); data[src] = color_cache.Lookup ((uint)key); } else // Not reached { status_ = VP8StatusCode.BitstreamError; return false; } AdvanceByOne: ++src; ++col; if (col >= width) { col = 0; ++row; if ((row % NumARGBCacheRows == 0) && (process_func != null)) { process_func (this, row); } if (color_cache != null) { while (last_cached < src) color_cache.Insert (data[last_cached++]); } } } if (incremental_ && br_.EoS && src < src_end) { RestoreState(); } else if (!br_.EoS) { // Process the remaining rows corresponding to last row-block. if (process_func != null) process_func (this, row); status_ = VP8StatusCode.Ok; last_pixel_ = src; // end-of-scan marker } else { // if not incremental, and we are past the end of buffer (eos_=1), then this // is a real bitstream error. status_ = VP8StatusCode.BitstreamError; return false; } return true; }
public bool DecodeImageStream(int xsize, int ysize, bool is_level0, ref uint[] decoded_data, bool set_data) { bool ok = true; int transform_xsize = xsize; int transform_ysize = ysize; int color_cache_bits = 0; uint[] data = null; // Read the transforms (may recurse). if (is_level0) { while (ok && 0 != br_.ReadBits (1)) ok = ReadTransform (ref transform_xsize, ref transform_ysize); } // Color cache if (ok && 0 != br_.ReadBits (1)) { color_cache_bits = (int)br_.ReadBits (4); ok = (color_cache_bits >= 1 && color_cache_bits <= MaxCacheBits); if (!ok) { status_ = VP8StatusCode.BitstreamError; return false; } } // Read the Huffman codes (may recurse). ok = ok && ReadHuffmanCodes (transform_xsize, transform_ysize, color_cache_bits, is_level0); if (!ok) { status_ = VP8StatusCode.BitstreamError; return false; } // Finish setting up the color-cache if (color_cache_bits > 0) { hdr_.color_cache_size_ = 1 << color_cache_bits; hdr_.color_cache_.Init (color_cache_bits); } else { hdr_.color_cache_size_ = 0; } UpdateDecoder (transform_xsize, transform_ysize); if (is_level0) // level 0 complete { state_ = VP8DecodeState.ReadHdr; } else { var total_size = transform_xsize * transform_ysize; data = new uint[total_size]; // Use the Huffman trees to decode the LZ77 encoded data. ok = DecodeImageData (data, transform_xsize, transform_ysize, transform_ysize, null); ok = ok && !br_.EoS; } if (ok) { if (set_data) { decoded_data = data; } last_pixel_ = 0; // Reset for future DECODE_DATA_FUNC() calls. if (!is_level0) hdr_.ClearMetadata(); } return ok; }
public LosslessDecoder() { status_ = VP8StatusCode.Ok; state_ = VP8DecodeState.ReadDim; for (int i = 0; i < transforms_.Length; ++i) transforms_[i] = new VP8LTransform(); }
public bool DecodeAlphaData(int width, int height, int last_row) { var data = pixels8_; bool ok = true; int row = last_pixel_ / width; int col = last_pixel_ % width; var htree_group = GetHtreeGroupForPos (col, row); int pos = last_pixel_; // current position int end = width * height; // End of data int last = width * last_row; // Last pixel to decode int len_code_limit = Huffman.NumLiteralCodes + Huffman.NumLengthCodes; int mask = hdr_.huffman_mask_; while (!br_.EoS && pos < last) { // Only update when changing tile. if ((col & mask) == 0) htree_group = GetHtreeGroupForPos (col, row); br_.FillBitWindow(); int code = ReadSymbol (htree_group.Tables, htree_group.GetMeta (HuffIndex.Green)); if (code < Huffman.NumLiteralCodes) // Literal { data[pos] = (byte)code; ++pos; ++col; if (col >= width) { col = 0; ++row; if (row % NumARGBCacheRows == 0) ExtractPalettedAlphaRows (row); } } else if (code < len_code_limit) // Backward reference { int length_sym = code - Huffman.NumLiteralCodes; int length = GetCopyLength (length_sym); int dist_symbol = ReadSymbol (htree_group.Tables, htree_group.GetMeta (HuffIndex.Dist)); br_.FillBitWindow(); int dist_code = GetCopyDistance (dist_symbol); int dist = PlaneCodeToDistance (width, dist_code); if (pos >= dist && end - pos >= length) { Binary.CopyOverlapped (data, pos - dist, pos, length); } else { ok = false; goto End; } pos += length; col += length; while (col >= width) { col -= width; ++row; if (row % NumARGBCacheRows == 0) ExtractPalettedAlphaRows (row); } if (pos < last && 0 != (col & mask)) htree_group = GetHtreeGroupForPos (col, row); } else // Not reached { ok = false; goto End; } } // Process the remaining rows corresponding to last row-block. ExtractPalettedAlphaRows (row); End: if (!ok || (br_.EoS && pos < end)) { ok = false; status_ = br_.EoS ? VP8StatusCode.Suspended : VP8StatusCode.BitstreamError; } else { last_pixel_ = pos; } return ok; }
void RestoreState() { status_ = VP8StatusCode.Suspended; saved_br_.CopyStateTo (br_); last_pixel_ = saved_last_pixel_; if (hdr_.color_cache_size_ > 0) hdr_.saved_color_cache_.Copy (hdr_.color_cache_); }
/// <summary>Initializes a new instance of the <see cref="WebpDecodeException"/> class with a specified error code.</summary> /// <param name="code">The error code of the operation.</param> public WebpDecodeException(VP8StatusCode code) : base() { this.ErrorCode = code; }
/// <summary>Initializes a new instance of the <see cref="WebpDecodeException"/> class with a specified error code and error message.</summary> /// <param name="code">The error code of the operation.</param> /// <param name="message">The error message of the operation.</param> public WebpDecodeException(VP8StatusCode code, string message) : base(message) { this.ErrorCode = code; }
/// <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); }
public void Init(int width, int height, VP8Io io, byte[] data, int data_i, int data_size, byte[] output) { width_ = width; height_ = height; status_ = VP8StatusCode.Ok; io_ = io; io_.opaque = output; io_.width = width_; io_.height = height_; br_.Init (data, data_i, (uint)data_size); }
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); } } }
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); }