mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-07-24 16:13:44 +00:00
New node: Pixel Noise (#1267)
Add Pixel Noise Node Currently only White Noise is implemented, but the Code is written so that other's can be added easily
This commit is contained in:
parent
185106132d
commit
a566331f1c
8 changed files with 117 additions and 3 deletions
|
@ -532,6 +532,27 @@ impl core::fmt::Display for RedGreenBlue {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "std", derive(specta::Type))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)]
|
||||
pub enum NoiseType {
|
||||
WhiteNoise,
|
||||
}
|
||||
|
||||
impl core::fmt::Display for NoiseType {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
NoiseType::WhiteNoise => write!(f, "White Noise"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NoiseType {
|
||||
pub fn list() -> [NoiseType; 1] {
|
||||
[NoiseType::WhiteNoise]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ChannelMixerNode<Monochrome, MonochromeR, MonochromeG, MonochromeB, MonochromeC, RedR, RedG, RedB, RedC, GreenR, GreenG, GreenB, GreenC, BlueR, BlueG, BlueB, BlueC> {
|
||||
monochrome: Monochrome,
|
||||
|
|
|
@ -43,6 +43,7 @@ pub enum TaggedValue {
|
|||
Stroke(graphene_core::vector::style::Stroke),
|
||||
VecF32(Vec<f32>),
|
||||
RedGreenBlue(graphene_core::raster::RedGreenBlue),
|
||||
NoiseType(graphene_core::raster::NoiseType),
|
||||
RelativeAbsolute(graphene_core::raster::RelativeAbsolute),
|
||||
SelectiveColorChoice(graphene_core::raster::SelectiveColorChoice),
|
||||
LineCap(graphene_core::vector::style::LineCap),
|
||||
|
@ -100,6 +101,7 @@ impl Hash for TaggedValue {
|
|||
Self::Stroke(stroke) => stroke.hash(state),
|
||||
Self::VecF32(vec_f32) => vec_f32.iter().for_each(|val| val.to_bits().hash(state)),
|
||||
Self::RedGreenBlue(red_green_blue) => red_green_blue.hash(state),
|
||||
Self::NoiseType(noise_type) => noise_type.hash(state),
|
||||
Self::RelativeAbsolute(relative_absolute) => relative_absolute.hash(state),
|
||||
Self::SelectiveColorChoice(selective_color_choice) => selective_color_choice.hash(state),
|
||||
Self::LineCap(line_cap) => line_cap.hash(state),
|
||||
|
@ -164,6 +166,7 @@ impl<'a> TaggedValue {
|
|||
TaggedValue::Stroke(x) => Box::new(x),
|
||||
TaggedValue::VecF32(x) => Box::new(x),
|
||||
TaggedValue::RedGreenBlue(x) => Box::new(x),
|
||||
TaggedValue::NoiseType(x) => Box::new(x),
|
||||
TaggedValue::RelativeAbsolute(x) => Box::new(x),
|
||||
TaggedValue::SelectiveColorChoice(x) => Box::new(x),
|
||||
TaggedValue::LineCap(x) => Box::new(x),
|
||||
|
@ -231,6 +234,7 @@ impl<'a> TaggedValue {
|
|||
TaggedValue::Stroke(_) => concrete!(graphene_core::vector::style::Stroke),
|
||||
TaggedValue::VecF32(_) => concrete!(Vec<f32>),
|
||||
TaggedValue::RedGreenBlue(_) => concrete!(graphene_core::raster::RedGreenBlue),
|
||||
TaggedValue::NoiseType(_) => concrete!(graphene_core::raster::NoiseType),
|
||||
TaggedValue::RelativeAbsolute(_) => concrete!(graphene_core::raster::RelativeAbsolute),
|
||||
TaggedValue::SelectiveColorChoice(_) => concrete!(graphene_core::raster::SelectiveColorChoice),
|
||||
TaggedValue::LineCap(_) => concrete!(graphene_core::vector::style::LineCap),
|
||||
|
@ -285,6 +289,7 @@ impl<'a> TaggedValue {
|
|||
x if x == TypeId::of::<graphene_core::vector::style::Stroke>() => Ok(TaggedValue::Stroke(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<Vec<f32>>() => Ok(TaggedValue::VecF32(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::RedGreenBlue>() => Ok(TaggedValue::RedGreenBlue(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::NoiseType>() => Ok(TaggedValue::NoiseType(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::RelativeAbsolute>() => Ok(TaggedValue::RelativeAbsolute(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::raster::SelectiveColorChoice>() => Ok(TaggedValue::SelectiveColorChoice(*downcast(input).unwrap())),
|
||||
x if x == TypeId::of::<graphene_core::vector::style::LineCap>() => Ok(TaggedValue::LineCap(*downcast(input).unwrap())),
|
||||
|
|
|
@ -24,6 +24,8 @@ imaginate = ["image/png", "base64", "js-sys", "web-sys", "wasm-bindgen-futures"]
|
|||
wayland = []
|
||||
|
||||
[dependencies]
|
||||
rand = { version = "0.8.5", features = ["alloc", "small_rng"], default-features = false}
|
||||
rand_chacha = { version = "0.3.1", default-features = false }
|
||||
autoquant = { git = "https://github.com/truedoctor/autoquant", optional = true, features = [
|
||||
"fitting",
|
||||
] }
|
||||
|
|
|
@ -2,7 +2,7 @@ use dyn_any::{DynAny, StaticType};
|
|||
use glam::{DAffine2, DVec2};
|
||||
use graph_craft::imaginate_input::{ImaginateController, ImaginateMaskStartingFill, ImaginateSamplingMethod};
|
||||
use graph_craft::proto::DynFuture;
|
||||
use graphene_core::raster::{Alpha, BlendMode, BlendNode, Image, ImageFrame, Linear, LinearChannel, Luminance, Pixel, RGBMut, Raster, RasterMut, RedGreenBlue, Sample};
|
||||
use graphene_core::raster::{Alpha, BlendMode, BlendNode, Image, ImageFrame, Linear, LinearChannel, Luminance, NoiseType, Pixel, RGBMut, Raster, RasterMut, RedGreenBlue, Sample};
|
||||
use graphene_core::transform::Transform;
|
||||
|
||||
use crate::wasm_application_io::WasmEditorApi;
|
||||
|
@ -16,6 +16,9 @@ use std::hash::Hash;
|
|||
use std::marker::PhantomData;
|
||||
use std::path::Path;
|
||||
|
||||
use rand::prelude::*;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
#[derive(Debug, DynAny)]
|
||||
pub enum Error {
|
||||
IO(std::io::Error),
|
||||
|
@ -509,6 +512,33 @@ pub struct ImageFrameNode<P, Transform> {
|
|||
fn image_frame<_P: Pixel>(image: Image<_P>, transform: DAffine2) -> graphene_core::raster::ImageFrame<_P> {
|
||||
graphene_core::raster::ImageFrame { image, transform }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PixelNoiseNode<Height, Seed, NoiseType> {
|
||||
height: Height,
|
||||
seed: Seed,
|
||||
noise_type: NoiseType,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(PixelNoiseNode)]
|
||||
fn pixel_noise(width: u32, height: u32, seed: u32, noise_type: NoiseType) -> graphene_core::raster::ImageFrame<Color> {
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(seed as u64);
|
||||
let mut image = Image::new(width, height, Color::from_luminance(0.5));
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let pixel = image.get_pixel_mut(x, y).unwrap();
|
||||
let luminance = match noise_type {
|
||||
NoiseType::WhiteNoise => rng.gen_range(0.0..1.0) as f32,
|
||||
};
|
||||
*pixel = Color::from_luminance(luminance);
|
||||
}
|
||||
}
|
||||
ImageFrame::<Color> {
|
||||
image,
|
||||
transform: DAffine2::from_scale(DVec2::new(width as f64, height as f64)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
|
|
|
@ -612,6 +612,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: SurfaceFrame, params: [SurfaceFrame]),
|
||||
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
|
||||
register_node!(graphene_std::raster::ImageFrameNode<_, _>, input: Image<Color>, params: [DAffine2]),
|
||||
register_node!(graphene_std::raster::PixelNoiseNode<_, _, _>, input: u32, params: [u32, u32, NoiseType]),
|
||||
#[cfg(feature = "quantization")]
|
||||
register_node!(graphene_std::quantization::GenerateQuantizationNode<_, _>, input: ImageFrame<Color>, params: [u32, u32]),
|
||||
register_node!(graphene_core::quantization::QuantizeNode<_>, input: Color, params: [QuantizationChannels]),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue