Explain the purpose of the `ImageSource::Bytes` URI (#3402)

Closes https://github.com/emilk/egui/issues/3363
This commit is contained in:
Emil Ernerfeldt 2023-09-27 13:53:33 +02:00 committed by GitHub
parent a9272e0e55
commit dbf3405597
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 22 deletions

View File

@ -458,10 +458,10 @@ pub fn warn_if_debug_build(ui: &mut crate::Ui) {
#[macro_export] #[macro_export]
macro_rules! include_image { macro_rules! include_image {
($path: literal) => { ($path: literal) => {
$crate::ImageSource::Bytes( $crate::ImageSource::Bytes {
::std::borrow::Cow::Borrowed(concat!("bytes://", $path)), // uri uri: ::std::borrow::Cow::Borrowed(concat!("bytes://", $path)),
$crate::load::Bytes::Static(include_bytes!($path)), bytes: $crate::load::Bytes::Static(include_bytes!($path)),
) }
}; };
} }

View File

@ -79,15 +79,15 @@ pub enum LoadError {
/// Programmer error: There are no image loaders installed. /// Programmer error: There are no image loaders installed.
NoImageLoaders, NoImageLoaders,
/// A specific loader does not support this schema, protocol or image format. /// A specific loader does not support this scheme, protocol or image format.
NotSupported, NotSupported,
/// Programmer error: Failed to find the bytes for this image because /// Programmer error: Failed to find the bytes for this image because
/// there was no [`BytesLoader`] supporting the schema. /// there was no [`BytesLoader`] supporting the scheme.
NoMatchingBytesLoader, NoMatchingBytesLoader,
/// Programmer error: Failed to parse the bytes as an image because /// Programmer error: Failed to parse the bytes as an image because
/// there was no [`ImageLoader`] supporting the schema. /// there was no [`ImageLoader`] supporting the scheme.
NoMatchingImageLoader, NoMatchingImageLoader,
/// Programmer error: no matching [`TextureLoader`]. /// Programmer error: no matching [`TextureLoader`].
@ -111,7 +111,7 @@ impl Display for LoadError {
Self::NoMatchingTextureLoader => f.write_str("No matching TextureLoader. Did you remove the default one?"), Self::NoMatchingTextureLoader => f.write_str("No matching TextureLoader. Did you remove the default one?"),
Self::NotSupported => f.write_str("Iagge schema or URI not supported by this loader"), Self::NotSupported => f.write_str("Image scheme or URI not supported by this loader"),
Self::Loading(message) => f.write_str(message), Self::Loading(message) => f.write_str(message),
} }

View File

@ -100,7 +100,10 @@ impl<'a> Image<'a> {
/// ///
/// See [`ImageSource::Bytes`]. /// See [`ImageSource::Bytes`].
pub fn from_bytes(uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) -> Self { pub fn from_bytes(uri: impl Into<Cow<'static, str>>, bytes: impl Into<Bytes>) -> Self {
Self::new(ImageSource::Bytes(uri.into(), bytes.into())) Self::new(ImageSource::Bytes {
uri: uri.into(),
bytes: bytes.into(),
})
} }
/// Texture options used when creating the texture. /// Texture options used when creating the texture.
@ -275,7 +278,7 @@ impl<'a> Image<'a> {
pub fn size(&self) -> Option<Vec2> { pub fn size(&self) -> Option<Vec2> {
match &self.source { match &self.source {
ImageSource::Texture(texture) => Some(texture.size), ImageSource::Texture(texture) => Some(texture.size),
ImageSource::Uri(_) | ImageSource::Bytes(_, _) => None, ImageSource::Uri(_) | ImageSource::Bytes { .. } => None,
} }
} }
@ -478,9 +481,10 @@ impl Default for ImageSize {
/// This is used by [`Image::new`] and [`Ui::image`]. /// This is used by [`Image::new`] and [`Ui::image`].
#[derive(Clone)] #[derive(Clone)]
pub enum ImageSource<'a> { pub enum ImageSource<'a> {
/// Load the image from a URI. /// Load the image from a URI, e.g. `https://example.com/image.png`.
///
/// This could be a `file://` path, `https://` url, `bytes://` identifier, or some other scheme.
/// ///
/// This could be a `file://` url, `http(s)?://` url, or a `bare` identifier.
/// How the URI will be turned into a texture for rendering purposes is /// How the URI will be turned into a texture for rendering purposes is
/// up to the registered loaders to handle. /// up to the registered loaders to handle.
/// ///
@ -495,8 +499,6 @@ pub enum ImageSource<'a> {
/// Load the image from some raw bytes. /// Load the image from some raw bytes.
/// ///
/// For better error messages, use the `bytes://` prefix for the URI.
///
/// The [`Bytes`] may be: /// The [`Bytes`] may be:
/// - `'static`, obtained from `include_bytes!` or similar /// - `'static`, obtained from `include_bytes!` or similar
/// - Anything that can be converted to `Arc<[u8]>` /// - Anything that can be converted to `Arc<[u8]>`
@ -506,13 +508,22 @@ pub enum ImageSource<'a> {
/// See also [`include_image`] for an easy way to load and display static images. /// See also [`include_image`] for an easy way to load and display static images.
/// ///
/// See [`crate::load`] for more information. /// See [`crate::load`] for more information.
Bytes(Cow<'static, str>, Bytes), Bytes {
/// The unique identifier for this image, e.g. `bytes://my_logo.png`.
///
/// You should use a proper extension (`.jpg`, `.png`, `.svg`, etc) for the image to load properly.
///
/// Use the `bytes://` scheme for the URI for better error messages.
uri: Cow<'static, str>,
bytes: Bytes,
},
} }
impl<'a> std::fmt::Debug for ImageSource<'a> { impl<'a> std::fmt::Debug for ImageSource<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
ImageSource::Bytes(uri, _) | ImageSource::Uri(uri) => uri.as_ref().fmt(f), ImageSource::Bytes { uri, .. } | ImageSource::Uri(uri) => uri.as_ref().fmt(f),
ImageSource::Texture(st) => st.id.fmt(f), ImageSource::Texture(st) => st.id.fmt(f),
} }
} }
@ -524,7 +535,7 @@ impl<'a> ImageSource<'a> {
pub fn texture_size(&self) -> Option<Vec2> { pub fn texture_size(&self) -> Option<Vec2> {
match self { match self {
ImageSource::Texture(texture) => Some(texture.size), ImageSource::Texture(texture) => Some(texture.size),
ImageSource::Uri(_) | ImageSource::Bytes(_, _) => None, ImageSource::Uri(_) | ImageSource::Bytes { .. } => None,
} }
} }
@ -539,7 +550,7 @@ impl<'a> ImageSource<'a> {
match self { match self {
Self::Texture(texture) => Ok(TexturePoll::Ready { texture }), Self::Texture(texture) => Ok(TexturePoll::Ready { texture }),
Self::Uri(uri) => ctx.try_load_texture(uri.as_ref(), texture_options, size_hint), Self::Uri(uri) => ctx.try_load_texture(uri.as_ref(), texture_options, size_hint),
Self::Bytes(uri, bytes) => { Self::Bytes { uri, bytes } => {
ctx.include_bytes(uri.clone(), bytes); ctx.include_bytes(uri.clone(), bytes);
ctx.try_load_texture(uri.as_ref(), texture_options, size_hint) ctx.try_load_texture(uri.as_ref(), texture_options, size_hint)
} }
@ -551,7 +562,7 @@ impl<'a> ImageSource<'a> {
/// This will return `None` for [`Self::Texture`]. /// This will return `None` for [`Self::Texture`].
pub fn uri(&self) -> Option<&str> { pub fn uri(&self) -> Option<&str> {
match self { match self {
ImageSource::Bytes(uri, _) | ImageSource::Uri(uri) => Some(uri), ImageSource::Bytes { uri, .. } | ImageSource::Uri(uri) => Some(uri),
ImageSource::Texture(_) => None, ImageSource::Texture(_) => None,
} }
} }
@ -644,21 +655,30 @@ impl<'a> From<Cow<'a, str>> for ImageSource<'a> {
impl<T: Into<Bytes>> From<(&'static str, T)> for ImageSource<'static> { impl<T: Into<Bytes>> From<(&'static str, T)> for ImageSource<'static> {
#[inline] #[inline]
fn from((uri, bytes): (&'static str, T)) -> Self { fn from((uri, bytes): (&'static str, T)) -> Self {
Self::Bytes(uri.into(), bytes.into()) Self::Bytes {
uri: uri.into(),
bytes: bytes.into(),
}
} }
} }
impl<T: Into<Bytes>> From<(Cow<'static, str>, T)> for ImageSource<'static> { impl<T: Into<Bytes>> From<(Cow<'static, str>, T)> for ImageSource<'static> {
#[inline] #[inline]
fn from((uri, bytes): (Cow<'static, str>, T)) -> Self { fn from((uri, bytes): (Cow<'static, str>, T)) -> Self {
Self::Bytes(uri, bytes.into()) Self::Bytes {
uri,
bytes: bytes.into(),
}
} }
} }
impl<T: Into<Bytes>> From<(String, T)> for ImageSource<'static> { impl<T: Into<Bytes>> From<(String, T)> for ImageSource<'static> {
#[inline] #[inline]
fn from((uri, bytes): (String, T)) -> Self { fn from((uri, bytes): (String, T)) -> Self {
Self::Bytes(uri.into(), bytes.into()) Self::Bytes {
uri: uri.into(),
bytes: bytes.into(),
}
} }
} }