diff --git a/imageflow_core/src/clients/fluent.rs b/imageflow_core/src/clients/fluent.rs index a5851634f..9e9aa6e4e 100644 --- a/imageflow_core/src/clients/fluent.rs +++ b/imageflow_core/src/clients/fluent.rs @@ -143,6 +143,10 @@ impl FluentNode { self.to(s::Node::Transpose) } + pub fn crop_whitespace(self, threshold: u32, percent_padding: f32) -> FluentNode { + self.to(s::Node::CropWhitespace { threshold: threshold, percent_padding: percent_padding }) + } + #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] pub fn copy_rect_from(self, from: FluentNode, diff --git a/imageflow_core/src/flow/definitions.rs b/imageflow_core/src/flow/definitions.rs index f59a616de..a37e271f5 100644 --- a/imageflow_core/src/flow/definitions.rs +++ b/imageflow_core/src/flow/definitions.rs @@ -310,7 +310,7 @@ impl NodeDefOneInputExpand for MutProtect where T: NodeDef{ fn expand(&self, ctx: &mut OpCtxMut, ix: NodeIndex, params: NodeParams, parent: FrameInfo) -> Result<()>{ let mut new_nodes = Vec::with_capacity(2); if ctx.has_other_children(ctx.first_parent_input(ix).unwrap(), ix) { - new_nodes.push(Node::n(self.node, NodeParams::None)); + new_nodes.push(Node::n(&CLONE, NodeParams::None)); } new_nodes.push(Node::n(&*self.node, ctx.weight(ix).params.clone())); ctx.replace_node(ix, new_nodes); diff --git a/imageflow_core/src/flow/nodes/round_corners.rs b/imageflow_core/src/flow/nodes/round_corners.rs index ca5c92bd9..34ad95efc 100644 --- a/imageflow_core/src/flow/nodes/round_corners.rs +++ b/imageflow_core/src/flow/nodes/round_corners.rs @@ -3,9 +3,9 @@ use super::internal_prelude::*; pub static ROUND_IMAGE_CORNERS: RoundImageCorners = RoundImageCorners{}; -pub static ROUND_IMAGE_CORNERS_SRGB_MUTATE: RoundImageCornersMut = RoundImageCornersMut{}; +pub static ROUND_IMAGE_CORNERS_SRGB: MutProtect = MutProtect{node: &ROUND_IMAGE_CORNERS_SRGB_MUTATE, fqn: "imazen.round_image_corners_srgb"}; -//TODO: May need MutProtect to prevent invalid mutation order (also, does MutProtect work right??) +pub static ROUND_IMAGE_CORNERS_SRGB_MUTATE: RoundImageCornersMut = RoundImageCornersMut{}; #[derive(Debug,Clone)] pub struct RoundImageCorners; @@ -26,7 +26,7 @@ impl NodeDefOneInputExpand for RoundImageCorners{ nodes.push(Node::n(&ENABLE_TRANSPARENCY, NodeParams::None)); } - nodes.push(Node::n(&ROUND_IMAGE_CORNERS_SRGB_MUTATE, + nodes.push(Node::n(&ROUND_IMAGE_CORNERS_SRGB, NodeParams::Json(s::Node::RoundImageCorners { background_color: background_color.to_owned(), radius: *radius }))); ctx.replace_node(ix, nodes); diff --git a/imageflow_core/src/flow/nodes/white_balance.rs b/imageflow_core/src/flow/nodes/white_balance.rs index 1ac7d74c5..97bf11026 100644 --- a/imageflow_core/src/flow/nodes/white_balance.rs +++ b/imageflow_core/src/flow/nodes/white_balance.rs @@ -4,8 +4,8 @@ use super::internal_prelude::*; // http://localhost:39876/ir4/proxy_unsplash/photo-1496264057429-6a331647b69e?w=800 - pub static WHITE_BALANCE_SRGB: WhiteBalanceSrgbMutDef = WhiteBalanceSrgbMutDef{}; - pub static WHITE_BALANCE_SRGB_MUTATE: MutProtect = MutProtect{node: &WHITE_BALANCE_SRGB, fqn: "imazen.white_balance_srgb"}; + pub static WHITE_BALANCE_SRGB_MUTATE: WhiteBalanceSrgbMutDef = WhiteBalanceSrgbMutDef{}; + pub static WHITE_BALANCE_SRGB: MutProtect = MutProtect{node: &WHITE_BALANCE_SRGB_MUTATE, fqn: "imazen.white_balance_srgb"}; diff --git a/imageflow_core/tests/common/mod.rs b/imageflow_core/tests/common/mod.rs index 989e33e44..38f5d3b7d 100644 --- a/imageflow_core/tests/common/mod.rs +++ b/imageflow_core/tests/common/mod.rs @@ -111,15 +111,25 @@ impl IoTestTranslator { } + + + pub fn build_steps(context: &mut Context, steps: &[s::Node], io: Vec, security: Option, debug: bool) -> Result{ + build_framewise(context, s::Framewise::Steps(steps.to_vec()), io, security, debug).map_err(|e| e.at(here!())) +} + + + +pub fn build_framewise(context: &mut Context, framewise: s::Framewise, io: Vec, security: Option, debug: bool) -> Result{ + for (ix, val) in io.into_iter().enumerate() { IoTestTranslator{}.add(context, ix as i32, val)?; } let build = s::Execute001{ security, graph_recording: default_graph_recording(debug), - framewise: s::Framewise::Steps(steps.to_vec()) + framewise: framewise }; if debug { println!("{}", serde_json::to_string_pretty(&build).unwrap()); @@ -759,26 +769,45 @@ pub fn compare_with_context(context: &mut Context, inputs: Option, checksum_name: &str, store_if_missing: bool, debug: bool, require: Constraints, steps: Vec) -> bool { + compare_encoded_framewise(input, checksum_name, store_if_missing, debug, require, imageflow_types::Framewise::Steps(steps), 1) +} + +pub fn compare_encoded_framewise(input: Option, checksum_name: &str, store_if_missing: bool, debug: bool, require: Constraints, framewise: imageflow_types::Framewise, output_count: usize) -> bool { let mut io_vec = Vec::new(); if let Some(i) = input{ io_vec.push(i); } - io_vec.push(IoTestEnum::OutputBuffer); + let mut output_ids = Vec::new(); + for _ in 0..output_count{ + output_ids.push(io_vec.len() as i32); + io_vec.push(IoTestEnum::OutputBuffer); + } - let mut context = Context::create().unwrap(); + let mut context = Context::create().unwrap(); - let _ = build_steps(&mut context, &steps, io_vec, None, debug).unwrap(); + let _ = build_framewise(&mut context, framewise, io_vec, None, debug).unwrap(); - let bytes = context.get_output_buffer_slice(1).unwrap(); + for output_io_id in output_ids{ - let mut ctx = ChecksumCtx::visuals(); - ctx.create_if_missing = store_if_missing; + let checksum_sub_name = if output_count > 1{ + format!("{checksum_name}_output_{output_io_id}") + }else{ + checksum_name.to_owned() + }; + let bytes = context.get_output_buffer_slice(output_io_id).unwrap(); + let mut ctx = ChecksumCtx::visuals(); + ctx.create_if_missing = store_if_missing; + let result = evaluate_result(&ctx, &checksum_sub_name, ResultKind::Bytes(bytes), require.clone(), true); + if !result{ + return false; + } + } + return true; - evaluate_result(&ctx, checksum_name, ResultKind::Bytes(bytes), require, true) } diff --git a/imageflow_core/tests/visuals.rs b/imageflow_core/tests/visuals.rs index 6f80c6bea..71bbc7e38 100644 --- a/imageflow_core/tests/visuals.rs +++ b/imageflow_core/tests/visuals.rs @@ -171,6 +171,35 @@ fn test_transparent_png_to_jpeg_constrain() { ); } + + + +#[test] +fn test_branching_crop_whitespace() { + + let preset = EncoderPreset::Lodepng { maximum_deflate: None }; + + let s = imageflow_core::clients::fluent::fluently().decode(0); + let v1 = s.branch(); + let v2 = v1.branch().crop_whitespace(200,0f32); + let framewise = v1.encode(1,preset.clone()).builder().with(v2.encode(2,preset.clone())).to_framewise(); + + + + compare_encoded_framewise( + Some(IoTestEnum::Url("https://imageflow-resources.s3.us-west-2.amazonaws.com/test_inputs/little_gradient_whitespace.jpg".to_owned())), + "test_branching_crop_whitespace_gradient", + POPULATE_CHECKSUMS, + DEBUG_GRAPH, + Constraints { + similarity: Similarity::AllowDssimMatch(0.0, 0.002), + max_file_size: None + }, + framewise, + 2 + ); +} + #[test] fn test_matte_transparent_png() { compare_encoded( diff --git a/imageflow_core/tests/visuals/checksums.json b/imageflow_core/tests/visuals/checksums.json index 712078b64..140a117a6 100644 --- a/imageflow_core/tests/visuals/checksums.json +++ b/imageflow_core/tests/visuals/checksums.json @@ -75,6 +75,8 @@ "test cropping jpeg with exif rotate 8": "0CAA4C5C85C19D4D1_0AF9F04019B0BAF16", "test rotate 90 degrees": "0B843EE7B6518278E_0AE4839D1D9B04C57", "test rotate jpeg 90 degrees": "0285B89DDE072042D_0AE4839D1D9B04C57", + "test_branching_crop_whitespace_gradient_output_1": "01864661ED8AB31EF.png", + "test_branching_crop_whitespace_gradient_output_2": "0B3D16EB972FE0DBB.png", "test_negatives_in_command_string": "0BA85F7DC751DD69E_0726847C75419A20C", "test_rot_90_and_red_dot": "0176FBE641002F3ED_0AE4839D1D9B04C57", "test_rot_90_and_red_dot_command_string": "0C790C6600AFBBADA_0AE4839D1D9B04C57", diff --git a/imageflow_http_helpers/src/lib.rs b/imageflow_http_helpers/src/lib.rs index 61c4b2aef..24862058e 100644 --- a/imageflow_http_helpers/src/lib.rs +++ b/imageflow_http_helpers/src/lib.rs @@ -31,7 +31,7 @@ impl fmt::Display for FetchError { FetchError::UpstreamResponseErrorWithResponse {ref status, ..} => { write!(f, "Response status {}", status) }, - FetchError::ContentLengthMismatch => write!(f, "Content-Length value did not match bytes recieved.") + FetchError::ContentLengthMismatch => write!(f, "Content-Length value did not match bytes received.") } } }