use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use iced::advanced::{clipboard, mouse, renderer};
use iced::{Element, Font, Pixels, Point, Size, Theme};
use iced_runtime::user_interface::{Cache, UserInterface};
use iced_tiny_skia::graphics::Viewport;
#[allow(dead_code)] pub fn render_to_png<Message>(
view: Element<'_, Message, Theme, iced::Renderer>,
width: u32,
height: u32,
theme: &Theme,
events: &[iced::Event],
path: impl AsRef<Path>,
) -> (u32, u32) {
iced_tiny_skia::graphics::text::font_system()
.write()
.expect("font system lock")
.load_font(std::borrow::Cow::Borrowed(scrive_iced::CODICON_FONT));
let mut renderer = iced_renderer::fallback::Renderer::Secondary(
iced_tiny_skia::Renderer::new(Font::default(), Pixels(14.0)),
);
let viewport = Viewport::with_physical_size(Size::new(width, height), 1.0);
let logical = Size::new(width as f32, height as f32);
let cursor = mouse::Cursor::Available(Point::new(width as f32 / 2.0, height as f32 / 2.0));
let mut ui: UserInterface<'_, Message, Theme, iced::Renderer> =
UserInterface::build(view, logical, Cache::new(), &mut renderer);
let mut all = vec![iced::Event::Window(iced::window::Event::RedrawRequested(
std::time::Instant::now(),
))];
all.extend_from_slice(events);
let mut published: Vec<Message> = Vec::new();
ui.update(&all, cursor, &mut renderer, &mut clipboard::Null, &mut published);
ui.draw(&mut renderer, theme, &renderer::Style::default(), cursor);
let iced_renderer::fallback::Renderer::Secondary(ts) = &mut renderer else {
unreachable!("constructed the tiny-skia variant above");
};
let rgba =
iced_tiny_skia::window::compositor::screenshot(ts, &viewport, theme.palette().background);
encode_png(&rgba, width, height, path);
(width, height)
}
fn encode_png(rgba: &[u8], width: u32, height: u32, path: impl AsRef<Path>) {
let file = File::create(&path).expect("create PNG file");
let mut encoder = png::Encoder::new(BufWriter::new(file), width, height);
encoder.set_color(png::ColorType::Rgba);
encoder.set_depth(png::BitDepth::Eight);
encoder
.write_header()
.expect("write PNG header")
.write_image_data(rgba)
.expect("write PNG data");
}
#[allow(dead_code)] #[allow(clippy::too_many_arguments)] pub fn render_interactive_to_png<State, Msg>(
mut state: State,
mut update: impl FnMut(&mut State, Msg),
view: impl Fn(&State) -> Element<'_, Msg, Theme, iced::Renderer>,
width: u32,
height: u32,
theme: &Theme,
events: &[iced::Event],
path: impl AsRef<Path>,
) -> (u32, u32) {
iced_tiny_skia::graphics::text::font_system()
.write()
.expect("font system lock")
.load_font(std::borrow::Cow::Borrowed(scrive_iced::CODICON_FONT));
let mut renderer = iced_renderer::fallback::Renderer::Secondary(
iced_tiny_skia::Renderer::new(Font::default(), Pixels(14.0)),
);
let viewport = Viewport::with_physical_size(Size::new(width, height), 1.0);
let logical = Size::new(width as f32, height as f32);
let mut cache = Cache::new();
let mut cursor_pos = Point::new(width as f32 / 2.0, height as f32 / 2.0);
for event in events {
if let iced::Event::Mouse(mouse::Event::CursorMoved { position }) = event {
cursor_pos = *position;
}
let cursor = mouse::Cursor::Available(cursor_pos);
let mut ui = UserInterface::build(view(&state), logical, cache, &mut renderer);
let mut messages: Vec<Msg> = Vec::new();
ui.update(
std::slice::from_ref(event),
cursor,
&mut renderer,
&mut clipboard::Null,
&mut messages,
);
cache = ui.into_cache();
for message in messages {
update(&mut state, message);
}
}
let cursor = mouse::Cursor::Available(cursor_pos);
let mut ui = UserInterface::build(view(&state), logical, cache, &mut renderer);
ui.draw(&mut renderer, theme, &renderer::Style::default(), cursor);
let iced_renderer::fallback::Renderer::Secondary(ts) = &mut renderer else {
unreachable!("constructed the tiny-skia variant above");
};
let rgba =
iced_tiny_skia::window::compositor::screenshot(ts, &viewport, theme.palette().background);
encode_png(&rgba, width, height, path);
(width, height)
}