Skip to content

Commit db0a24a

Browse files
authored
refactor(core): use the image crate (#9132)
1 parent 26f0f71 commit db0a24a

File tree

12 files changed

+39
-169
lines changed

12 files changed

+39
-169
lines changed

.changes/image-crate.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": patch:breaking
3+
---
4+
5+
Use the image crate for `tauri::image::Image` and remove the `from_png_bytes` and `from_ico_bytes` APIs.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tauri-apps/api": patch:breaking
3+
---
4+
5+
Remove the `Image.fromPngBytes` and `Image.fromIcoBytes` APIs. Use `Image.fromBytes` instead.

Cargo.lock

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/tauri/Cargo.toml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ urlpattern = "0.2"
6868
mime = "0.3"
6969
data-url = { version = "0.3", optional = true }
7070
serialize-to-javascript = "=0.1.1"
71-
infer = { version = "0.15", optional = true }
72-
png = { version = "0.17", optional = true }
73-
ico = { version = "0.3.0", optional = true }
71+
image = { version = "0.24", default-features = false, optional = true }
7472
http-range = { version = "0.1.5", optional = true }
7573
tracing = { version = "0.1", optional = true }
7674
heck = "0.4"
@@ -154,8 +152,8 @@ webview-data-url = [ "data-url" ]
154152
protocol-asset = [ "http-range" ]
155153
config-json5 = [ "tauri-macros/config-json5" ]
156154
config-toml = [ "tauri-macros/config-toml" ]
157-
image-ico = [ "ico", "infer" ]
158-
image-png = [ "png", "infer" ]
155+
image-ico = [ "image/ico" ]
156+
image-png = [ "image/png" ]
159157
macos-proxy = [ "tauri-runtime-wry/macos-proxy" ]
160158

161159
[[example]]

core/tauri/build.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,6 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
142142
&[
143143
("new", true),
144144
("from_bytes", true),
145-
("from_png_bytes", true),
146-
("from_ico_bytes", true),
147145
("from_path", true),
148146
("rgba", true),
149147
("width", true),

core/tauri/permissions/image/autogenerated/reference.md

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,8 @@
22
|------|-----|
33
|`allow-from-bytes`|Enables the from_bytes command without any pre-configured scope.|
44
|`deny-from-bytes`|Denies the from_bytes command without any pre-configured scope.|
5-
|`allow-from-ico-bytes`|Enables the from_ico_bytes command without any pre-configured scope.|
6-
|`deny-from-ico-bytes`|Denies the from_ico_bytes command without any pre-configured scope.|
75
|`allow-from-path`|Enables the from_path command without any pre-configured scope.|
86
|`deny-from-path`|Denies the from_path command without any pre-configured scope.|
9-
|`allow-from-png-bytes`|Enables the from_png_bytes command without any pre-configured scope.|
10-
|`deny-from-png-bytes`|Denies the from_png_bytes command without any pre-configured scope.|
117
|`allow-height`|Enables the height command without any pre-configured scope.|
128
|`deny-height`|Denies the height command without any pre-configured scope.|
139
|`allow-new`|Enables the new command without any pre-configured scope.|

core/tauri/scripts/bundle.global.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/tauri/src/error.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ pub enum Error {
8181
/// Invalid glob pattern.
8282
#[error("invalid glob pattern: {0}")]
8383
GlobPattern(#[from] glob::PatternError),
84-
/// Error decoding PNG image.
85-
#[cfg(feature = "image-png")]
86-
#[error("failed to decode PNG: {0}")]
87-
PngDecode(#[from] png::DecodingError),
84+
/// Image error.
85+
#[cfg(any(feature = "image-png", feature = "image-ico"))]
86+
#[error("failed to process image: {0}")]
87+
Image(#[from] image::error::ImageError),
8888
/// The Window's raw handle is invalid for the platform.
8989
#[error("Unexpected `raw_window_handle` for the current platform")]
9090
InvalidWindowHandle,

core/tauri/src/image/mod.rs

Lines changed: 16 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
pub(crate) mod plugin;
88

99
use std::borrow::Cow;
10-
use std::io::{Error, ErrorKind};
1110
use std::sync::Arc;
1211

1312
use crate::{Manager, Resource, ResourceId, Runtime};
@@ -45,88 +44,32 @@ impl<'a> Image<'a> {
4544
}
4645
}
4746

48-
/// Creates a new image using the provided png bytes.
49-
#[cfg(feature = "image-png")]
50-
#[cfg_attr(docsrs, doc(cfg(feature = "image-png")))]
51-
pub fn from_png_bytes(bytes: &[u8]) -> std::io::Result<Self> {
52-
let decoder = png::Decoder::new(std::io::Cursor::new(bytes));
53-
let mut reader = decoder.read_info()?;
54-
let mut buffer = Vec::new();
55-
while let Ok(Some(row)) = reader.next_row() {
56-
buffer.extend(row.data());
57-
}
58-
Ok(Self {
59-
rgba: Cow::Owned(buffer),
60-
width: reader.info().width,
61-
height: reader.info().height,
62-
})
63-
}
64-
65-
/// Creates a new image using the provided ico bytes.
66-
#[cfg(feature = "image-ico")]
67-
#[cfg_attr(docsrs, doc(cfg(feature = "image-ico")))]
68-
pub fn from_ico_bytes(bytes: &[u8]) -> std::io::Result<Self> {
69-
let icon_dir = ico::IconDir::read(std::io::Cursor::new(&bytes))?;
70-
let first = icon_dir.entries().first().ok_or_else(|| {
71-
Error::new(
72-
ErrorKind::NotFound,
73-
"Couldn't find any icons inside provided ico bytes",
74-
)
75-
})?;
76-
77-
let rgba = first.decode()?.rgba_data().to_vec();
78-
79-
Ok(Self {
80-
rgba: Cow::Owned(rgba),
81-
width: first.width(),
82-
height: first.height(),
83-
})
84-
}
85-
8647
/// Creates a new image using the provided bytes.
8748
///
8849
/// Only `ico` and `png` are supported (based on activated feature flag).
8950
#[cfg(any(feature = "image-ico", feature = "image-png"))]
9051
#[cfg_attr(docsrs, doc(cfg(any(feature = "image-ico", feature = "image-png"))))]
91-
pub fn from_bytes(bytes: &[u8]) -> std::io::Result<Self> {
92-
let extension = infer::get(bytes)
93-
.expect("could not determine icon extension")
94-
.extension();
95-
96-
match extension {
97-
#[cfg(feature = "image-ico")]
98-
"ico" => Self::from_ico_bytes(bytes),
99-
#[cfg(feature = "image-png")]
100-
"png" => Self::from_png_bytes(bytes),
101-
_ => {
102-
let supported = [
103-
#[cfg(feature = "image-png")]
104-
"'png'",
105-
#[cfg(feature = "image-ico")]
106-
"'ico'",
107-
];
108-
109-
Err(Error::new(
110-
ErrorKind::InvalidInput,
111-
format!(
112-
"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.",
113-
if supported.is_empty() {
114-
"''".to_string()
115-
} else {
116-
supported.join(" or ")
117-
}
118-
),
119-
))
120-
}
121-
}
52+
pub fn from_bytes(bytes: &[u8]) -> crate::Result<Self> {
53+
use image::GenericImageView;
54+
55+
let img = image::load_from_memory(bytes)?;
56+
let pixels = img
57+
.pixels()
58+
.flat_map(|(_, _, pixel)| pixel.0)
59+
.collect::<Vec<_>>();
60+
Ok(Self {
61+
rgba: Cow::Owned(pixels),
62+
width: img.width(),
63+
height: img.height(),
64+
})
12265
}
12366

12467
/// Creates a new image using the provided path.
12568
///
12669
/// Only `ico` and `png` are supported (based on activated feature flag).
12770
#[cfg(any(feature = "image-ico", feature = "image-png"))]
12871
#[cfg_attr(docsrs, doc(cfg(any(feature = "image-ico", feature = "image-png"))))]
129-
pub fn from_path<P: AsRef<std::path::Path>>(path: P) -> std::io::Result<Self> {
72+
pub fn from_path<P: AsRef<std::path::Path>>(path: P) -> crate::Result<Self> {
13073
let bytes = std::fs::read(path)?;
13174
Self::from_bytes(&bytes)
13275
}
@@ -242,8 +185,8 @@ impl JsImage {
242185

243186
#[cfg(not(any(feature = "image-ico", feature = "image-png")))]
244187
_ => Err(
245-
Error::new(
246-
ErrorKind::InvalidInput,
188+
std::io::Error::new(
189+
std::io::ErrorKind::InvalidInput,
247190
format!(
248191
"expected RGBA image data, found {}",
249192
match self {

core/tauri/src/image/plugin.rs

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,36 +33,6 @@ fn from_bytes() -> std::result::Result<(), &'static str> {
3333
Err("from_bytes is only supported if the `image-ico` or `image-png` Cargo features are enabled")
3434
}
3535

36-
#[cfg(feature = "image-ico")]
37-
#[command(root = "crate")]
38-
fn from_ico_bytes<R: Runtime>(app: AppHandle<R>, bytes: Vec<u8>) -> crate::Result<ResourceId> {
39-
let image = Image::from_ico_bytes(&bytes)?.to_owned();
40-
let mut resources_table = app.resources_table();
41-
let rid = resources_table.add(image);
42-
Ok(rid)
43-
}
44-
45-
#[cfg(not(feature = "image-ico"))]
46-
#[command(root = "crate")]
47-
fn from_ico_bytes() -> std::result::Result<(), &'static str> {
48-
Err("from_ico_bytes is only supported if the `image-ico` Cargo feature is enabled")
49-
}
50-
51-
#[cfg(feature = "image-png")]
52-
#[command(root = "crate")]
53-
fn from_png_bytes<R: Runtime>(app: AppHandle<R>, bytes: Vec<u8>) -> crate::Result<ResourceId> {
54-
let image = Image::from_png_bytes(&bytes)?.to_owned();
55-
let mut resources_table = app.resources_table();
56-
let rid = resources_table.add(image);
57-
Ok(rid)
58-
}
59-
60-
#[cfg(not(feature = "image-png"))]
61-
#[command(root = "crate")]
62-
fn from_png_bytes() -> std::result::Result<(), &'static str> {
63-
Err("from_png_bytes is only supported if the `image-ico` Cargo feature is enabled")
64-
}
65-
6636
#[cfg(any(feature = "image-ico", feature = "image-png"))]
6737
#[command(root = "crate")]
6838
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>
10373
pub fn init<R: Runtime>() -> TauriPlugin<R> {
10474
Builder::new("image")
10575
.invoke_handler(crate::generate_handler![
106-
new,
107-
from_bytes,
108-
from_ico_bytes,
109-
from_png_bytes,
110-
from_path,
111-
rgba,
112-
width,
113-
height
76+
new, from_bytes, from_path, rgba, width, height
11477
])
11578
.build()
11679
}

0 commit comments

Comments
 (0)