Sfoglia il codice sorgente

feat(core): expose the image module (#9122)

* feat(core): expose the image module

* code review

* fix import

* fix

* fix codegen

* jsimage owned

* fmt

---------

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
Lucas Fernandes Nogueira 1 anno fa
parent
commit
ed48e2b3c7

+ 6 - 0
.changes/expose-js-image.md

@@ -0,0 +1,6 @@
+---
+"tauri": patch:breaking
+"tauri-codegen": patch:breaking
+---
+
+Expose `tauri::image` module to export the `JsImage` type and removed the `Image` root re-export.

+ 2 - 2
core/tauri-codegen/src/context.rs

@@ -493,7 +493,7 @@ fn ico_icon<P: AsRef<Path>>(
   })?;
 
   let icon_file_name = icon_file_name.to_str().unwrap();
-  let icon = quote!(#root::Image::new(include_bytes!(concat!(std::env!("OUT_DIR"), "/", #icon_file_name)), #width, #height));
+  let icon = quote!(#root::image::Image::new(include_bytes!(concat!(std::env!("OUT_DIR"), "/", #icon_file_name)), #width, #height));
   Ok(icon)
 }
 
@@ -551,7 +551,7 @@ fn png_icon<P: AsRef<Path>>(
   })?;
 
   let icon_file_name = icon_file_name.to_str().unwrap();
-  let icon = quote!(#root::Image::new(include_bytes!(concat!(std::env!("OUT_DIR"), "/", #icon_file_name)), #width, #height));
+  let icon = quote!(#root::image::Image::new(include_bytes!(concat!(std::env!("OUT_DIR"), "/", #icon_file_name)), #width, #height));
   Ok(icon)
 }
 

+ 3 - 2
core/tauri/src/app.rs

@@ -3,6 +3,7 @@
 // SPDX-License-Identifier: MIT
 
 use crate::{
+  image::Image,
   ipc::{
     channel::ChannelDataIpcQueue, CallbackFn, CommandArg, CommandItem, Invoke, InvokeError,
     InvokeHandler, InvokeResponder, InvokeResponse,
@@ -20,8 +21,8 @@ use crate::{
   utils::config::Config,
   utils::{assets::Assets, Env},
   webview::PageLoadPayload,
-  Context, DeviceEventFilter, EventLoopMessage, Image, Manager, Monitor, Runtime, Scopes,
-  StateManager, Theme, Webview, WebviewWindowBuilder, Window,
+  Context, DeviceEventFilter, EventLoopMessage, Manager, Monitor, Runtime, Scopes, StateManager,
+  Theme, Webview, WebviewWindowBuilder, Window,
 };
 
 #[cfg(desktop)]

+ 30 - 8
core/tauri/src/image/mod.rs

@@ -2,7 +2,9 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-pub mod plugin;
+//! Image types used by this crate and also referenced by the JavaScript API layer.
+
+pub(crate) mod plugin;
 
 use std::borrow::Cow;
 use std::io::{Error, ErrorKind};
@@ -186,21 +188,41 @@ impl TryFrom<Image<'_>> for tray_icon::Icon {
   }
 }
 
+/// An image type that accepts file paths, raw bytes, previously loaded images and image objects.
+/// This type is meant to be used along the [transformImage](https://beta.tauri.app/references/v2/js/image/namespaceimage/#transformimage) API.
+///
+/// # Stability
+///
+/// The stability of the variants are not guaranteed, and matching against them is not recommended.
+/// Use [`JsImage::into_img`] instead.
 #[derive(serde::Deserialize)]
 #[serde(untagged)]
-pub enum JsImage<'a> {
+#[non_exhaustive]
+pub enum JsImage {
+  /// A reference to a image in the filesystem.
+  #[non_exhaustive]
   Path(std::path::PathBuf),
-  Bytes(&'a [u8]),
+  /// Image from raw bytes.
+  #[non_exhaustive]
+  Bytes(Vec<u8>),
+  /// An image that was previously loaded with the API and is stored in the resource table.
+  #[non_exhaustive]
   Resource(ResourceId),
+  /// Raw RGBA definition of an image.
+  #[non_exhaustive]
   Rgba {
-    rgba: &'a [u8],
+    /// Image bytes.
+    rgba: Vec<u8>,
+    /// Image width.
     width: u32,
+    /// Image height.
     height: u32,
   },
 }
 
-impl<'a> JsImage<'a> {
-  pub fn into_img<R: Runtime, M: Manager<R>>(self, app: &M) -> crate::Result<Arc<Image<'a>>> {
+impl JsImage {
+  /// Converts this intermediate image format into an actual [`Image`].
+  pub fn into_img<R: Runtime, M: Manager<R>>(self, app: &M) -> crate::Result<Arc<Image<'_>>> {
     match self {
       Self::Resource(rid) => {
         let resources_table = app.resources_table();
@@ -210,13 +232,13 @@ impl<'a> JsImage<'a> {
       Self::Path(path) => Image::from_path(path).map(Arc::new).map_err(Into::into),
 
       #[cfg(any(feature = "image-ico", feature = "image-png"))]
-      Self::Bytes(bytes) => Image::from_bytes(bytes).map(Arc::new).map_err(Into::into),
+      Self::Bytes(bytes) => Image::from_bytes(&bytes).map(Arc::new).map_err(Into::into),
 
       Self::Rgba {
         rgba,
         width,
         height,
-      } => Ok(Arc::new(Image::new(rgba, width, height))),
+      } => Ok(Arc::new(Image::new_owned(rgba, width, height))),
 
       #[cfg(not(any(feature = "image-ico", feature = "image-png")))]
       _ => Err(

+ 1 - 1
core/tauri/src/image/plugin.rs

@@ -3,7 +3,7 @@
 // SPDX-License-Identifier: MIT
 
 use crate::plugin::{Builder, TauriPlugin};
-use crate::{command, AppHandle, Image, Manager, ResourceId, Runtime};
+use crate::{command, image::Image, AppHandle, Manager, ResourceId, Runtime};
 
 #[command(root = "crate")]
 fn new<R: Runtime>(

+ 8 - 9
core/tauri/src/lib.rs

@@ -94,7 +94,7 @@ mod vibrancy;
 pub mod webview;
 pub mod window;
 use tauri_runtime as runtime;
-mod image;
+pub mod image;
 #[cfg(target_os = "ios")]
 mod ios;
 #[cfg(desktop)]
@@ -212,7 +212,6 @@ pub use {
   self::app::{
     App, AppHandle, AssetResolver, Builder, CloseRequestApi, RunEvent, WebviewEvent, WindowEvent,
   },
-  self::image::Image,
   self::manager::Asset,
   self::runtime::{
     webview::WebviewAttributes,
@@ -346,10 +345,10 @@ pub fn dev() -> bool {
 pub struct Context<A: Assets> {
   pub(crate) config: Config,
   pub(crate) assets: Box<A>,
-  pub(crate) default_window_icon: Option<Image<'static>>,
+  pub(crate) default_window_icon: Option<image::Image<'static>>,
   pub(crate) app_icon: Option<Vec<u8>>,
   #[cfg(all(desktop, feature = "tray-icon"))]
-  pub(crate) tray_icon: Option<Image<'static>>,
+  pub(crate) tray_icon: Option<image::Image<'static>>,
   pub(crate) package_info: PackageInfo,
   pub(crate) _info_plist: (),
   pub(crate) pattern: Pattern,
@@ -399,13 +398,13 @@ impl<A: Assets> Context<A> {
 
   /// The default window icon Tauri should use when creating windows.
   #[inline(always)]
-  pub fn default_window_icon(&self) -> Option<&Image<'_>> {
+  pub fn default_window_icon(&self) -> Option<&image::Image<'_>> {
     self.default_window_icon.as_ref()
   }
 
   /// Set the default window icon Tauri should use when creating windows.
   #[inline(always)]
-  pub fn set_default_window_icon(&mut self, icon: Option<Image<'static>>) {
+  pub fn set_default_window_icon(&mut self, icon: Option<image::Image<'static>>) {
     self.default_window_icon = icon;
   }
 
@@ -413,7 +412,7 @@ impl<A: Assets> Context<A> {
   #[cfg(all(desktop, feature = "tray-icon"))]
   #[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "tray-icon"))))]
   #[inline(always)]
-  pub fn tray_icon(&self) -> Option<&Image<'_>> {
+  pub fn tray_icon(&self) -> Option<&image::Image<'_>> {
     self.tray_icon.as_ref()
   }
 
@@ -421,7 +420,7 @@ impl<A: Assets> Context<A> {
   #[cfg(all(desktop, feature = "tray-icon"))]
   #[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "tray-icon"))))]
   #[inline(always)]
-  pub fn set_tray_icon(&mut self, icon: Option<Image<'static>>) {
+  pub fn set_tray_icon(&mut self, icon: Option<image::Image<'static>>) {
     self.tray_icon = icon;
   }
 
@@ -460,7 +459,7 @@ impl<A: Assets> Context<A> {
   pub fn new(
     config: Config,
     assets: Box<A>,
-    default_window_icon: Option<Image<'static>>,
+    default_window_icon: Option<image::Image<'static>>,
     app_icon: Option<Vec<u8>>,
     package_info: PackageInfo,
     info_plist: (),

+ 2 - 1
core/tauri/src/manager/tray.rs

@@ -6,8 +6,9 @@ use std::{collections::HashMap, fmt, sync::Mutex};
 
 use crate::{
   app::GlobalTrayIconEventListener,
+  image::Image,
   tray::{TrayIcon, TrayIconId},
-  AppHandle, Image, Runtime,
+  AppHandle, Runtime,
 };
 
 pub struct TrayManager<R: Runtime> {

+ 2 - 2
core/tauri/src/manager/window.rs

@@ -19,8 +19,8 @@ use tauri_runtime::{
 };
 
 use crate::{
-  app::GlobalWindowEventListener, sealed::ManagerBase, AppHandle, EventLoopMessage, EventTarget,
-  Image, Manager, Runtime, Scopes, Window, WindowEvent,
+  app::GlobalWindowEventListener, image::Image, sealed::ManagerBase, AppHandle, EventLoopMessage,
+  EventTarget, Manager, Runtime, Scopes, Window, WindowEvent,
 };
 
 const WINDOW_RESIZED_EVENT: &str = "tauri://resize";

+ 2 - 1
core/tauri/src/menu/builders/icon.rs

@@ -3,8 +3,9 @@
 // SPDX-License-Identifier: MIT
 
 use crate::{
+  image::Image,
   menu::{IconMenuItem, MenuId, NativeIcon},
-  Image, Manager, Runtime,
+  Manager, Runtime,
 };
 
 /// A builder type for [`IconMenuItem`]

+ 2 - 2
core/tauri/src/menu/builders/menu.rs

@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-use crate::{menu::*, Image, Manager, Runtime};
+use crate::{image::Image, menu::*, Manager, Runtime};
 
 /// A builder type for [`Menu`]
 ///
@@ -13,7 +13,7 @@ use crate::{menu::*, Image, Manager, Runtime};
 /// tauri::Builder::default()
 ///   .setup(move |app| {
 ///     let handle = app.handle();
-///     # let icon1 = tauri::Image::new(&[], 0, 0);
+///     # let icon1 = tauri::image::Image::new(&[], 0, 0);
 ///     let menu = MenuBuilder::new(handle)
 ///       .item(&MenuItem::new(handle, "MenuItem 1", true, None::<&str>)?)
 ///       .items(&[

+ 2 - 2
core/tauri/src/menu/builders/submenu.rs

@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 // SPDX-License-Identifier: MIT
 
-use crate::{menu::*, Image, Manager, Runtime};
+use crate::{image::Image, menu::*, Manager, Runtime};
 
 /// A builder type for [`Submenu`]
 ///
@@ -13,7 +13,7 @@ use crate::{menu::*, Image, Manager, Runtime};
 /// tauri::Builder::default()
 ///   .setup(move |app| {
 ///     let handle = app.handle();
-///     # let icon1 = tauri::Image::new(&[], 0, 0);
+///     # let icon1 = tauri::image::Image::new(&[], 0, 0);
 ///     # let icon2 = icon1.clone();
 ///     let menu = Menu::new(handle)?;
 ///     let submenu = SubmenuBuilder::new(handle, "File")

+ 1 - 1
core/tauri/src/menu/icon.rs

@@ -8,7 +8,7 @@ use super::run_item_main_thread;
 use super::{IconMenuItem, NativeIcon};
 use crate::menu::IconMenuItemInner;
 use crate::run_main_thread;
-use crate::{menu::MenuId, AppHandle, Image, Manager, Runtime};
+use crate::{image::Image, menu::MenuId, AppHandle, Manager, Runtime};
 
 impl<R: Runtime> IconMenuItem<R> {
   /// Create a new menu item.

+ 1 - 1
core/tauri/src/menu/mod.rs

@@ -21,7 +21,7 @@ pub use builders::*;
 pub use menu::{HELP_SUBMENU_ID, WINDOW_SUBMENU_ID};
 use serde::{Deserialize, Serialize};
 
-use crate::{AppHandle, Image, Runtime};
+use crate::{image::Image, AppHandle, Runtime};
 pub use muda::MenuId;
 
 macro_rules! run_item_main_thread {

+ 32 - 43
core/tauri/src/menu/plugin.rs

@@ -34,7 +34,7 @@ pub(crate) enum ItemKind {
 
 #[derive(Deserialize)]
 #[serde(rename_all = "camelCase")]
-pub(crate) struct AboutMetadata<'a> {
+pub(crate) struct AboutMetadata {
   pub name: Option<String>,
   pub version: Option<String>,
   pub short_version: Option<String>,
@@ -45,15 +45,14 @@ pub(crate) struct AboutMetadata<'a> {
   pub website: Option<String>,
   pub website_label: Option<String>,
   pub credits: Option<String>,
-  #[serde(borrow)]
-  pub icon: Option<JsImage<'a>>,
+  pub icon: Option<JsImage>,
 }
 
-impl<'a> AboutMetadata<'a> {
+impl AboutMetadata {
   pub fn into_metdata<R: Runtime, M: Manager<R>>(
     self,
     app: &M,
-  ) -> crate::Result<super::AboutMetadata<'a>> {
+  ) -> crate::Result<super::AboutMetadata<'_>> {
     let icon = match self.icon {
       Some(i) => Some(i.into_img(app)?.as_ref().clone()),
       None => None,
@@ -77,7 +76,7 @@ impl<'a> AboutMetadata<'a> {
 
 #[allow(clippy::large_enum_variant)]
 #[derive(Deserialize)]
-enum Predefined<'a> {
+enum Predefined {
   Separator,
   Copy,
   Cut,
@@ -93,21 +92,19 @@ enum Predefined<'a> {
   ShowAll,
   CloseWindow,
   Quit,
-  #[serde(borrow)]
-  About(Option<AboutMetadata<'a>>),
+  About(Option<AboutMetadata>),
   Services,
 }
 
 #[derive(Deserialize)]
-struct SubmenuPayload<'a> {
+struct SubmenuPayload {
   id: Option<MenuId>,
   text: String,
   enabled: Option<bool>,
-  #[serde(borrow)]
-  items: Vec<MenuItemPayloadKind<'a>>,
+  items: Vec<MenuItemPayloadKind>,
 }
 
-impl<'a> SubmenuPayload<'a> {
+impl SubmenuPayload {
   pub fn create_item<R: Runtime>(
     self,
     webview: &Webview<R>,
@@ -171,25 +168,23 @@ impl CheckMenuItemPayload {
 
 #[derive(Deserialize)]
 #[serde(untagged)]
-enum Icon<'a> {
+enum Icon {
   Native(NativeIcon),
-  #[serde(borrow)]
-  Icon(JsImage<'a>),
+  Icon(JsImage),
 }
 
 #[derive(Deserialize)]
 #[serde(rename_all = "camelCase")]
-struct IconMenuItemPayload<'a> {
+struct IconMenuItemPayload {
   handler: Option<JavaScriptChannelId>,
   id: Option<MenuId>,
   text: String,
-  #[serde(borrow)]
-  icon: Icon<'a>,
+  icon: Icon,
   enabled: Option<bool>,
   accelerator: Option<String>,
 }
 
-impl<'a> IconMenuItemPayload<'a> {
+impl IconMenuItemPayload {
   pub fn create_item<R: Runtime>(self, webview: &Webview<R>) -> crate::Result<IconMenuItem<R>> {
     let mut builder = if let Some(id) = self.id {
       IconMenuItemBuilder::with_id(id, self.text)
@@ -263,13 +258,12 @@ impl MenuItemPayload {
 }
 
 #[derive(Deserialize)]
-struct PredefinedMenuItemPayload<'a> {
-  #[serde(borrow)]
-  item: Predefined<'a>,
+struct PredefinedMenuItemPayload {
+  item: Predefined,
   text: Option<String>,
 }
 
-impl<'a> PredefinedMenuItemPayload<'a> {
+impl PredefinedMenuItemPayload {
   pub fn create_item<R: Runtime>(
     self,
     webview: &Webview<R>,
@@ -304,19 +298,16 @@ impl<'a> PredefinedMenuItemPayload<'a> {
 
 #[derive(Deserialize)]
 #[serde(untagged)]
-enum MenuItemPayloadKind<'a> {
+enum MenuItemPayloadKind {
   ExistingItem((ResourceId, ItemKind)),
-  #[serde(borrow)]
-  Predefined(PredefinedMenuItemPayload<'a>),
+  Predefined(PredefinedMenuItemPayload),
   Check(CheckMenuItemPayload),
-  #[serde(borrow)]
-  Submenu(SubmenuPayload<'a>),
-  #[serde(borrow)]
-  Icon(IconMenuItemPayload<'a>),
+  Submenu(SubmenuPayload),
+  Icon(IconMenuItemPayload),
   MenuItem(MenuItemPayload),
 }
 
-impl<'a> MenuItemPayloadKind<'a> {
+impl MenuItemPayloadKind {
   pub fn with_item<T, R: Runtime, F: FnOnce(&dyn IsMenuItem<R>) -> crate::Result<T>>(
     self,
     webview: &Webview<R>,
@@ -338,18 +329,16 @@ impl<'a> MenuItemPayloadKind<'a> {
 
 #[derive(Deserialize, Default)]
 #[serde(rename_all = "camelCase")]
-struct NewOptions<'a> {
+struct NewOptions {
   id: Option<MenuId>,
   text: Option<String>,
   enabled: Option<bool>,
   checked: Option<bool>,
   accelerator: Option<String>,
-  #[serde(borrow, rename = "item")]
-  predefined_item: Option<Predefined<'a>>,
-  #[serde(borrow)]
-  icon: Option<Icon<'a>>,
-  #[serde(borrow)]
-  items: Option<Vec<MenuItemPayloadKind<'a>>>,
+  #[serde(rename = "item")]
+  predefined_item: Option<Predefined>,
+  icon: Option<Icon>,
+  items: Option<Vec<MenuItemPayloadKind>>,
 }
 
 #[command(root = "crate")]
@@ -357,7 +346,7 @@ fn new<R: Runtime>(
   app: AppHandle<R>,
   webview: Webview<R>,
   kind: ItemKind,
-  options: Option<NewOptions<'_>>,
+  options: Option<NewOptions>,
   channels: State<'_, MenuChannels>,
   handler: Channel,
 ) -> crate::Result<(ResourceId, MenuId)> {
@@ -465,7 +454,7 @@ fn append<R: Runtime>(
   webview: Webview<R>,
   rid: ResourceId,
   kind: ItemKind,
-  items: Vec<MenuItemPayloadKind<'_>>,
+  items: Vec<MenuItemPayloadKind>,
 ) -> crate::Result<()> {
   let resources_table = webview.resources_table();
   match kind {
@@ -492,7 +481,7 @@ fn prepend<R: Runtime>(
   webview: Webview<R>,
   rid: ResourceId,
   kind: ItemKind,
-  items: Vec<MenuItemPayloadKind<'_>>,
+  items: Vec<MenuItemPayloadKind>,
 ) -> crate::Result<()> {
   let resources_table = webview.resources_table();
   match kind {
@@ -519,7 +508,7 @@ fn insert<R: Runtime>(
   webview: Webview<R>,
   rid: ResourceId,
   kind: ItemKind,
-  items: Vec<MenuItemPayloadKind<'_>>,
+  items: Vec<MenuItemPayloadKind>,
   mut position: usize,
 ) -> crate::Result<()> {
   let resources_table = webview.resources_table();
@@ -846,7 +835,7 @@ fn set_checked<R: Runtime>(app: AppHandle<R>, rid: ResourceId, checked: bool) ->
 fn set_icon<R: Runtime>(
   app: AppHandle<R>,
   rid: ResourceId,
-  icon: Option<Icon<'_>>,
+  icon: Option<Icon>,
 ) -> crate::Result<()> {
   let resources_table = app.resources_table();
   let icon_item = resources_table.get::<IconMenuItem<R>>(rid)?;

+ 1 - 1
core/tauri/src/tray/mod.rs

@@ -12,7 +12,7 @@ use crate::app::{GlobalMenuEventListener, GlobalTrayIconEventListener};
 use crate::menu::ContextMenu;
 use crate::menu::MenuEvent;
 use crate::resources::Resource;
-use crate::{menu::run_item_main_thread, AppHandle, Image, Manager, Runtime};
+use crate::{image::Image, menu::run_item_main_thread, AppHandle, Manager, Runtime};
 use serde::Serialize;
 use std::path::Path;
 pub use tray_icon::TrayIconId;

+ 4 - 5
core/tauri/src/tray/plugin.rs

@@ -21,11 +21,10 @@ use super::TrayIcon;
 
 #[derive(Deserialize)]
 #[serde(rename_all = "camelCase")]
-struct TrayIconOptions<'a> {
+struct TrayIconOptions {
   id: Option<String>,
   menu: Option<(ResourceId, ItemKind)>,
-  #[serde(borrow)]
-  icon: Option<JsImage<'a>>,
+  icon: Option<JsImage>,
   tooltip: Option<String>,
   title: Option<String>,
   temp_dir_path: Option<PathBuf>,
@@ -36,7 +35,7 @@ struct TrayIconOptions<'a> {
 #[command(root = "crate")]
 fn new<R: Runtime>(
   app: AppHandle<R>,
-  options: TrayIconOptions<'_>,
+  options: TrayIconOptions,
   handler: Channel,
 ) -> crate::Result<(ResourceId, String)> {
   let mut builder = if let Some(id) = options.id {
@@ -94,7 +93,7 @@ fn new<R: Runtime>(
 fn set_icon<R: Runtime>(
   app: AppHandle<R>,
   rid: ResourceId,
-  icon: Option<JsImage<'_>>,
+  icon: Option<JsImage>,
 ) -> crate::Result<()> {
   let resources_table = app.resources_table();
   let tray = resources_table.get::<TrayIcon<R>>(rid)?;

+ 1 - 1
core/tauri/src/webview/webview_window.rs

@@ -13,6 +13,7 @@ use crate::{
 };
 #[cfg(desktop)]
 use crate::{
+  image::Image,
   menu::{ContextMenu, Menu},
   runtime::{
     window::{
@@ -21,7 +22,6 @@ use crate::{
     },
     UserAttentionType,
   },
-  Image,
 };
 use tauri_utils::config::{WebviewUrl, WindowConfig};
 use url::Url;

+ 2 - 1
core/tauri/src/window/mod.rs

@@ -33,12 +33,13 @@ use crate::{
 };
 #[cfg(desktop)]
 use crate::{
+  image::Image,
   menu::{ContextMenu, Menu, MenuId},
   runtime::{
     window::dpi::{Position, Size},
     UserAttentionType,
   },
-  CursorIcon, Image,
+  CursorIcon,
 };
 
 use serde::Serialize;

+ 1 - 1
core/tauri/src/window/plugin.rs

@@ -134,7 +134,7 @@ mod desktop_commands {
   pub async fn set_icon<R: Runtime>(
     window: Window<R>,
     label: Option<String>,
-    value: crate::image::JsImage<'_>,
+    value: crate::image::JsImage,
   ) -> crate::Result<()> {
     let window = get_window(window, label)?;
     window

+ 57 - 0
examples/api/src-tauri/Cargo.lock

@@ -3192,6 +3192,7 @@ dependencies = [
  "tokio",
  "tray-icon",
  "url",
+ "urlpattern",
  "uuid",
  "webkit2gtk",
  "webview2-com",
@@ -3343,6 +3344,7 @@ dependencies = [
  "phf 0.11.2",
  "proc-macro2",
  "quote",
+ "regex",
  "schemars",
  "semver",
  "serde",
@@ -3353,6 +3355,7 @@ dependencies = [
  "thiserror",
  "toml 0.8.2",
  "url",
+ "urlpattern",
  "walkdir",
 ]
 
@@ -3681,6 +3684,47 @@ version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
+[[package]]
+name = "unic-char-property"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
+dependencies = [
+ "unic-char-range",
+]
+
+[[package]]
+name = "unic-char-range"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
+
+[[package]]
+name = "unic-common"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
+
+[[package]]
+name = "unic-ucd-ident"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
+dependencies = [
+ "unic-char-property",
+ "unic-char-range",
+ "unic-ucd-version",
+]
+
+[[package]]
+name = "unic-ucd-version"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
+dependencies = [
+ "unic-common",
+]
+
 [[package]]
 name = "unicode-bidi"
 version = "0.3.15"
@@ -3730,6 +3774,19 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "urlpattern"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9bd5ff03aea02fa45b13a7980151fe45009af1980ba69f651ec367121a31609"
+dependencies = [
+ "derive_more",
+ "regex",
+ "serde",
+ "unic-ucd-ident",
+ "url",
+]
+
 [[package]]
 name = "utf-8"
 version = "0.7.6"

+ 2 - 2
examples/api/src-tauri/src/tray.rs

@@ -82,9 +82,9 @@ pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
       i @ "icon-1" | i @ "icon-2" => {
         if let Some(tray) = app.tray_by_id("tray-1") {
           let icon = if i == "icon-1" {
-            tauri::Image::from_bytes(include_bytes!("../../../.icons/icon.ico"))
+            tauri::image::Image::from_bytes(include_bytes!("../../../.icons/icon.ico"))
           } else {
-            tauri::Image::from_bytes(include_bytes!(
+            tauri::image::Image::from_bytes(include_bytes!(
               "../../../.icons/tray_icon_with_transparency.png"
             ))
           };

+ 3 - 7
examples/api/src-tauri/tauri-plugin-sample/permissions/schemas/schema.json

@@ -139,14 +139,10 @@
         },
         "platforms": {
           "description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
-          "default": [
-            "linux",
-            "macOS",
-            "windows",
-            "android",
-            "iOS"
+          "type": [
+            "array",
+            "null"
           ],
-          "type": "array",
           "items": {
             "$ref": "#/definitions/Target"
           }

+ 3 - 2
tooling/api/src/image.ts

@@ -117,9 +117,10 @@ export class Image extends Resource {
 }
 
 /**
- * Transforms image from various types into a type acceptable by Rust. Intended for internal use only.
+ * Transforms image from various types into a type acceptable by Rust.
  *
- * @ignore
+ * See [tauri::image::JsImage](https://docs.rs/tauri/2/tauri/image/enum.JsImage.html) for more information.
+ * Note the API signature is not stable and might change.
  */
 export function transformImage<T>(
   image: string | Image | Uint8Array | ArrayBuffer | number[] | null