Skip to content

Commit a28f90a

Browse files
committed
feat: add max_total_file_pixels, JobOptions, make ExecutionSecurity non_exhaustive
- Add ExecutionSecurity::max_total_file_pixels (Option<u64>, default 400MP) for bounding total decoded pixels across all animation frames. - Make ExecutionSecurity #[non_exhaustive] so new fields don't break downstream crates. External construction now uses sane_defaults() or unspecified() with field mutation. - Add JobOptions struct (#[non_exhaustive], currently empty) reserved for upcoming backend and color management controls. - Wire JobOptions into Build001Config and Execute001. - Update all test and tool construction sites.
1 parent c17bf66 commit a28f90a

File tree

15 files changed

+127
-55
lines changed

15 files changed

+127
-55
lines changed

imageflow_core/src/clients/stateless.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ impl LibClient {
125125
let send_execute = s::Execute001 {
126126
framewise: task.framewise,
127127
security: None,
128+
job_options: None,
128129
graph_recording: task
129130
.export_graphs_to
130131
.map(|_| s::Build001GraphRecording::debug_defaults()),

imageflow_core/src/context.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,9 @@ impl Context {
647647
if s.max_json_bytes.is_some() {
648648
self.security.max_json_bytes = s.max_json_bytes;
649649
}
650+
if s.max_total_file_pixels.is_some() {
651+
self.security.max_total_file_pixels = s.max_total_file_pixels;
652+
}
650653
}
651654

652655
/// For executing an operation graph (assumes you have already configured the context with IO sources/destinations as needed)
@@ -860,6 +863,7 @@ fn test_take_after_encode_returns_data() {
860863
let execute = s::Execute001 {
861864
graph_recording: Some(s::Build001GraphRecording::off()),
862865
security: None,
866+
job_options: None,
863867
framewise: s::Framewise::Steps(vec![
864868
s::Node::Decode { io_id: 0, commands: None },
865869
s::Node::Encode {
@@ -896,6 +900,7 @@ fn test_get_ptr_after_encode_then_take_blocked() {
896900
let execute = s::Execute001 {
897901
graph_recording: Some(s::Build001GraphRecording::off()),
898902
security: None,
903+
job_options: None,
899904
framewise: s::Framewise::Steps(vec![
900905
s::Node::Decode { io_id: 0, commands: None },
901906
s::Node::Encode {
@@ -940,7 +945,7 @@ impl Drop for Context {
940945
#[test]
941946
fn test_context_size() {
942947
eprintln!("std::mem::sizeof(Context) = {}", std::mem::size_of::<Context>());
943-
assert!(std::mem::size_of::<Context>() < 380);
948+
assert!(std::mem::size_of::<Context>() < 400);
944949
}
945950

946951
#[test]
@@ -975,10 +980,10 @@ fn test_calculate_context_heap_size() {
975980
// Fail if this grows so we can notice it
976981
// Windows has larger RwLock/Mutex, so allow a few extra bytes
977982
assert!(context_allocs <= 6);
978-
assert!(context_bytes <= 1024);
983+
assert!(context_bytes <= 1056);
979984

980985
assert!(context_allocs <= 6);
981-
assert!(thread_safe_bytes <= 1216);
986+
assert!(thread_safe_bytes <= 1248);
982987
}
983988

984989
#[test]

imageflow_core/src/json/endpoints/mod.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,7 @@ fn test_handler() {
145145
];
146146

147147
let build = Build001 {
148-
builder_config: Some(Build001Config {
149-
graph_recording: None,
150-
security: None,
151-
// process_all_gif_frames: Some(false),
152-
// enable_jpeg_block_scaling: Some(false)
153-
}),
148+
builder_config: Some(Build001Config::default()),
154149
io: vec![input_io, output_io],
155150
framewise: Framewise::Steps(steps),
156151
};

imageflow_core/src/json/endpoints/openapi_schema_v1.json

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,16 @@
617617
}
618618
]
619619
},
620+
"job_options": {
621+
"oneOf": [
622+
{
623+
"type": "null"
624+
},
625+
{
626+
"$ref": "#/components/schemas/JobOptions"
627+
}
628+
]
629+
},
620630
"security": {
621631
"oneOf": [
622632
{
@@ -1532,6 +1542,16 @@
15321542
}
15331543
]
15341544
},
1545+
"job_options": {
1546+
"oneOf": [
1547+
{
1548+
"type": "null"
1549+
},
1550+
{
1551+
"$ref": "#/components/schemas/JobOptions"
1552+
}
1553+
]
1554+
},
15351555
"security": {
15361556
"oneOf": [
15371557
{
@@ -1603,6 +1623,15 @@
16031623
],
16041624
"description": "Maximum bytes for a JSON API payload before deserialization.\nDefault: 64 MB. Set to `None` to disable.",
16051625
"minimum": 0
1626+
},
1627+
"max_total_file_pixels": {
1628+
"type": [
1629+
"integer",
1630+
"null"
1631+
],
1632+
"format": "int64",
1633+
"description": "Maximum total decoded pixels across all frames in a file.\nFor animation, this is checked as frame_count * width * height.\nDefault: 400 megapixels. Set to `None` to disable.",
1634+
"minimum": 0
16061635
}
16071636
}
16081637
},
@@ -1949,6 +1978,10 @@
19491978
}
19501979
}
19511980
},
1981+
"JobOptions": {
1982+
"type": "object",
1983+
"description": "Reserved for future options controlling backends, color management,\nand other job-level behavior. Currently empty."
1984+
},
19521985
"JobResult": {
19531986
"type": "object",
19541987
"required": [
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
526a58cce7aa8a9b5a4149d9f00b1211
1+
8da8d9f74761cd780b80ee05e81c2c9e

imageflow_core/src/json/endpoints/v1.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -717,12 +717,7 @@ fn test_handler() {
717717
];
718718

719719
let build = Build001 {
720-
builder_config: Some(Build001Config {
721-
graph_recording: None,
722-
security: None,
723-
// process_all_gif_frames: Some(false),
724-
// enable_jpeg_block_scaling: Some(false)
725-
}),
720+
builder_config: Some(Build001Config::default()),
726721
io: vec![input_io, output_io],
727722
framewise: Framewise::Steps(steps),
728723
};

imageflow_core/tests/integration/cms_diagnostic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ fn cms_cmyk_backend_divergence() {
4545
ctx.add_output_buffer(1).unwrap();
4646

4747
let execute = s::Execute001 {
48+
job_options: None,
4849
graph_recording: Some(s::Build001GraphRecording::off()),
4950
security: None,
5051
framewise: s::Framewise::Steps(vec![
@@ -88,6 +89,7 @@ fn cms_dual_backend_regression() {
8889
ctx.add_output_buffer(1).unwrap();
8990

9091
let execute = s::Execute001 {
92+
job_options: None,
9193
graph_recording: Some(s::Build001GraphRecording::off()),
9294
security: None,
9395
framewise: s::Framewise::Steps(vec![

imageflow_core/tests/integration/color_conversion.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,7 @@ fn test_matte_compositing_no_double_division() {
859859
ctx.add_input_vector(0, png_bytes).unwrap();
860860
ctx.add_output_buffer(1).unwrap();
861861
let execute = imageflow_types::Execute001 {
862+
job_options: None,
862863
graph_recording: None,
863864
security: None,
864865
framewise: imageflow_types::Framewise::Steps(steps),
@@ -878,6 +879,7 @@ fn test_matte_compositing_no_double_division() {
878879
},
879880
];
880881
let execute2 = imageflow_types::Execute001 {
882+
job_options: None,
881883
graph_recording: None,
882884
security: None,
883885
framewise: imageflow_types::Framewise::Steps(decode_steps),
@@ -1020,6 +1022,7 @@ fn test_matte_compositing_fully_transparent_pixels() {
10201022
ctx.add_input_vector(0, png_bytes).unwrap();
10211023
ctx.add_output_buffer(1).unwrap();
10221024
let execute = imageflow_types::Execute001 {
1025+
job_options: None,
10231026
graph_recording: None,
10241027
security: None,
10251028
framewise: imageflow_types::Framewise::Steps(steps),
@@ -1124,6 +1127,7 @@ fn test_matte_compositing_mixed_alpha() {
11241127
ctx.add_input_vector(0, png_bytes).unwrap();
11251128
ctx.add_output_buffer(1).unwrap();
11261129
let execute = imageflow_types::Execute001 {
1130+
job_options: None,
11271131
graph_recording: None,
11281132
security: None,
11291133
framewise: imageflow_types::Framewise::Steps(steps),

imageflow_core/tests/integration/common/mod.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,12 @@ pub fn build_framewise(
219219
for (ix, val) in io.into_iter().enumerate() {
220220
IoTestTranslator {}.add(context, ix as i32, val)?;
221221
}
222-
let build =
223-
s::Execute001 { security, graph_recording: default_graph_recording(debug), framewise };
222+
let build = s::Execute001 {
223+
job_options: None,
224+
security,
225+
graph_recording: default_graph_recording(debug),
226+
framewise,
227+
};
224228
if debug {
225229
println!("{}", serde_json::to_string_pretty(&build).unwrap());
226230
}
@@ -315,6 +319,7 @@ pub fn decode_image(c: &mut Context, io_id: i32) -> BitmapKey {
315319
fn try_decode_image(c: &mut Context, io_id: i32) -> Option<BitmapKey> {
316320
let capture_id = 0;
317321
let result = c.execute_1(s::Execute001 {
322+
job_options: None,
318323
graph_recording: None,
319324
security: None,
320325
framewise: s::Framewise::Steps(vec![

imageflow_core/tests/integration/encoders.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ pub fn compare_encoded_to_source(
202202
let input_copy = input.clone();
203203

204204
let execute = s::Execute001 {
205+
job_options: None,
205206
graph_recording: default_graph_recording(debug),
206207
security: None,
207208
framewise: s::Framewise::Steps(steps),

0 commit comments

Comments
 (0)