Make Imaginate into a node (#878)

* Simplify document node input defenitions

* Remove imaginate layer

* Imaginate node properties

* Fix serde feature gate

* Add Proc Macro for Protonode implementation

* Fix incorrect type

* Add cargo.toml metadata

* Send imaginate params to frontend

* Fix image_creativity range

* Finish imaginate implementation

* Fix the imaginate draw tool

* Remove node-graph/rpco-macro

* Cargo fmt

* Fix missing workspace member

* Changes to the resolution

* Add checkbox for Imaginate auto resolution; improve Properties panel layouts

And fix bugs in panel resizing

* Implement the Rescale button

* Reorder imports

* Update Rust deps

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2022-12-20 22:51:38 +00:00
committed by Keavon Chambers
co-authored by Keavon Chambers
parent 2f2daa25e9
commit 2732492307
61 changed files with 2249 additions and 2596 deletions
+6
View File
@@ -19,6 +19,12 @@ impl Color {
pub const RED: Color = Color::from_unsafe(1., 0., 0.);
pub const GREEN: Color = Color::from_unsafe(0., 1., 0.);
pub const BLUE: Color = Color::from_unsafe(0., 0., 1.);
pub const TRANSPARENT: Color = Self {
red: 0.,
green: 0.,
blue: 0.,
alpha: 0.,
};
/// Returns `Some(Color)` if `red`, `green`, `blue` and `alpha` have a valid value. Negative numbers (including `-0.0`), NaN, and infinity are not valid values and return `None`.
/// Alpha values greater than `1.0` are not valid.
+36 -207
View File
@@ -2,7 +2,6 @@ use crate::boolean_ops::composite_boolean_operation;
use crate::intersection::Quad;
use crate::layers::folder_layer::FolderLayer;
use crate::layers::image_layer::ImageLayer;
use crate::layers::imaginate_layer::{ImaginateImageData, ImaginateLayer, ImaginateStatus};
use crate::layers::layer_info::{Layer, LayerData, LayerDataType, LayerDataTypeDiscriminant};
use crate::layers::nodegraph_layer::NodeGraphFrameLayer;
use crate::layers::shape_layer::ShapeLayer;
@@ -142,7 +141,7 @@ impl Document {
return Ok(&self.root);
}
let (path, id) = split_path(path)?;
self.folder(&path)?.layer(id).ok_or_else(|| DocumentError::LayerNotFound(path.into()))
self.folder(path)?.layer(id).ok_or_else(|| DocumentError::LayerNotFound(path.into()))
}
/// Returns a mutable reference to the layer or folder at the path.
@@ -607,15 +606,13 @@ impl Document {
Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
}
Operation::AddImaginateFrame { path, insert_index, transform } => {
let layer = Layer::new(LayerDataType::Imaginate(ImaginateLayer::default()), transform);
self.set_layer(&path, layer, insert_index)?;
Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
}
Operation::AddNodeGraphFrame { path, insert_index, transform } => {
let layer = Layer::new(LayerDataType::NodeGraphFrame(NodeGraphFrameLayer::default()), transform);
Operation::AddNodeGraphFrame {
path,
insert_index,
transform,
network,
} => {
let layer = Layer::new(LayerDataType::NodeGraphFrame(NodeGraphFrameLayer { network, ..Default::default() }), transform);
self.set_layer(&path, layer, insert_index)?;
@@ -837,52 +834,15 @@ impl Document {
node_graph_frame.blob_url = Some(blob_url);
node_graph_frame.dimensions = resolution.into();
}
LayerDataType::Imaginate(imaginate) => {
imaginate.blob_url = Some(blob_url);
imaginate.dimensions = resolution.into();
}
_ => panic!("Incorrectly trying to set the image blob URL for a layer that is not an Image, NodeGraphFrame or Imaginate layer type"),
}
self.mark_as_dirty(&layer_path)?;
Some([vec![DocumentChanged, LayerChanged { path: layer_path.clone() }], update_thumbnails_upstream(&layer_path)].concat())
}
Operation::ImaginateSetImageData { layer_path, image_data } => {
let layer = self.layer_mut(&layer_path).expect("Setting Imaginate image data for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
let image_data = std::sync::Arc::new(image_data);
imaginate.image_data = Some(ImaginateImageData { image_data });
} else {
panic!("Incorrectly trying to set image data for a layer that is not an Imaginate layer type");
}
Some(vec![LayerChanged { path: layer_path.clone() }])
}
Operation::ImaginateSetGeneratingStatus { path, percent, status } => {
let layer = self.layer_mut(&path).expect("Generating Imaginate for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
if let Some(percentage) = percent {
imaginate.percent_complete = percentage;
}
if status == ImaginateStatus::Generating {
imaginate.image_data = None;
}
imaginate.status = status;
} else {
panic!("Incorrectly trying to set the generating status for a layer that is not an Imaginate layer type");
}
Some(vec![LayerChanged { path: path.clone() }])
}
Operation::ClearBlobURL { path } => {
let layer = self.layer_mut(&path).expect("Clearing Imaginate image for invalid layer");
let layer = self.layer_mut(&path).expect("Clearing node graph image for invalid layer");
match &mut layer.data {
LayerDataType::Imaginate(imaginate) => {
imaginate.image_data = None;
imaginate.blob_url = None;
imaginate.status = ImaginateStatus::Idle;
imaginate.percent_complete = 0.;
}
LayerDataType::NodeGraphFrame(node_graph) => {
node_graph.image_data = None;
node_graph.blob_url = None;
@@ -892,164 +852,6 @@ impl Document {
self.mark_as_dirty(&path)?;
Some([vec![DocumentChanged, LayerChanged { path: path.clone() }], update_thumbnails_upstream(&path)].concat())
}
Operation::ImaginateSetNegativePrompt { path, negative_prompt } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate negative prompt for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.negative_prompt = negative_prompt;
} else {
panic!("Incorrectly trying to set the negative prompt for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetPrompt { path, prompt } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate prompt for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.prompt = prompt;
} else {
panic!("Incorrectly trying to set the prompt for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetMaskBlurPx { path, mask_blur_px } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate mask blur for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.mask_blur_px = mask_blur_px;
} else {
panic!("Incorrectly trying to set the mask blur for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetMaskFillContent { path, mode } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate mask fill content for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.mask_fill_content = mode;
} else {
panic!("Incorrectly trying to set the mask fill content for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetMaskPaintMode { path, paint } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate mask paint mode for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.mask_paint_mode = paint;
} else {
panic!("Incorrectly trying to set the mask paint mode for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetCfgScale { path, cfg_scale } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate CFG scale for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.cfg_scale = cfg_scale;
} else {
panic!("Incorrectly trying to set the CFG scale for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetDenoisingStrength { path, denoising_strength } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate denoising strength for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.denoising_strength = denoising_strength;
} else {
panic!("Incorrectly trying to set the denoising strength for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetLayerPath { path, layer_path } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate layer path strength for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.mask_layer_ref = layer_path;
} else {
panic!("Incorrectly trying to set the layer path for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetSamples { path, samples } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate samples for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.samples = samples;
} else {
panic!("Incorrectly trying to set the samples for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::SetImaginateSamplingMethod { path, method } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate sampling method for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.sampling_method = method;
} else {
panic!("Incorrectly trying to set the sampling method for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetScaleFromResolution { path } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate scale from resolution for invalid layer");
let (width, height) = pick_layer_safe_imaginate_resolution(layer, font_cache);
let current_width = layer.transform.transform_vector2((1., 0.).into()).length();
let current_height = layer.transform.transform_vector2((0., 1.).into()).length();
let scale_x_by = width as f64 / current_width;
let scale_y_by = height as f64 / current_height;
let scale_by_vector = DVec2::new(scale_x_by, scale_y_by);
let scale_by_matrix = DAffine2::from_scale_angle_translation(scale_by_vector, 0., (0., 0.).into());
layer.transform = layer.transform * scale_by_matrix;
self.mark_as_dirty(&path)?;
Some([update_thumbnails_upstream(&path), vec![DocumentChanged, LayerChanged { path }]].concat())
}
Operation::ImaginateSetSeed { path, seed } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate seed for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.seed = seed;
} else {
panic!("Incorrectly trying to set the seed for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetUseImg2Img { path, use_img2img } => {
let layer = self.layer_mut(&path).expect("Calling Imaginate img2img for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.use_img2img = use_img2img;
} else {
panic!("Incorrectly trying to set the img2img status for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetRestoreFaces { path, restore_faces } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate restore faces for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.restore_faces = restore_faces;
} else {
panic!("Incorrectly trying to set the restore faces status for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::ImaginateSetTiling { path, tiling } => {
let layer = self.layer_mut(&path).expect("Setting Imaginate tiling for invalid layer");
if let LayerDataType::Imaginate(imaginate) = &mut layer.data {
imaginate.tiling = tiling;
} else {
panic!("Incorrectly trying to set the tiling status for a layer that is not an Imaginate layer type");
}
self.mark_as_dirty(&path)?;
Some(vec![LayerChanged { path }])
}
Operation::SetPivot { layer_path, pivot } => {
let layer = self.layer_mut(&layer_path).expect("Setting pivot for invalid layer");
layer.pivot = pivot.into();
@@ -1161,6 +963,33 @@ impl Document {
self.mark_as_dirty(&path)?;
Some([vec![DocumentChanged], update_thumbnails_upstream(&path)].concat())
}
Operation::TransformLayerScaleAroundPivot { path, scale_factor } => {
let layer = self.layer_mut(&path)?;
let offset = DAffine2::from_translation(-layer.pivot);
let scale = DAffine2::from_scale(scale_factor.into());
let offset_back = DAffine2::from_translation(layer.pivot);
layer.transform = layer.transform * offset_back * scale * offset;
self.mark_as_dirty(&path)?;
Some([vec![DocumentChanged], update_thumbnails_upstream(&path)].concat())
}
Operation::SetLayerScaleAroundPivot { path, new_scale } => {
let layer = self.layer_mut(&path)?;
let matrix = layer.transform.to_cols_array();
let old_scale = (matrix[0], matrix[3]);
let scale_factor = DVec2::from(new_scale) / DVec2::from(old_scale);
let offset = DAffine2::from_translation(-layer.pivot);
let scale = DAffine2::from_scale(scale_factor);
let offset_back = DAffine2::from_translation(layer.pivot);
layer.transform = layer.transform * offset_back * scale * offset;
self.mark_as_dirty(&path)?;
Some([vec![DocumentChanged], update_thumbnails_upstream(&path)].concat())
}
Operation::SetLayerTransform { path, transform } => {
let transform = DAffine2::from_cols_array(&transform);
let layer = self.layer_mut(&path)?;
-351
View File
@@ -1,351 +0,0 @@
use super::base64_serde;
use super::layer_info::LayerData;
use super::style::{RenderData, ViewMode};
use crate::intersection::{intersect_quad_bez_path, Quad};
use crate::layers::text_layer::FontCache;
use crate::LayerId;
use glam::{DAffine2, DMat2, DVec2};
use kurbo::{Affine, BezPath, Shape as KurboShape};
use serde::{Deserialize, Serialize};
use std::fmt::Write;
#[derive(Clone, PartialEq, Deserialize, Serialize)]
pub struct ImaginateLayer {
// User-configurable layer parameters
pub seed: u64,
pub samples: u32,
pub sampling_method: ImaginateSamplingMethod,
pub use_img2img: bool,
pub denoising_strength: f64,
pub mask_layer_ref: Option<Vec<LayerId>>,
pub mask_paint_mode: ImaginateMaskPaintMode,
pub mask_blur_px: u32,
pub mask_fill_content: ImaginateMaskFillContent,
pub cfg_scale: f64,
pub prompt: String,
pub negative_prompt: String,
pub restore_faces: bool,
pub tiling: bool,
// Image stored in layer after generation completes
pub image_data: Option<ImaginateImageData>,
pub mime: String,
/// 0 is not started, 100 is complete.
pub percent_complete: f64,
// TODO: Have the browser dispose of this blob URL when this is dropped (like when the layer is deleted)
#[serde(skip)]
pub blob_url: Option<String>,
#[serde(skip)]
pub status: ImaginateStatus,
#[serde(skip)]
pub dimensions: DVec2,
}
#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
pub enum ImaginateStatus {
#[default]
Idle,
Beginning,
Uploading(f64),
Generating,
Terminating,
Terminated,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
pub struct ImaginateImageData {
#[serde(serialize_with = "base64_serde::as_base64", deserialize_with = "base64_serde::from_base64")]
pub image_data: std::sync::Arc<Vec<u8>>,
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ImaginateBaseImage {
pub svg: String,
pub size: DVec2,
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
pub enum ImaginateMaskPaintMode {
#[default]
Inpaint,
Outpaint,
}
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
pub enum ImaginateMaskFillContent {
#[default]
Fill,
Original,
LatentNoise,
LatentNothing,
}
impl ImaginateMaskFillContent {
pub fn list() -> [ImaginateMaskFillContent; 4] {
[
ImaginateMaskFillContent::Fill,
ImaginateMaskFillContent::Original,
ImaginateMaskFillContent::LatentNoise,
ImaginateMaskFillContent::LatentNothing,
]
}
}
impl std::fmt::Display for ImaginateMaskFillContent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ImaginateMaskFillContent::Fill => write!(f, "Smeared Surroundings"),
ImaginateMaskFillContent::Original => write!(f, "Original Base Image"),
ImaginateMaskFillContent::LatentNoise => write!(f, "Randomness (Latent Noise)"),
ImaginateMaskFillContent::LatentNothing => write!(f, "Neutral (Latent Nothing)"),
}
}
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Deserialize, Serialize)]
pub enum ImaginateSamplingMethod {
#[default]
EulerA,
Euler,
LMS,
Heun,
DPM2,
DPM2A,
DPMPlusPlus2sA,
DPMPlusPlus2m,
DPMFast,
DPMAdaptive,
LMSKarras,
DPM2Karras,
DPM2AKarras,
DPMPlusPlus2sAKarras,
DPMPlusPlus2mKarras,
DDIM,
PLMS,
}
impl ImaginateSamplingMethod {
pub fn api_value(&self) -> &str {
match self {
ImaginateSamplingMethod::EulerA => "Euler a",
ImaginateSamplingMethod::Euler => "Euler",
ImaginateSamplingMethod::LMS => "LMS",
ImaginateSamplingMethod::Heun => "Heun",
ImaginateSamplingMethod::DPM2 => "DPM2",
ImaginateSamplingMethod::DPM2A => "DPM2 a",
ImaginateSamplingMethod::DPMPlusPlus2sA => "DPM++ 2S a",
ImaginateSamplingMethod::DPMPlusPlus2m => "DPM++ 2M",
ImaginateSamplingMethod::DPMFast => "DPM fast",
ImaginateSamplingMethod::DPMAdaptive => "DPM adaptive",
ImaginateSamplingMethod::LMSKarras => "LMS Karras",
ImaginateSamplingMethod::DPM2Karras => "DPM2 Karras",
ImaginateSamplingMethod::DPM2AKarras => "DPM2 a Karras",
ImaginateSamplingMethod::DPMPlusPlus2sAKarras => "DPM++ 2S a Karras",
ImaginateSamplingMethod::DPMPlusPlus2mKarras => "DPM++ 2M Karras",
ImaginateSamplingMethod::DDIM => "DDIM",
ImaginateSamplingMethod::PLMS => "PLMS",
}
}
pub fn list() -> [ImaginateSamplingMethod; 17] {
[
ImaginateSamplingMethod::EulerA,
ImaginateSamplingMethod::Euler,
ImaginateSamplingMethod::LMS,
ImaginateSamplingMethod::Heun,
ImaginateSamplingMethod::DPM2,
ImaginateSamplingMethod::DPM2A,
ImaginateSamplingMethod::DPMPlusPlus2sA,
ImaginateSamplingMethod::DPMPlusPlus2m,
ImaginateSamplingMethod::DPMFast,
ImaginateSamplingMethod::DPMAdaptive,
ImaginateSamplingMethod::LMSKarras,
ImaginateSamplingMethod::DPM2Karras,
ImaginateSamplingMethod::DPM2AKarras,
ImaginateSamplingMethod::DPMPlusPlus2sAKarras,
ImaginateSamplingMethod::DPMPlusPlus2mKarras,
ImaginateSamplingMethod::DDIM,
ImaginateSamplingMethod::PLMS,
]
}
}
impl std::fmt::Display for ImaginateSamplingMethod {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ImaginateSamplingMethod::EulerA => write!(f, "Euler A (Recommended)"),
ImaginateSamplingMethod::Euler => write!(f, "Euler"),
ImaginateSamplingMethod::LMS => write!(f, "LMS"),
ImaginateSamplingMethod::Heun => write!(f, "Heun"),
ImaginateSamplingMethod::DPM2 => write!(f, "DPM2"),
ImaginateSamplingMethod::DPM2A => write!(f, "DPM2 A"),
ImaginateSamplingMethod::DPMPlusPlus2sA => write!(f, "DPM++ 2S a"),
ImaginateSamplingMethod::DPMPlusPlus2m => write!(f, "DPM++ 2M"),
ImaginateSamplingMethod::DPMFast => write!(f, "DPM Fast"),
ImaginateSamplingMethod::DPMAdaptive => write!(f, "DPM Adaptive"),
ImaginateSamplingMethod::LMSKarras => write!(f, "LMS Karras"),
ImaginateSamplingMethod::DPM2Karras => write!(f, "DPM2 Karras"),
ImaginateSamplingMethod::DPM2AKarras => write!(f, "DPM2 A Karras"),
ImaginateSamplingMethod::DPMPlusPlus2sAKarras => write!(f, "DPM++ 2S a Karras"),
ImaginateSamplingMethod::DPMPlusPlus2mKarras => write!(f, "DPM++ 2M Karras"),
ImaginateSamplingMethod::DDIM => write!(f, "DDIM"),
ImaginateSamplingMethod::PLMS => write!(f, "PLMS"),
}
}
}
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ImaginateGenerationParameters {
pub seed: u64,
pub samples: u32,
/// Use `ImaginateSamplingMethod::api_value()` to generate this string
#[serde(rename = "samplingMethod")]
pub sampling_method: String,
#[serde(rename = "denoisingStrength")]
pub denoising_strength: Option<f64>,
#[serde(rename = "cfgScale")]
pub cfg_scale: f64,
pub prompt: String,
#[serde(rename = "negativePrompt")]
pub negative_prompt: String,
pub resolution: (u64, u64),
#[serde(rename = "restoreFaces")]
pub restore_faces: bool,
pub tiling: bool,
}
impl Default for ImaginateLayer {
fn default() -> Self {
Self {
seed: 0,
samples: 30,
sampling_method: Default::default(),
use_img2img: false,
denoising_strength: 0.66,
mask_paint_mode: ImaginateMaskPaintMode::default(),
mask_layer_ref: None,
mask_blur_px: 4,
mask_fill_content: ImaginateMaskFillContent::default(),
cfg_scale: 10.,
prompt: "".into(),
negative_prompt: "".into(),
restore_faces: false,
tiling: false,
image_data: None,
mime: "image/png".into(),
blob_url: None,
percent_complete: 0.,
status: Default::default(),
dimensions: Default::default(),
}
}
}
impl LayerData for ImaginateLayer {
fn render(&mut self, svg: &mut String, _svg_defs: &mut String, transforms: &mut Vec<DAffine2>, render_data: RenderData) {
let transform = self.transform(transforms, render_data.view_mode);
let inverse = transform.inverse();
let (width, height) = (transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length());
if !inverse.is_finite() {
let _ = write!(svg, "<!-- SVG shape has an invalid transform -->");
return;
}
let _ = writeln!(svg, r#"<g transform="matrix("#);
inverse.to_cols_array().iter().enumerate().for_each(|(i, entry)| {
let _ = svg.write_str(&(entry.to_string() + if i == 5 { "" } else { "," }));
});
let _ = svg.write_str(r#")">"#);
if let Some(blob_url) = &self.blob_url {
let _ = write!(
svg,
r#"<image width="{}" height="{}" preserveAspectRatio="none" href="{}" transform="matrix("#,
width.abs(),
height.abs(),
blob_url
);
} else {
let _ = write!(
svg,
r#"<rect width="{}" height="{}" fill="none" stroke="var(--color-data-raster)" stroke-width="3" stroke-dasharray="8" transform="matrix("#,
width.abs(),
height.abs(),
);
}
(transform * DAffine2::from_scale((width, height).into()).inverse())
.to_cols_array()
.iter()
.enumerate()
.for_each(|(i, entry)| {
let _ = svg.write_str(&(entry.to_string() + if i == 5 { "" } else { "," }));
});
let _ = svg.write_str(r#")" /> </g>"#);
}
fn bounding_box(&self, transform: glam::DAffine2, _font_cache: &FontCache) -> Option<[DVec2; 2]> {
let mut path = self.bounds();
if transform.matrix2 == DMat2::ZERO {
return None;
}
path.apply_affine(glam_to_kurbo(transform));
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
Some([(x0, y0).into(), (x1, y1).into()])
}
fn intersects_quad(&self, quad: Quad, path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>, _font_cache: &FontCache) {
if intersect_quad_bez_path(quad, &self.bounds(), true) {
intersections.push(path.clone());
}
}
}
impl ImaginateLayer {
pub fn transform(&self, transforms: &[DAffine2], mode: ViewMode) -> DAffine2 {
let start = match mode {
ViewMode::Outline => 0,
_ => (transforms.len() as i32 - 1).max(0) as usize,
};
transforms.iter().skip(start).cloned().reduce(|a, b| a * b).unwrap_or(DAffine2::IDENTITY)
}
fn bounds(&self) -> BezPath {
kurbo::Rect::from_origin_size(kurbo::Point::ZERO, kurbo::Size::new(1., 1.)).to_path(0.)
}
}
fn glam_to_kurbo(transform: DAffine2) -> Affine {
Affine::new(transform.to_cols_array())
}
impl std::fmt::Debug for ImaginateLayer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ImaginateLayer")
.field("seed", &self.seed)
.field("samples", &self.samples)
.field("use_img2img", &self.use_img2img)
.field("denoising_strength", &self.denoising_strength)
.field("cfg_scale", &self.cfg_scale)
.field("prompt", &self.prompt)
.field("negative_prompt", &self.negative_prompt)
.field("restore_faces", &self.restore_faces)
.field("tiling", &self.tiling)
.field("image_data", &self.image_data.as_ref().map(|_| "..."))
.field("mime", &self.mime)
.field("percent_complete", &self.percent_complete)
.field("blob_url", &self.blob_url)
.field("status", &self.status)
.field("dimensions", &self.dimensions)
.finish()
}
}
-26
View File
@@ -1,7 +1,6 @@
use super::blend_mode::BlendMode;
use super::folder_layer::FolderLayer;
use super::image_layer::ImageLayer;
use super::imaginate_layer::ImaginateLayer;
use super::nodegraph_layer::NodeGraphFrameLayer;
use super::shape_layer::ShapeLayer;
use super::style::{PathStyle, RenderData};
@@ -29,8 +28,6 @@ pub enum LayerDataType {
Text(TextLayer),
/// A layer that wraps an [ImageLayer] struct.
Image(ImageLayer),
/// A layer that wraps an [ImaginateLayer] struct.
Imaginate(ImaginateLayer),
/// A layer that wraps an [NodeGraphFrameLayer] struct.
NodeGraphFrame(NodeGraphFrameLayer),
}
@@ -42,7 +39,6 @@ impl LayerDataType {
LayerDataType::Folder(f) => f,
LayerDataType::Text(t) => t,
LayerDataType::Image(i) => i,
LayerDataType::Imaginate(a) => a,
LayerDataType::NodeGraphFrame(n) => n,
}
}
@@ -53,7 +49,6 @@ impl LayerDataType {
LayerDataType::Folder(f) => f,
LayerDataType::Text(t) => t,
LayerDataType::Image(i) => i,
LayerDataType::Imaginate(a) => a,
LayerDataType::NodeGraphFrame(n) => n,
}
}
@@ -65,7 +60,6 @@ pub enum LayerDataTypeDiscriminant {
Shape,
Text,
Image,
Imaginate,
NodeGraphFrame,
}
@@ -76,7 +70,6 @@ impl fmt::Display for LayerDataTypeDiscriminant {
LayerDataTypeDiscriminant::Shape => write!(f, "Shape"),
LayerDataTypeDiscriminant::Text => write!(f, "Text"),
LayerDataTypeDiscriminant::Image => write!(f, "Image"),
LayerDataTypeDiscriminant::Imaginate => write!(f, "Imaginate"),
LayerDataTypeDiscriminant::NodeGraphFrame => write!(f, "Node Graph Frame"),
}
}
@@ -91,7 +84,6 @@ impl From<&LayerDataType> for LayerDataTypeDiscriminant {
Shape(_) => LayerDataTypeDiscriminant::Shape,
Text(_) => LayerDataTypeDiscriminant::Text,
Image(_) => LayerDataTypeDiscriminant::Image,
Imaginate(_) => LayerDataTypeDiscriminant::Imaginate,
NodeGraphFrame(_) => LayerDataTypeDiscriminant::NodeGraphFrame,
}
}
@@ -499,24 +491,6 @@ impl Layer {
}
}
/// Get a mutable reference to the Imaginate element wrapped by the layer.
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Imaginate`.
pub fn as_imaginate_mut(&mut self) -> Result<&mut ImaginateLayer, DocumentError> {
match &mut self.data {
LayerDataType::Imaginate(imaginate) => Ok(imaginate),
_ => Err(DocumentError::NotAnImaginate),
}
}
/// Get a reference to the Imaginate element wrapped by the layer.
/// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Imaginate`.
pub fn as_imaginate(&self) -> Result<&ImaginateLayer, DocumentError> {
match &self.data {
LayerDataType::Imaginate(imaginate) => Ok(imaginate),
_ => Err(DocumentError::NotAnImaginate),
}
}
pub fn style(&self) -> Result<&PathStyle, DocumentError> {
match &self.data {
LayerDataType::Shape(s) => Ok(&s.style),
-2
View File
@@ -22,8 +22,6 @@ pub mod blend_mode;
pub mod folder_layer;
/// Contains the [ImageLayer](image_layer::ImageLayer) type that contains a bitmap image.
pub mod image_layer;
/// Contains the [ImaginateLayer](imaginate_layer::ImaginateLayer) type that contains a bitmap image generated based on a prompt and optionally the layers beneath it.
pub mod imaginate_layer;
/// Contains the base [Layer](layer_info::Layer) type, an abstraction over the different types of layers.
pub mod layer_info;
/// Contains the [NodegraphLayer](nodegraph_layer::NodegraphLayer) type that contains a node graph.
+1 -43
View File
@@ -6,13 +6,11 @@ use crate::layers::text_layer::FontCache;
use crate::LayerId;
use glam::{DAffine2, DMat2, DVec2};
use graph_craft::proto::Type;
use kurbo::{Affine, BezPath, Shape as KurboShape};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use std::fmt::Write;
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
pub struct NodeGraphFrameLayer {
// Image stored in layer after generation completes
pub mime: String,
@@ -115,43 +113,3 @@ impl NodeGraphFrameLayer {
fn glam_to_kurbo(transform: DAffine2) -> Affine {
Affine::new(transform.to_cols_array())
}
impl Default for NodeGraphFrameLayer {
fn default() -> Self {
use graph_craft::document::*;
use graph_craft::proto::NodeIdentifier;
Self {
mime: String::new(),
network: NodeNetwork {
inputs: vec![0],
output: 1,
nodes: [
(
0,
DocumentNode {
name: "Input".into(),
inputs: vec![NodeInput::Network],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic(Cow::Borrowed("T"))])),
metadata: DocumentNodeMetadata { position: (8, 4) },
},
),
(
1,
DocumentNode {
name: "Output".into(),
inputs: vec![NodeInput::Node(0)],
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic(Cow::Borrowed("T"))])),
metadata: DocumentNodeMetadata { position: (20, 4) },
},
),
]
.into_iter()
.collect(),
},
blob_url: None,
dimensions: DVec2::ZERO,
image_data: None,
}
}
}
+9 -74
View File
@@ -1,6 +1,5 @@
use crate::boolean_ops::BooleanOperation as BooleanOperationType;
use crate::layers::blend_mode::BlendMode;
use crate::layers::imaginate_layer::{ImaginateMaskFillContent, ImaginateMaskPaintMode, ImaginateSamplingMethod, ImaginateStatus};
use crate::layers::layer_info::Layer;
use crate::layers::style::{self, Stroke};
use crate::LayerId;
@@ -53,15 +52,11 @@ pub enum Operation {
mime: String,
image_data: Vec<u8>,
},
AddImaginateFrame {
path: Vec<LayerId>,
insert_index: isize,
transform: [f64; 6],
},
AddNodeGraphFrame {
path: Vec<LayerId>,
insert_index: isize,
transform: [f64; 6],
network: graph_craft::document::NodeNetwork,
},
SetNodeGraphFrameImageData {
layer_path: Vec<LayerId>,
@@ -79,74 +74,6 @@ pub enum Operation {
ClearBlobURL {
path: Vec<LayerId>,
},
ImaginateSetGeneratingStatus {
path: Vec<LayerId>,
percent: Option<f64>,
status: ImaginateStatus,
},
ImaginateSetImageData {
layer_path: Vec<LayerId>,
image_data: Vec<u8>,
},
ImaginateSetNegativePrompt {
path: Vec<LayerId>,
negative_prompt: String,
},
ImaginateSetPrompt {
path: Vec<LayerId>,
prompt: String,
},
ImaginateSetMaskBlurPx {
path: Vec<LayerId>,
mask_blur_px: u32,
},
ImaginateSetMaskFillContent {
path: Vec<LayerId>,
mode: ImaginateMaskFillContent,
},
ImaginateSetMaskPaintMode {
path: Vec<LayerId>,
paint: ImaginateMaskPaintMode,
},
ImaginateSetCfgScale {
path: Vec<LayerId>,
cfg_scale: f64,
},
ImaginateSetSamples {
path: Vec<LayerId>,
samples: u32,
},
SetImaginateSamplingMethod {
path: Vec<LayerId>,
method: ImaginateSamplingMethod,
},
ImaginateSetScaleFromResolution {
path: Vec<LayerId>,
},
ImaginateSetSeed {
path: Vec<LayerId>,
seed: u64,
},
ImaginateSetDenoisingStrength {
path: Vec<LayerId>,
denoising_strength: f64,
},
ImaginateSetLayerPath {
path: Vec<LayerId>,
layer_path: Option<Vec<LayerId>>,
},
ImaginateSetUseImg2Img {
path: Vec<LayerId>,
use_img2img: bool,
},
ImaginateSetRestoreFaces {
path: Vec<LayerId>,
restore_faces: bool,
},
ImaginateSetTiling {
path: Vec<LayerId>,
tiling: bool,
},
SetPivot {
layer_path: Vec<LayerId>,
pivot: (f64, f64),
@@ -295,6 +222,14 @@ pub enum Operation {
transform: [f64; 6],
scope: [f64; 6],
},
TransformLayerScaleAroundPivot {
path: Vec<LayerId>,
scale_factor: (f64, f64),
},
SetLayerScaleAroundPivot {
path: Vec<LayerId>,
new_scale: (f64, f64),
},
SetLayerTransform {
path: Vec<LayerId>,
transform: [f64; 6],