mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-07-10 16:27:05 +02:00
inline notify-rust [skip ci]
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
#[cfg(feature = "dbus")]
|
||||
use dbus::arg::messageitem::{MessageItem, MessageItemArray};
|
||||
pub use image::DynamicImage;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryFrom;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::miniver::Version;
|
||||
|
||||
mod constants {
|
||||
pub const IMAGE_DATA: &str = "image-data";
|
||||
pub const IMAGE_DATA_1_1: &str = "image_data";
|
||||
pub const IMAGE_DATA_1_0: &str = "icon_data";
|
||||
}
|
||||
|
||||
/// Image representation for images. Send via `Notification::image_data()`
|
||||
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
|
||||
pub struct Image {
|
||||
width: i32,
|
||||
height: i32,
|
||||
rowstride: i32,
|
||||
alpha: bool,
|
||||
bits_per_sample: i32,
|
||||
channels: i32,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
fn from_raw_data(
|
||||
width: i32,
|
||||
height: i32,
|
||||
data: Vec<u8>,
|
||||
channels: i32,
|
||||
bits_per_sample: i32,
|
||||
alpha: bool,
|
||||
) -> Result<Self, ImageError> {
|
||||
const MAX_SIZE: i32 = 0x0fff_ffff;
|
||||
if width > MAX_SIZE || height > MAX_SIZE {
|
||||
return Err(ImageError::TooBig);
|
||||
}
|
||||
|
||||
if data.len() != (width * height * channels) as usize {
|
||||
Err(ImageError::WrongDataSize)
|
||||
} else {
|
||||
Ok(Self {
|
||||
width,
|
||||
height,
|
||||
bits_per_sample,
|
||||
channels,
|
||||
data,
|
||||
rowstride: width * channels,
|
||||
alpha,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an image from a raw vector of bytes
|
||||
pub fn from_rgb(width: i32, height: i32, data: Vec<u8>) -> Result<Self, ImageError> {
|
||||
let channels = 3i32;
|
||||
let bits_per_sample = 8;
|
||||
Self::from_raw_data(width, height, data, channels, bits_per_sample, false)
|
||||
}
|
||||
|
||||
/// Creates an image from a raw vector of bytes with alpha
|
||||
pub fn from_rgba(width: i32, height: i32, data: Vec<u8>) -> Result<Self, ImageError> {
|
||||
let channels = 4i32;
|
||||
let bits_per_sample = 8;
|
||||
Self::from_raw_data(width, height, data, channels, bits_per_sample, true)
|
||||
}
|
||||
|
||||
/// Attempts to open the given path as image
|
||||
pub fn open<T: AsRef<Path> + Sized>(path: T) -> Result<Self, ImageError> {
|
||||
let dyn_img = image::open(&path).map_err(ImageError::CantOpen)?;
|
||||
Image::try_from(dyn_img)
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "images", feature = "zbus"))]
|
||||
pub(crate) fn to_tuple(&self) -> (i32, i32, i32, bool, i32, i32, Vec<u8>) {
|
||||
(
|
||||
self.width,
|
||||
self.height,
|
||||
self.rowstride,
|
||||
self.alpha,
|
||||
self.bits_per_sample,
|
||||
self.channels,
|
||||
self.data.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<DynamicImage> for Image {
|
||||
type Error = ImageError;
|
||||
|
||||
fn try_from(dyn_img: DynamicImage) -> Result<Self, Self::Error> {
|
||||
match dyn_img {
|
||||
DynamicImage::ImageRgb8(img) => Self::try_from(img),
|
||||
DynamicImage::ImageRgba8(img) => Self::try_from(img),
|
||||
_ => Err(ImageError::CantConvert),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<image::RgbImage> for Image {
|
||||
type Error = ImageError;
|
||||
|
||||
fn try_from(img: image::RgbImage) -> Result<Self, Self::Error> {
|
||||
let (width, height) = img.dimensions();
|
||||
let image_data = img.into_raw();
|
||||
Image::from_rgb(width as i32, height as i32, image_data)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<image::RgbaImage> for Image {
|
||||
type Error = ImageError;
|
||||
|
||||
fn try_from(img: image::RgbaImage) -> Result<Self, Self::Error> {
|
||||
let (width, height) = img.dimensions();
|
||||
let image_data = img.into_raw();
|
||||
Image::from_rgba(width as i32, height as i32, image_data)
|
||||
}
|
||||
}
|
||||
|
||||
/// Errors that can occur when creating an Image
|
||||
#[derive(Debug)]
|
||||
pub enum ImageError {
|
||||
/// The given image is too big. DBus only has 32 bits for width / height
|
||||
TooBig,
|
||||
/// The given bytes don't match the width, height and channel count
|
||||
WrongDataSize,
|
||||
/// Can't open given path
|
||||
CantOpen(image::ImageError),
|
||||
/// Can't convert from given input
|
||||
CantConvert,
|
||||
}
|
||||
|
||||
impl Error for ImageError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
use ImageError::*;
|
||||
match self {
|
||||
TooBig | WrongDataSize | CantConvert => None,
|
||||
CantOpen(e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ImageError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use ImageError::*;
|
||||
match self {
|
||||
TooBig => writeln!(
|
||||
f,
|
||||
"The given image is too big. DBus only has 32 bits for width / height"
|
||||
),
|
||||
WrongDataSize => writeln!(
|
||||
f,
|
||||
"The given bytes don't match the width, height and channel count"
|
||||
),
|
||||
CantOpen(e) => writeln!(f, "Can't open given path {}", e),
|
||||
CantConvert => writeln!(f, "Can't convert from given input"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// matching image data key for each spec version
|
||||
#[cfg(feature = "dbus")]
|
||||
pub(crate) fn image_spec(version: Version) -> String {
|
||||
match version.cmp(&Version::new(1, 1)) {
|
||||
Ordering::Less => constants::IMAGE_DATA_1_0.to_owned(),
|
||||
Ordering::Equal => constants::IMAGE_DATA_1_1.to_owned(),
|
||||
Ordering::Greater => constants::IMAGE_DATA.to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
/// matching image data key for each spec version
|
||||
#[cfg(feature = "zbus")]
|
||||
pub(crate) fn image_spec_str(version: Version) -> &'static str {
|
||||
match version.cmp(&Version::new(1, 1)) {
|
||||
Ordering::Less => constants::IMAGE_DATA_1_0,
|
||||
Ordering::Equal => constants::IMAGE_DATA_1_1,
|
||||
Ordering::Greater => constants::IMAGE_DATA,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus")]
|
||||
pub struct ImageMessage(Image);
|
||||
|
||||
#[cfg(feature = "dbus")]
|
||||
impl From<Image> for ImageMessage {
|
||||
fn from(hint: Image) -> Self {
|
||||
ImageMessage(hint)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<image::ImageError> for ImageError {
|
||||
fn from(image_error: image::ImageError) -> Self {
|
||||
ImageError::CantOpen(image_error)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus")]
|
||||
impl std::ops::Deref for ImageMessage {
|
||||
type Target = Image;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus")]
|
||||
impl From<ImageMessage> for MessageItem {
|
||||
fn from(img_msg: ImageMessage) -> Self {
|
||||
let img = img_msg.0;
|
||||
|
||||
let bytes = img.data.into_iter().map(MessageItem::Byte).collect();
|
||||
|
||||
MessageItem::Struct(vec![
|
||||
MessageItem::Int32(img.width),
|
||||
MessageItem::Int32(img.height),
|
||||
MessageItem::Int32(img.rowstride),
|
||||
MessageItem::Bool(img.alpha),
|
||||
MessageItem::Int32(img.bits_per_sample),
|
||||
MessageItem::Int32(img.channels),
|
||||
MessageItem::Array(MessageItemArray::new(bytes, "ay".into()).unwrap()),
|
||||
])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user