mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 14:20:04 -04:00
eframe: gate web clipboard image copy behind web_clipboard_image feature
The wasm path of `set_clipboard_image` is the only consumer of the `image` crate inside eframe; `image`'s decoders / color-management code add ~600 KB compressed to a wasm bundle even when only `png` is requested (image-webp / moxcms / pxfm get pulled in regardless). Make the dep optional behind a new `web_clipboard_image` feature (default-on, so this is source-compatible for everyone except those who explicitly want the smaller bundle). Apps that opt out get a `log::warn!` if a CopyImage command ever fires.
This commit is contained in:
@@ -29,12 +29,18 @@ default = [
|
|||||||
"accesskit",
|
"accesskit",
|
||||||
"default_fonts",
|
"default_fonts",
|
||||||
"wayland", # Required for Linux support (including CI!)
|
"wayland", # Required for Linux support (including CI!)
|
||||||
|
"web_clipboard_image",
|
||||||
"web_screen_reader",
|
"web_screen_reader",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit/default",
|
"winit/default",
|
||||||
"x11",
|
"x11",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
## Enable PNG-encoding `egui::ColorImage`s for the web clipboard via the
|
||||||
|
## [`image`](https://docs.rs/image) crate. Disable on the web to drop the
|
||||||
|
## image (and image-webp / moxcms / ...) crates from the wasm bundle.
|
||||||
|
web_clipboard_image = ["dep:image"]
|
||||||
|
|
||||||
## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/).
|
## Enable platform accessibility API implementations through [AccessKit](https://accesskit.dev/).
|
||||||
accesskit = ["egui-winit/accesskit"]
|
accesskit = ["egui-winit/accesskit"]
|
||||||
|
|
||||||
@@ -195,7 +201,10 @@ windows-sys = { workspace = true, features = [
|
|||||||
# web:
|
# web:
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
bytemuck.workspace = true
|
bytemuck.workspace = true
|
||||||
image = { workspace = true, features = ["png"] } # For copying images
|
# `image` is only needed for the "copy image to clipboard" path on the web.
|
||||||
|
# Behind `web_clipboard_image` (default-on) so apps that don't care can drop
|
||||||
|
# the image crate (and ~600 KB of png/webp/moxcms compressed code with it).
|
||||||
|
image = { workspace = true, features = ["png"], optional = true }
|
||||||
js-sys.workspace = true
|
js-sys.workspace = true
|
||||||
percent-encoding.workspace = true
|
percent-encoding.workspace = true
|
||||||
wasm-bindgen.workspace = true
|
wasm-bindgen.workspace = true
|
||||||
|
|||||||
@@ -385,7 +385,16 @@ impl AppRunner {
|
|||||||
super::set_clipboard_text(&text);
|
super::set_clipboard_text(&text);
|
||||||
}
|
}
|
||||||
egui::OutputCommand::CopyImage(image) => {
|
egui::OutputCommand::CopyImage(image) => {
|
||||||
|
#[cfg(feature = "web_clipboard_image")]
|
||||||
super::set_clipboard_image(&image);
|
super::set_clipboard_image(&image);
|
||||||
|
#[cfg(not(feature = "web_clipboard_image"))]
|
||||||
|
{
|
||||||
|
let _ = image;
|
||||||
|
log::warn!(
|
||||||
|
"CopyImage requested but eframe was built without the \
|
||||||
|
`web_clipboard_image` feature; ignoring."
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
egui::OutputCommand::OpenUrl(open_url) => {
|
egui::OutputCommand::OpenUrl(open_url) => {
|
||||||
super::open_url(&open_url.url, open_url.new_tab);
|
super::open_url(&open_url.url, open_url.new_tab);
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ fn set_clipboard_text(s: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set the clipboard image.
|
/// Set the clipboard image.
|
||||||
|
#[cfg(feature = "web_clipboard_image")]
|
||||||
fn set_clipboard_image(image: &egui::ColorImage) {
|
fn set_clipboard_image(image: &egui::ColorImage) {
|
||||||
if let Some(window) = web_sys::window() {
|
if let Some(window) = web_sys::window() {
|
||||||
if !window.is_secure_context() {
|
if !window.is_secure_context() {
|
||||||
@@ -250,6 +251,7 @@ fn set_clipboard_image(image: &egui::ColorImage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "web_clipboard_image")]
|
||||||
fn to_image(image: &egui::ColorImage) -> Result<image::RgbaImage, String> {
|
fn to_image(image: &egui::ColorImage) -> Result<image::RgbaImage, String> {
|
||||||
profiling::function_scope!();
|
profiling::function_scope!();
|
||||||
image::RgbaImage::from_raw(
|
image::RgbaImage::from_raw(
|
||||||
@@ -260,6 +262,7 @@ fn to_image(image: &egui::ColorImage) -> Result<image::RgbaImage, String> {
|
|||||||
.ok_or_else(|| "Invalid IconData".to_owned())
|
.ok_or_else(|| "Invalid IconData".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "web_clipboard_image")]
|
||||||
fn to_png_bytes(image: &image::RgbaImage) -> Result<Vec<u8>, String> {
|
fn to_png_bytes(image: &image::RgbaImage) -> Result<Vec<u8>, String> {
|
||||||
profiling::function_scope!();
|
profiling::function_scope!();
|
||||||
let mut png_bytes: Vec<u8> = Vec::new();
|
let mut png_bytes: Vec<u8> = Vec::new();
|
||||||
@@ -272,6 +275,7 @@ fn to_png_bytes(image: &image::RgbaImage) -> Result<Vec<u8>, String> {
|
|||||||
Ok(png_bytes)
|
Ok(png_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "web_clipboard_image")]
|
||||||
fn create_clipboard_item(mime: &str, bytes: &[u8]) -> Result<web_sys::ClipboardItem, JsValue> {
|
fn create_clipboard_item(mime: &str, bytes: &[u8]) -> Result<web_sys::ClipboardItem, JsValue> {
|
||||||
let array = js_sys::Uint8Array::from(bytes);
|
let array = js_sys::Uint8Array::from(bytes);
|
||||||
let blob_parts = js_sys::Array::new();
|
let blob_parts = js_sys::Array::new();
|
||||||
|
|||||||
Reference in New Issue
Block a user