Iced image grayed out

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!

You've got the color format wrong. Handle::from_pixels expects RGBA image data

To get it to show up, and be readable, switch to Rgba:

diff --git a/src/capture.rs b/src/capture.rs
index 3835d4b..0c4c861 100644
--- a/src/capture.rs
+++ b/src/capture.rs
@@ -28,10 +28,10 @@ pub fn capture_screenshot() -> Result<(usize, usize, Vec<u32>), Box<dyn std::err
     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)
+        (((255) as u32) << 24) // alpha channel
+            | (((chunk[0] as f32 * darkening_factor).round() as u32) << 16) // blue
+            | (((chunk[1] as f32 * darkening_factor).round() as u32) << 8) // green
+            | ((chunk[2] as f32 * darkening_factor).round() as u32) // red
     })
         .collect();
 
@@ -39,8 +39,8 @@ pub fn capture_screenshot() -> Result<(usize, usize, Vec<u32>), Box<dyn std::err
 }
 
 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);
+    let image_buffer = ImageBuffer::<image::Rgba<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::ImageRgba8(image_buffer);
     match dynamic_image.save("test.jpg"){
         Ok(_) => {},
         Err(err) => panic!("Failed to save image: {:?}", err),

(note that I tested this on X11, not Win32)

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.