mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 06:38:03 +08:00
Insert pasted images as layers in document graph (#1418)
Changes: Graph is evaluated on every viewport change move all navigation logic into the viewport reduce the number of js roundtrips add canvas rendering enable image pasting various cleanups Fix cache nodes being reset every evaluation
This commit is contained in:
committed by
Keavon Chambers
parent
d82f133514
commit
833f41bccb
@@ -58,41 +58,49 @@ fn buffer_node<R: std::io::Read>(reader: R) -> Result<Vec<u8>, Error> {
|
||||
Ok(std::io::Read::bytes(reader).collect::<Result<Vec<_>, _>>()?)
|
||||
}
|
||||
|
||||
pub struct DownresNode<ImageFrame> {
|
||||
pub struct SampleNode<ImageFrame> {
|
||||
image_frame: ImageFrame,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(DownresNode)]
|
||||
fn downres(footprint: Footprint, image_frame: ImageFrame<Color>) -> ImageFrame<Color> {
|
||||
#[node_macro::node_fn(SampleNode)]
|
||||
fn sample(footprint: Footprint, image_frame: ImageFrame<Color>) -> ImageFrame<Color> {
|
||||
// resize the image using the image crate
|
||||
let image = image_frame.image;
|
||||
let data = bytemuck::cast_vec(image.data);
|
||||
|
||||
let viewport_bounds = footprint.viewport_bounds_in_local_space();
|
||||
log::debug!("viewport_bounds: {viewport_bounds:?}");
|
||||
let bbox = Bbox::from_transform(image_frame.transform * DAffine2::from_scale(DVec2::new(image.width as f64, image.height as f64)));
|
||||
log::debug!("local_bounds: {bbox:?}");
|
||||
let bounds = viewport_bounds.intersect(&bbox.to_axis_aligned_bbox());
|
||||
log::debug!("intersection: {bounds:?}");
|
||||
let union = viewport_bounds.union(&bbox.to_axis_aligned_bbox());
|
||||
log::debug!("union: {union:?}");
|
||||
let size = bounds.size();
|
||||
let image_bounds = Bbox::from_transform(image_frame.transform).to_axis_aligned_bbox();
|
||||
let intersection = viewport_bounds.intersect(&image_bounds);
|
||||
let image_size = DAffine2::from_scale(DVec2::new(image.width as f64, image.height as f64));
|
||||
let size = intersection.size();
|
||||
let size_px = image_size.transform_vector2(size).as_uvec2();
|
||||
|
||||
// If the image would not be visible, return an empty image
|
||||
if size.x <= 0. || size.y <= 0. {
|
||||
return ImageFrame::empty();
|
||||
}
|
||||
|
||||
let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, data).expect("Failed to convert internal ImageFrame into image-rs data type.");
|
||||
|
||||
let dynamic_image: image::DynamicImage = image_buffer.into();
|
||||
let offset = (bounds.start - viewport_bounds.start).as_uvec2();
|
||||
let cropped = dynamic_image.crop_imm(offset.x, offset.y, size.x as u32, size.y as u32);
|
||||
let offset = (intersection.start - image_bounds.start).max(DVec2::ZERO);
|
||||
let offset_px = image_size.transform_vector2(offset).as_uvec2();
|
||||
let cropped = dynamic_image.crop_imm(offset_px.x, offset_px.y, size_px.x, size_px.y);
|
||||
|
||||
log::debug!("transform: {:?}", footprint.transform);
|
||||
log::debug!("size: {size:?}");
|
||||
let viewport_resolution_x = footprint.transform.transform_vector2(DVec2::X * size.x).length();
|
||||
let viewport_resolution_y = footprint.transform.transform_vector2(DVec2::Y * size.y).length();
|
||||
let nwidth = viewport_resolution_x as u32;
|
||||
let nheight = viewport_resolution_y as u32;
|
||||
log::debug!("x: {viewport_resolution_x}, y: {viewport_resolution_y}");
|
||||
let mut nwidth = size_px.x;
|
||||
let mut nheight = size_px.y;
|
||||
|
||||
let resized = cropped.resize_exact(nwidth, nheight, image::imageops::Lanczos3);
|
||||
// Only downscale the image for now
|
||||
let resized = if nwidth < image.width || nheight < image.height {
|
||||
nwidth = viewport_resolution_x as u32;
|
||||
nheight = viewport_resolution_y as u32;
|
||||
// TODO: choose filter based on quality reqirements
|
||||
cropped.resize_exact(nwidth, nheight, image::imageops::Triangle)
|
||||
} else {
|
||||
cropped
|
||||
};
|
||||
let buffer = resized.to_rgba32f();
|
||||
let buffer = buffer.into_raw();
|
||||
let vec = bytemuck::cast_vec(buffer);
|
||||
@@ -101,11 +109,10 @@ fn downres(footprint: Footprint, image_frame: ImageFrame<Color>) -> ImageFrame<C
|
||||
height: nheight,
|
||||
data: vec,
|
||||
};
|
||||
// we need to adjust the offset if we truncate the offset calculation
|
||||
|
||||
ImageFrame {
|
||||
image,
|
||||
transform: image_frame.transform,
|
||||
}
|
||||
let new_transform = image_frame.transform * DAffine2::from_translation(offset) * DAffine2::from_scale(DVec2::new(size.x, size.y));
|
||||
ImageFrame { image, transform: new_transform }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
|
||||
Reference in New Issue
Block a user