gpui: Add support for animated images (#13809)

This PR adds support for animated images. The image requires a id for it
to actually animate across frames.

Currently it only has support for `GIF`, I tried adding decoding a
animated `WebP` into frames but it seems to error. This issue in the
image crate seems to document this
https://github.com/image-rs/image/issues/2263.

Not sure if this is the best way or the desired way for animated images
to work in GPUI but I would really like support for animated images.
Open to feedback.

Example Video:


https://github.com/zed-industries/zed/assets/76515905/011f790f-d070-499b-96c9-bbff141fb002



Closes https://github.com/zed-industries/zed/issues/9993

Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Matin Aniss 2024-07-27 22:05:37 +10:00 committed by GitHub
parent c0df1e1846
commit 4bd935b409
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 212 additions and 51 deletions

View file

@ -1,6 +1,7 @@
use crate::{size, DevicePixels, Result, SharedString, Size};
use smallvec::SmallVec;
use image::RgbaImage;
use image::{Delay, Frame};
use std::{
borrow::Cow,
fmt,
@ -34,43 +35,54 @@ pub struct ImageId(usize);
#[derive(PartialEq, Eq, Hash, Clone)]
pub(crate) struct RenderImageParams {
pub(crate) image_id: ImageId,
pub(crate) frame_index: usize,
}
/// A cached and processed image.
pub struct ImageData {
/// The ID associated with this image
pub id: ImageId,
data: RgbaImage,
data: SmallVec<[Frame; 1]>,
}
impl ImageData {
/// Create a new image from the given data.
pub fn new(data: RgbaImage) -> Self {
pub fn new(data: impl Into<SmallVec<[Frame; 1]>>) -> Self {
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
Self {
id: ImageId(NEXT_ID.fetch_add(1, SeqCst)),
data,
data: data.into(),
}
}
/// Convert this image into a byte slice.
pub fn as_bytes(&self) -> &[u8] {
&self.data
pub fn as_bytes(&self, frame_index: usize) -> &[u8] {
&self.data[frame_index].buffer()
}
/// Get the size of this image, in pixels
pub fn size(&self) -> Size<DevicePixels> {
let (width, height) = self.data.dimensions();
/// Get the size of this image, in pixels.
pub fn size(&self, frame_index: usize) -> Size<DevicePixels> {
let (width, height) = self.data[frame_index].buffer().dimensions();
size(width.into(), height.into())
}
/// Get the delay of this frame from the previous
pub fn delay(&self, frame_index: usize) -> Delay {
self.data[frame_index].delay()
}
/// Get the number of frames for this image.
pub fn frame_count(&self) -> usize {
self.data.len()
}
}
impl fmt::Debug for ImageData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ImageData")
.field("id", &self.id)
.field("size", &self.data.dimensions())
.field("size", &self.size(0))
.finish()
}
}