refactor(core): use the image crate (#9132)

This commit is contained in:
Lucas Fernandes Nogueira 2024-03-11 11:46:34 -03:00 committed by GitHub
parent 26f0f71a40
commit db0a24a973
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 38 additions and 168 deletions

5
.changes/image-crate.md Normal file
View 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.

View 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
View File

@ -1591,6 +1591,7 @@ dependencies = [
"byteorder",
"color_quant",
"num-traits",
"png",
]
[[package]]
@ -3610,8 +3611,7 @@ dependencies = [
"heck",
"http",
"http-range",
"ico",
"infer",
"image",
"jni",
"libc",
"log",
@ -3619,7 +3619,6 @@ dependencies = [
"muda",
"objc",
"percent-encoding",
"png",
"proptest",
"quickcheck",
"quickcheck_macros",

View File

@ -68,9 +68,7 @@ urlpattern = "0.2"
mime = "0.3"
data-url = { version = "0.3", optional = true }
serialize-to-javascript = "=0.1.1"
infer = { version = "0.15", optional = true }
png = { version = "0.17", optional = true }
ico = { version = "0.3.0", optional = true }
image = { version = "0.24", default-features = false, optional = true }
http-range = { version = "0.1.5", optional = true }
tracing = { version = "0.1", optional = true }
heck = "0.4"
@ -154,8 +152,8 @@ webview-data-url = [ "data-url" ]
protocol-asset = [ "http-range" ]
config-json5 = [ "tauri-macros/config-json5" ]
config-toml = [ "tauri-macros/config-toml" ]
image-ico = [ "ico", "infer" ]
image-png = [ "png", "infer" ]
image-ico = [ "image/ico" ]
image-png = [ "image/png" ]
macos-proxy = [ "tauri-runtime-wry/macos-proxy" ]
[[example]]

View File

@ -142,8 +142,6 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
&[
("new", true),
("from_bytes", true),
("from_png_bytes", true),
("from_ico_bytes", true),
("from_path", true),
("rgba", true),
("width", true),

View File

@ -2,12 +2,8 @@
|------|-----|
|`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.|
|`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.|
|`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.|
|`deny-height`|Denies the height 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

View File

@ -81,10 +81,10 @@ pub enum Error {
/// Invalid glob pattern.
#[error("invalid glob pattern: {0}")]
GlobPattern(#[from] glob::PatternError),
/// Error decoding PNG image.
#[cfg(feature = "image-png")]
#[error("failed to decode PNG: {0}")]
PngDecode(#[from] png::DecodingError),
/// Image error.
#[cfg(any(feature = "image-png", feature = "image-ico"))]
#[error("failed to process image: {0}")]
Image(#[from] image::error::ImageError),
/// The Window's raw handle is invalid for the platform.
#[error("Unexpected `raw_window_handle` for the current platform")]
InvalidWindowHandle,

View File

@ -7,7 +7,6 @@
pub(crate) mod plugin;
use std::borrow::Cow;
use std::io::{Error, ErrorKind};
use std::sync::Arc;
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.
///
/// Only `ico` and `png` are supported (based on activated feature flag).
#[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> {
let extension = infer::get(bytes)
.expect("could not determine icon extension")
.extension();
pub fn from_bytes(bytes: &[u8]) -> crate::Result<Self> {
use image::GenericImageView;
match extension {
#[cfg(feature = "image-ico")]
"ico" => Self::from_ico_bytes(bytes),
#[cfg(feature = "image-png")]
"png" => Self::from_png_bytes(bytes),
_ => {
let supported = [
#[cfg(feature = "image-png")]
"'png'",
#[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 ")
}
),
))
}
}
let img = image::load_from_memory(bytes)?;
let pixels = img
.pixels()
.flat_map(|(_, _, pixel)| pixel.0)
.collect::<Vec<_>>();
Ok(Self {
rgba: Cow::Owned(pixels),
width: img.width(),
height: img.height(),
})
}
/// 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).
#[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)?;
Self::from_bytes(&bytes)
}
@ -242,8 +185,8 @@ impl JsImage {
#[cfg(not(any(feature = "image-ico", feature = "image-png")))]
_ => Err(
Error::new(
ErrorKind::InvalidInput,
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"expected RGBA image data, found {}",
match self {

View File

@ -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")
}
#[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"))]
#[command(root = "crate")]
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> {
Builder::new("image")
.invoke_handler(crate::generate_handler![
new,
from_bytes,
from_ico_bytes,
from_png_bytes,
from_path,
rgba,
width,
height
new, from_bytes, from_path, rgba, width, height
])
.build()
}

View File

@ -1516,6 +1516,7 @@ dependencies = [
"byteorder",
"color_quant",
"num-traits",
"png",
]
[[package]]
@ -3165,8 +3166,7 @@ dependencies = [
"heck",
"http",
"http-range",
"ico",
"infer",
"image",
"jni",
"libc",
"log",
@ -3174,7 +3174,6 @@ dependencies = [
"muda",
"objc",
"percent-encoding",
"png",
"raw-window-handle 0.6.0",
"reqwest",
"serde",

View File

@ -44,42 +44,6 @@ export class Image extends Resource {
}).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.
*