summaryrefslogtreecommitdiffstats
path: root/web/src/widget
diff options
context:
space:
mode:
authorLibravatar Liam Murphy <liampm32@gmail.com>2021-03-21 14:36:06 +1100
committerLibravatar Liam Murphy <liampm32@gmail.com>2021-03-21 14:36:06 +1100
commit1d85b6e887761ae885bec3f0b5405bf902ef8b64 (patch)
tree5a1595e91a8f7f9c3fff91b0a1d5528249abef04 /web/src/widget
parent0333a8daff6db989adc6035a4c09df171a86f6fe (diff)
downloadiced-1d85b6e887761ae885bec3f0b5405bf902ef8b64.tar.gz
iced-1d85b6e887761ae885bec3f0b5405bf902ef8b64.tar.bz2
iced-1d85b6e887761ae885bec3f0b5405bf902ef8b64.zip
feat(web): Support in-memory image data
I had to create two methods which basically do the same thing, `from_memory` and `from_slice`, but `from_memory` takes ownership of the bytes to be compatible with `iced_native`. Also, `Data` is incompatible, because if I stored the bytes in `Data` and created a new object URL every render, it would have caused a memory leak because bumpalo doesn't call destructors and there'd be no way to call URL.revokeObjectUrl on it. It's also more efficient this way.
Diffstat (limited to 'web/src/widget')
-rw-r--r--web/src/widget/image.rs39
1 files changed, 39 insertions, 0 deletions
diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs
index 05c89ea5..545e7e28 100644
--- a/web/src/widget/image.rs
+++ b/web/src/widget/image.rs
@@ -2,11 +2,15 @@
use crate::{Bus, Css, Element, Hasher, Length, Widget};
use dodrio::bumpalo;
+use js_sys::Array;
+use js_sys::Uint8Array;
use std::{
hash::{Hash, Hasher as _},
path::PathBuf,
sync::Arc,
};
+use web_sys::Blob;
+use web_sys::Url;
/// A frame that displays an image while keeping aspect ratio.
///
@@ -75,6 +79,7 @@ impl<Message> Widget<Message> for Image {
let src = String::from_str_in(
match self.handle.data.as_ref() {
Data::Path(path) => path.to_str().unwrap_or(""),
+ Data::ObjectUrl(url) => &url,
},
bump,
)
@@ -122,6 +127,27 @@ impl Handle {
Self::from_data(Data::Path(path.into()))
}
+ /// Creates an image [`Handle`] containing the image data directly.
+ ///
+ /// NOTE: this unnecessarily takes ownership of the data to be compaticle with `iced_native`.
+ /// If you're only using `iced_web`, you should use `from_slice` instead.
+ pub fn from_memory(bytes: Vec<u8>) -> Handle {
+ Handle::from_slice(bytes.as_slice())
+ }
+
+ /// Creates an image [`Handle`] containing the image data directly.
+ pub fn from_slice(bytes: &[u8]) -> Handle {
+ // This copies the memory twice (once in Uint8Array::from and once in Blob::new),
+ // but unsafe code is needed not to do that and #[forbid(unsafe_code)] is on.
+ let blob = Blob::new_with_u8_array_sequence(&Array::of1(
+ &Uint8Array::from(bytes),
+ ))
+ .unwrap();
+ Self::from_data(Data::ObjectUrl(
+ Url::create_object_url_with_blob(&blob).unwrap(),
+ ))
+ }
+
fn from_data(data: Data) -> Handle {
let mut hasher = Hasher::default();
data.hash(&mut hasher);
@@ -160,12 +186,25 @@ impl From<&str> for Handle {
pub enum Data {
/// A remote image
Path(PathBuf),
+
+ /// An Object URL pointing to some image data.
+ ObjectUrl(String),
}
impl std::fmt::Debug for Data {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Data::Path(path) => write!(f, "Path({:?})", path),
+ Data::ObjectUrl(url) => write!(f, "ObjectUrl({:?})", url),
+ }
+ }
+}
+
+impl Drop for Data {
+ fn drop(&mut self) {
+ match self {
+ Data::ObjectUrl(url) => Url::revoke_object_url(&url).unwrap(),
+ _ => {}
}
}
}