Hi,
I'm attempting to use iced to display a screenshot of the desktop.
I'm capturing the screenshot like so
use scrap::{Capturer, Display};
use image::ImageBuffer;
use image::{DynamicImage};
use iced::widget::image::{Image, Handle};
pub fn capture_screenshot() -> Result<(usize, usize, Vec<u32>), Box<dyn std::error::Error>> {
let display = Display::primary()?;
let mut capturer = Capturer::new(display)?;
let (width, height) = (capturer.width(), capturer.height());
let frame = loop {
match capturer.frame() {
Ok(frame) => break frame,
Err(error) => {
if error.kind() == std::io::ErrorKind::WouldBlock {
// Frame is not ready yet, retry
std::thread::sleep(std::time::Duration::from_millis(10));
} else {
return Err(Box::new(error));
}
}
}
};
let darkening_factor = 0.4;
let raw_pixels: Vec<u8> = frame.to_vec();
let raw_pixels_u32: Vec<u32> = raw_pixels
.chunks_exact(4)
.map(|chunk| {
(((chunk[3] as f32 * darkening_factor).round() as u32) << 24)
| (((chunk[2] as f32 * darkening_factor).round() as u32) << 16)
| (((chunk[1] as f32 * darkening_factor).round() as u32) << 8)
| ((chunk[0] as f32 * darkening_factor).round() as u32)
})
.collect();
Ok((width as usize, height as usize, raw_pixels_u32))
}
pub fn screenshot_to_iced_image(width: usize, height: usize, raw_pixels_u32: Vec<u32>) -> Handle {
let image_buffer = ImageBuffer::<image::Bgra<u8>, _>::from_raw(width as u32, height as u32, unsafe { std::slice::from_raw_parts(raw_pixels_u32.as_ptr() as *const u8, raw_pixels_u32.len() * 4) }.to_vec()).unwrap();
let dynamic_image = DynamicImage::ImageBgra8(image_buffer);
match dynamic_image.save("test.jpg"){
Ok(_) => {},
Err(err) => panic!("Failed to save image: {:?}", err),
}
return Handle::from_pixels(width as u32, height as u32, dynamic_image.to_bytes())
}
And here is my iced application
mod capture;
use capture::{capture_screenshot, screenshot_to_iced_image};
use iced::widget::{button, column, text, Image, Container};
use iced::{Alignment, Element, Sandbox, Settings, Length};
use iced::widget::image::viewer;
use iced::widget::image::Handle;
use std::rc::Rc;
pub fn main() -> iced::Result {
Counter::run(Settings::default())
}
struct Counter {
value: i32,
screenshot: Handle,
}
#[derive(Debug, Clone, Copy)]
enum Message {
IncrementPressed,
DecrementPressed,
}
impl Sandbox for Counter {
type Message = Message;
fn new() -> Self {
let (width, height, raw_pixels_u32) = capture_screenshot().unwrap();
let screenshot = screenshot_to_iced_image(width, height, raw_pixels_u32);
Self { value: 0, screenshot }
}
fn title(&self) -> String {
String::from("Counter - Iced")
}
fn update(&mut self, message: Message) {
match message {
Message::IncrementPressed => {
self.value += 1;
}
Message::DecrementPressed => {
self.value -= 1;
}
}
}
fn view(&self) -> Element<Message> {
// let image = Image::new("resources/ferris.png")
// .width(Length::Fill)
// .height(Length::Fill);
Container::new(viewer(self.screenshot.clone()))
.width(Length::Fill)
.height(Length::Fill)
.center_x()
.center_y()
.into()
// column![
// viewer(self.screenshot.clone())
// ]
// .into()
// Container::new(viewer)
// .width(Length::Fill)
// .height(Length::Fill)
// .center_x()
// .center_y()
// .into()
}
}
I'm having trouble trying to display the screenshot in my view function
There are no compile issues etc, but the screenshot is just gray
I'm writing out the DynamicImage to a .jpg file and the file looks correct, it's just not displaying in Iced correctly.
Could somone familiar with Iced give me a pointer in the right direction here, I'm not sure what I am doing wrong.
Thanks!