mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-08-16 19:30:27 +03:00
refactor(core): use the image crate (#9132)
This commit is contained in:
parent
26f0f71a40
commit
db0a24a973
5
.changes/image-crate.md
Normal file
5
.changes/image-crate.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"tauri": patch:breaking
|
||||||
|
---
|
||||||
|
|
||||||
|
Use the image crate for `tauri::image::Image` and remove the `from_png_bytes` and `from_ico_bytes` APIs.
|
5
.changes/remove-from-format-image.md
Normal file
5
.changes/remove-from-format-image.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@tauri-apps/api": patch:breaking
|
||||||
|
---
|
||||||
|
|
||||||
|
Remove the `Image.fromPngBytes` and `Image.fromIcoBytes` APIs. Use `Image.fromBytes` instead.
|
5
Cargo.lock
generated
5
Cargo.lock
generated
@ -1591,6 +1591,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"png",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3610,8 +3611,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"http",
|
"http",
|
||||||
"http-range",
|
"http-range",
|
||||||
"ico",
|
"image",
|
||||||
"infer",
|
|
||||||
"jni",
|
"jni",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -3619,7 +3619,6 @@ dependencies = [
|
|||||||
"muda",
|
"muda",
|
||||||
"objc",
|
"objc",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"png",
|
|
||||||
"proptest",
|
"proptest",
|
||||||
"quickcheck",
|
"quickcheck",
|
||||||
"quickcheck_macros",
|
"quickcheck_macros",
|
||||||
|
@ -68,9 +68,7 @@ urlpattern = "0.2"
|
|||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
data-url = { version = "0.3", optional = true }
|
data-url = { version = "0.3", optional = true }
|
||||||
serialize-to-javascript = "=0.1.1"
|
serialize-to-javascript = "=0.1.1"
|
||||||
infer = { version = "0.15", optional = true }
|
image = { version = "0.24", default-features = false, optional = true }
|
||||||
png = { version = "0.17", optional = true }
|
|
||||||
ico = { version = "0.3.0", optional = true }
|
|
||||||
http-range = { version = "0.1.5", optional = true }
|
http-range = { version = "0.1.5", optional = true }
|
||||||
tracing = { version = "0.1", optional = true }
|
tracing = { version = "0.1", optional = true }
|
||||||
heck = "0.4"
|
heck = "0.4"
|
||||||
@ -154,8 +152,8 @@ webview-data-url = [ "data-url" ]
|
|||||||
protocol-asset = [ "http-range" ]
|
protocol-asset = [ "http-range" ]
|
||||||
config-json5 = [ "tauri-macros/config-json5" ]
|
config-json5 = [ "tauri-macros/config-json5" ]
|
||||||
config-toml = [ "tauri-macros/config-toml" ]
|
config-toml = [ "tauri-macros/config-toml" ]
|
||||||
image-ico = [ "ico", "infer" ]
|
image-ico = [ "image/ico" ]
|
||||||
image-png = [ "png", "infer" ]
|
image-png = [ "image/png" ]
|
||||||
macos-proxy = [ "tauri-runtime-wry/macos-proxy" ]
|
macos-proxy = [ "tauri-runtime-wry/macos-proxy" ]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
|
@ -142,8 +142,6 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
|
|||||||
&[
|
&[
|
||||||
("new", true),
|
("new", true),
|
||||||
("from_bytes", true),
|
("from_bytes", true),
|
||||||
("from_png_bytes", true),
|
|
||||||
("from_ico_bytes", true),
|
|
||||||
("from_path", true),
|
("from_path", true),
|
||||||
("rgba", true),
|
("rgba", true),
|
||||||
("width", true),
|
("width", true),
|
||||||
|
@ -2,12 +2,8 @@
|
|||||||
|------|-----|
|
|------|-----|
|
||||||
|`allow-from-bytes`|Enables the from_bytes command without any pre-configured scope.|
|
|`allow-from-bytes`|Enables the from_bytes command without any pre-configured scope.|
|
||||||
|`deny-from-bytes`|Denies the from_bytes command without any pre-configured scope.|
|
|`deny-from-bytes`|Denies the from_bytes command without any pre-configured scope.|
|
||||||
|`allow-from-ico-bytes`|Enables the from_ico_bytes command without any pre-configured scope.|
|
|
||||||
|`deny-from-ico-bytes`|Denies the from_ico_bytes command without any pre-configured scope.|
|
|
||||||
|`allow-from-path`|Enables the from_path command without any pre-configured scope.|
|
|`allow-from-path`|Enables the from_path command without any pre-configured scope.|
|
||||||
|`deny-from-path`|Denies the from_path command without any pre-configured scope.|
|
|`deny-from-path`|Denies the from_path command without any pre-configured scope.|
|
||||||
|`allow-from-png-bytes`|Enables the from_png_bytes command without any pre-configured scope.|
|
|
||||||
|`deny-from-png-bytes`|Denies the from_png_bytes command without any pre-configured scope.|
|
|
||||||
|`allow-height`|Enables the height command without any pre-configured scope.|
|
|`allow-height`|Enables the height command without any pre-configured scope.|
|
||||||
|`deny-height`|Denies the height command without any pre-configured scope.|
|
|`deny-height`|Denies the height command without any pre-configured scope.|
|
||||||
|`allow-new`|Enables the new command without any pre-configured scope.|
|
|`allow-new`|Enables the new command without any pre-configured scope.|
|
||||||
|
File diff suppressed because one or more lines are too long
@ -81,10 +81,10 @@ pub enum Error {
|
|||||||
/// Invalid glob pattern.
|
/// Invalid glob pattern.
|
||||||
#[error("invalid glob pattern: {0}")]
|
#[error("invalid glob pattern: {0}")]
|
||||||
GlobPattern(#[from] glob::PatternError),
|
GlobPattern(#[from] glob::PatternError),
|
||||||
/// Error decoding PNG image.
|
/// Image error.
|
||||||
#[cfg(feature = "image-png")]
|
#[cfg(any(feature = "image-png", feature = "image-ico"))]
|
||||||
#[error("failed to decode PNG: {0}")]
|
#[error("failed to process image: {0}")]
|
||||||
PngDecode(#[from] png::DecodingError),
|
Image(#[from] image::error::ImageError),
|
||||||
/// The Window's raw handle is invalid for the platform.
|
/// The Window's raw handle is invalid for the platform.
|
||||||
#[error("Unexpected `raw_window_handle` for the current platform")]
|
#[error("Unexpected `raw_window_handle` for the current platform")]
|
||||||
InvalidWindowHandle,
|
InvalidWindowHandle,
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
pub(crate) mod plugin;
|
pub(crate) mod plugin;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io::{Error, ErrorKind};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{Manager, Resource, ResourceId, Runtime};
|
use crate::{Manager, Resource, ResourceId, Runtime};
|
||||||
@ -45,80 +44,24 @@ impl<'a> Image<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new image using the provided png bytes.
|
|
||||||
#[cfg(feature = "image-png")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "image-png")))]
|
|
||||||
pub fn from_png_bytes(bytes: &[u8]) -> std::io::Result<Self> {
|
|
||||||
let decoder = png::Decoder::new(std::io::Cursor::new(bytes));
|
|
||||||
let mut reader = decoder.read_info()?;
|
|
||||||
let mut buffer = Vec::new();
|
|
||||||
while let Ok(Some(row)) = reader.next_row() {
|
|
||||||
buffer.extend(row.data());
|
|
||||||
}
|
|
||||||
Ok(Self {
|
|
||||||
rgba: Cow::Owned(buffer),
|
|
||||||
width: reader.info().width,
|
|
||||||
height: reader.info().height,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new image using the provided ico bytes.
|
|
||||||
#[cfg(feature = "image-ico")]
|
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "image-ico")))]
|
|
||||||
pub fn from_ico_bytes(bytes: &[u8]) -> std::io::Result<Self> {
|
|
||||||
let icon_dir = ico::IconDir::read(std::io::Cursor::new(&bytes))?;
|
|
||||||
let first = icon_dir.entries().first().ok_or_else(|| {
|
|
||||||
Error::new(
|
|
||||||
ErrorKind::NotFound,
|
|
||||||
"Couldn't find any icons inside provided ico bytes",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let rgba = first.decode()?.rgba_data().to_vec();
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
rgba: Cow::Owned(rgba),
|
|
||||||
width: first.width(),
|
|
||||||
height: first.height(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new image using the provided bytes.
|
/// Creates a new image using the provided bytes.
|
||||||
///
|
///
|
||||||
/// Only `ico` and `png` are supported (based on activated feature flag).
|
/// Only `ico` and `png` are supported (based on activated feature flag).
|
||||||
#[cfg(any(feature = "image-ico", feature = "image-png"))]
|
#[cfg(any(feature = "image-ico", feature = "image-png"))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "image-ico", feature = "image-png"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "image-ico", feature = "image-png"))))]
|
||||||
pub fn from_bytes(bytes: &[u8]) -> std::io::Result<Self> {
|
pub fn from_bytes(bytes: &[u8]) -> crate::Result<Self> {
|
||||||
let extension = infer::get(bytes)
|
use image::GenericImageView;
|
||||||
.expect("could not determine icon extension")
|
|
||||||
.extension();
|
|
||||||
|
|
||||||
match extension {
|
let img = image::load_from_memory(bytes)?;
|
||||||
#[cfg(feature = "image-ico")]
|
let pixels = img
|
||||||
"ico" => Self::from_ico_bytes(bytes),
|
.pixels()
|
||||||
#[cfg(feature = "image-png")]
|
.flat_map(|(_, _, pixel)| pixel.0)
|
||||||
"png" => Self::from_png_bytes(bytes),
|
.collect::<Vec<_>>();
|
||||||
_ => {
|
Ok(Self {
|
||||||
let supported = [
|
rgba: Cow::Owned(pixels),
|
||||||
#[cfg(feature = "image-png")]
|
width: img.width(),
|
||||||
"'png'",
|
height: img.height(),
|
||||||
#[cfg(feature = "image-ico")]
|
})
|
||||||
"'ico'",
|
|
||||||
];
|
|
||||||
|
|
||||||
Err(Error::new(
|
|
||||||
ErrorKind::InvalidInput,
|
|
||||||
format!(
|
|
||||||
"Unexpected image format, expected {}, found '{extension}'. Please check the `image-*` Cargo features on the tauri crate to see if Tauri has optional support for this format.",
|
|
||||||
if supported.is_empty() {
|
|
||||||
"''".to_string()
|
|
||||||
} else {
|
|
||||||
supported.join(" or ")
|
|
||||||
}
|
|
||||||
),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new image using the provided path.
|
/// Creates a new image using the provided path.
|
||||||
@ -126,7 +69,7 @@ impl<'a> Image<'a> {
|
|||||||
/// Only `ico` and `png` are supported (based on activated feature flag).
|
/// Only `ico` and `png` are supported (based on activated feature flag).
|
||||||
#[cfg(any(feature = "image-ico", feature = "image-png"))]
|
#[cfg(any(feature = "image-ico", feature = "image-png"))]
|
||||||
#[cfg_attr(docsrs, doc(cfg(any(feature = "image-ico", feature = "image-png"))))]
|
#[cfg_attr(docsrs, doc(cfg(any(feature = "image-ico", feature = "image-png"))))]
|
||||||
pub fn from_path<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<Self> {
|
pub fn from_path<P: AsRef<std::path::Path>>(path: P) -> crate::Result<Self> {
|
||||||
let bytes = std::fs::read(path)?;
|
let bytes = std::fs::read(path)?;
|
||||||
Self::from_bytes(&bytes)
|
Self::from_bytes(&bytes)
|
||||||
}
|
}
|
||||||
@ -242,8 +185,8 @@ impl JsImage {
|
|||||||
|
|
||||||
#[cfg(not(any(feature = "image-ico", feature = "image-png")))]
|
#[cfg(not(any(feature = "image-ico", feature = "image-png")))]
|
||||||
_ => Err(
|
_ => Err(
|
||||||
Error::new(
|
std::io::Error::new(
|
||||||
ErrorKind::InvalidInput,
|
std::io::ErrorKind::InvalidInput,
|
||||||
format!(
|
format!(
|
||||||
"expected RGBA image data, found {}",
|
"expected RGBA image data, found {}",
|
||||||
match self {
|
match self {
|
||||||
|
@ -33,36 +33,6 @@ fn from_bytes() -> std::result::Result<(), &'static str> {
|
|||||||
Err("from_bytes is only supported if the `image-ico` or `image-png` Cargo features are enabled")
|
Err("from_bytes is only supported if the `image-ico` or `image-png` Cargo features are enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "image-ico")]
|
|
||||||
#[command(root = "crate")]
|
|
||||||
fn from_ico_bytes<R: Runtime>(app: AppHandle<R>, bytes: Vec<u8>) -> crate::Result<ResourceId> {
|
|
||||||
let image = Image::from_ico_bytes(&bytes)?.to_owned();
|
|
||||||
let mut resources_table = app.resources_table();
|
|
||||||
let rid = resources_table.add(image);
|
|
||||||
Ok(rid)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "image-ico"))]
|
|
||||||
#[command(root = "crate")]
|
|
||||||
fn from_ico_bytes() -> std::result::Result<(), &'static str> {
|
|
||||||
Err("from_ico_bytes is only supported if the `image-ico` Cargo feature is enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "image-png")]
|
|
||||||
#[command(root = "crate")]
|
|
||||||
fn from_png_bytes<R: Runtime>(app: AppHandle<R>, bytes: Vec<u8>) -> crate::Result<ResourceId> {
|
|
||||||
let image = Image::from_png_bytes(&bytes)?.to_owned();
|
|
||||||
let mut resources_table = app.resources_table();
|
|
||||||
let rid = resources_table.add(image);
|
|
||||||
Ok(rid)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "image-png"))]
|
|
||||||
#[command(root = "crate")]
|
|
||||||
fn from_png_bytes() -> std::result::Result<(), &'static str> {
|
|
||||||
Err("from_png_bytes is only supported if the `image-ico` Cargo feature is enabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "image-ico", feature = "image-png"))]
|
#[cfg(any(feature = "image-ico", feature = "image-png"))]
|
||||||
#[command(root = "crate")]
|
#[command(root = "crate")]
|
||||||
fn from_path<R: Runtime>(app: AppHandle<R>, path: std::path::PathBuf) -> crate::Result<ResourceId> {
|
fn from_path<R: Runtime>(app: AppHandle<R>, path: std::path::PathBuf) -> crate::Result<ResourceId> {
|
||||||
@ -103,14 +73,7 @@ fn height<R: Runtime>(app: AppHandle<R>, rid: ResourceId) -> crate::Result<u32>
|
|||||||
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||||
Builder::new("image")
|
Builder::new("image")
|
||||||
.invoke_handler(crate::generate_handler![
|
.invoke_handler(crate::generate_handler![
|
||||||
new,
|
new, from_bytes, from_path, rgba, width, height
|
||||||
from_bytes,
|
|
||||||
from_ico_bytes,
|
|
||||||
from_png_bytes,
|
|
||||||
from_path,
|
|
||||||
rgba,
|
|
||||||
width,
|
|
||||||
height
|
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
5
examples/api/src-tauri/Cargo.lock
generated
5
examples/api/src-tauri/Cargo.lock
generated
@ -1516,6 +1516,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"png",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3165,8 +3166,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"http",
|
"http",
|
||||||
"http-range",
|
"http-range",
|
||||||
"ico",
|
"image",
|
||||||
"infer",
|
|
||||||
"jni",
|
"jni",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -3174,7 +3174,6 @@ dependencies = [
|
|||||||
"muda",
|
"muda",
|
||||||
"objc",
|
"objc",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"png",
|
|
||||||
"raw-window-handle 0.6.0",
|
"raw-window-handle 0.6.0",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -44,42 +44,6 @@ export class Image extends Resource {
|
|||||||
}).then((rid) => new Image(rid))
|
}).then((rid) => new Image(rid))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new image using the provided png bytes.
|
|
||||||
*
|
|
||||||
* Note that you need the `image-png` Cargo features to use this API.
|
|
||||||
* To enable it, change your Cargo.toml file:
|
|
||||||
* ```toml
|
|
||||||
* [dependencies]
|
|
||||||
* tauri = { version = "...", features = ["...", "image-png"] }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
static async fromPngBytes(
|
|
||||||
bytes: number[] | Uint8Array | ArrayBuffer
|
|
||||||
): Promise<Image> {
|
|
||||||
return invoke<number>('plugin:image|from_png_bytes', {
|
|
||||||
bytes: transformImage(bytes)
|
|
||||||
}).then((rid) => new Image(rid))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new image using the provided ico bytes.
|
|
||||||
*
|
|
||||||
* Note that you need the `image-ico` Cargo features to use this API.
|
|
||||||
* To enable it, change your Cargo.toml file:
|
|
||||||
* ```toml
|
|
||||||
* [dependencies]
|
|
||||||
* tauri = { version = "...", features = ["...", "image-ico"] }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
static async fromIcoBytes(
|
|
||||||
bytes: number[] | Uint8Array | ArrayBuffer
|
|
||||||
): Promise<Image> {
|
|
||||||
return invoke<number>('plugin:image|from_ico_bytes', {
|
|
||||||
bytes: transformImage(bytes)
|
|
||||||
}).then((rid) => new Image(rid))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new image using the provided path.
|
* Creates a new image using the provided path.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user