@@ -251,6 +251,10 @@ pub struct CommunityPreset {
251251 pub name : String ,
252252 pub creator : String ,
253253 pub adjustments : Value ,
254+ #[ serde( rename = "includeMasks" ) ]
255+ pub include_masks : Option < bool > ,
256+ #[ serde( rename = "includeCropTransform" ) ]
257+ pub include_crop_transform : Option < bool > ,
254258}
255259
256260#[ derive( Serialize ) ]
@@ -3335,34 +3339,37 @@ fn generate_preset_preview(
33353339 . unwrap ( )
33363340 . clone ( )
33373341 . ok_or ( "No original image loaded for preset preview" ) ?;
3338- let original_image = loaded_image. image ;
3339- let path = loaded_image. path ;
33403342 let is_raw = loaded_image. is_raw ;
3341- let unique_hash = calculate_full_job_hash ( & path, & js_adjustments) ;
3343+ let unique_hash = calculate_full_job_hash ( & loaded_image . path , & js_adjustments) ;
33423344
3343- const PRESET_PREVIEW_DIM : u32 = 200 ;
3344- let preview_base = downscale_f32_image ( & original_image, PRESET_PREVIEW_DIM , PRESET_PREVIEW_DIM ) ;
3345+ const PRESET_PREVIEW_DIM : u32 = 400 ;
33453346
3346- let ( transformed_image, unscaled_crop_offset) =
3347- apply_all_transformations ( Cow :: Borrowed ( & preview_base) , & js_adjustments) ;
3348- let ( img_w, img_h) = transformed_image. dimensions ( ) ;
3347+ let ( preview_image, scale_for_gpu, unscaled_crop_offset) =
3348+ generate_transformed_preview ( & state, & loaded_image, & js_adjustments, PRESET_PREVIEW_DIM ) ?;
3349+
3350+ let ( img_w, img_h) = preview_image. dimensions ( ) ;
33493351
33503352 let mask_definitions: Vec < MaskDefinition > = js_adjustments
33513353 . get ( "masks" )
33523354 . and_then ( |m| serde_json:: from_value ( m. clone ( ) ) . ok ( ) )
33533355 . unwrap_or_default ( ) ;
33543356
3355- let warped_image = resolve_warped_image_for_masks ( & state, & js_adjustments, & mask_definitions) ;
3357+ let scaled_crop_offset = (
3358+ unscaled_crop_offset. 0 * scale_for_gpu,
3359+ unscaled_crop_offset. 1 * scale_for_gpu,
3360+ ) ;
3361+
33563362 let mask_bitmaps: Vec < ImageBuffer < Luma < u8 > , Vec < u8 > > > = mask_definitions
33573363 . iter ( )
33583364 . filter_map ( |def| {
3359- generate_mask_bitmap (
3365+ get_cached_or_generate_mask (
3366+ & state,
33603367 def,
33613368 img_w,
33623369 img_h,
3363- 1.0 ,
3364- unscaled_crop_offset ,
3365- warped_image . as_deref ( ) ,
3370+ scale_for_gpu ,
3371+ scaled_crop_offset ,
3372+ & js_adjustments ,
33663373 )
33673374 } )
33683375 . collect ( ) ;
@@ -3374,7 +3381,7 @@ fn generate_preset_preview(
33743381 let processed_image = process_and_get_dynamic_image (
33753382 & context,
33763383 & state,
3377- transformed_image . as_ref ( ) ,
3384+ & preview_image ,
33783385 unique_hash,
33793386 RenderRequest {
33803387 adjustments : all_adjustments,
@@ -3388,7 +3395,7 @@ fn generate_preset_preview(
33883395 let mut buf = Cursor :: new ( Vec :: new ( ) ) ;
33893396 processed_image
33903397 . to_rgb8 ( )
3391- . write_with_encoder ( JpegEncoder :: new_with_quality ( & mut buf, 50 ) )
3398+ . write_with_encoder ( JpegEncoder :: new_with_quality ( & mut buf, 80 ) )
33923399 . map_err ( |e| e. to_string ( ) ) ?;
33933400
33943401 Ok ( Response :: new ( buf. into_inner ( ) ) )
@@ -3666,7 +3673,7 @@ async fn generate_all_community_previews(
36663673 let highlight_compression = settings. raw_highlight_compression . unwrap_or ( 2.5 ) ;
36673674 let linear_mode = settings. linear_raw_mode ;
36683675
3669- let mut base_thumbnails: Vec < ( DynamicImage , bool ) > = Vec :: new ( ) ;
3676+ let mut base_thumbnails: Vec < ( DynamicImage , bool , f32 ) > = Vec :: new ( ) ;
36703677 for image_path in image_paths. iter ( ) {
36713678 let ( source_path, _) = parse_virtual_path ( image_path) ;
36723679 let source_path_str = source_path. to_string_lossy ( ) . to_string ( ) ;
@@ -3680,11 +3687,18 @@ async fn generate_all_community_previews(
36803687 None ,
36813688 )
36823689 . map_err ( |e| e. to_string ( ) ) ?;
3690+
36833691 let is_raw = is_raw_file ( & source_path_str) ;
3684- base_thumbnails. push ( (
3685- downscale_f32_image ( & original_image, PROCESSING_DIM , PROCESSING_DIM ) ,
3686- is_raw,
3687- ) ) ;
3692+ let ( orig_w, orig_h) = original_image. dimensions ( ) ;
3693+ let ( base_image, base_scale) = if orig_w > PROCESSING_DIM || orig_h > PROCESSING_DIM {
3694+ let downscaled = downscale_f32_image ( & original_image, PROCESSING_DIM , PROCESSING_DIM ) ;
3695+ let scale = downscaled. width ( ) as f32 / orig_w as f32 ;
3696+ ( downscaled, scale)
3697+ } else {
3698+ ( original_image, 1.0 )
3699+ } ;
3700+
3701+ base_thumbnails. push ( ( base_image, is_raw, base_scale) ) ;
36883702 }
36893703
36903704 for preset in presets. iter ( ) {
@@ -3695,33 +3709,53 @@ async fn generate_all_community_previews(
36953709 preset. name . hash ( & mut preset_hasher) ;
36963710 let preset_hash = preset_hasher. finish ( ) ;
36973711
3698- for ( i, ( base_image, is_raw) ) in base_thumbnails. iter ( ) . enumerate ( ) {
3699- let ( transformed_image, unscaled_crop_offset) =
3700- crate :: apply_all_transformations ( Cow :: Borrowed ( base_image) , js_adjustments) ;
3712+ for ( i, ( base_image, is_raw, base_scale) ) in base_thumbnails. iter ( ) . enumerate ( ) {
3713+ let mut scaled_adjustments = js_adjustments. clone ( ) ;
3714+ if let Some ( crop_val) = scaled_adjustments. get_mut ( "crop" )
3715+ && let Ok ( c) = serde_json:: from_value :: < Crop > ( crop_val. clone ( ) )
3716+ {
3717+ * crop_val = serde_json:: to_value ( Crop {
3718+ x : c. x * ( * base_scale as f64 ) ,
3719+ y : c. y * ( * base_scale as f64 ) ,
3720+ width : c. width * ( * base_scale as f64 ) ,
3721+ height : c. height * ( * base_scale as f64 ) ,
3722+ } )
3723+ . unwrap_or ( serde_json:: Value :: Null ) ;
3724+ }
3725+
3726+ let ( transformed_image, _scaled_crop_offset) =
3727+ crate :: apply_all_transformations ( Cow :: Borrowed ( base_image) , & scaled_adjustments) ;
37013728 let ( img_w, img_h) = transformed_image. dimensions ( ) ;
37023729
3703- let mask_definitions: Vec < MaskDefinition > = js_adjustments
3730+ let mask_definitions: Vec < MaskDefinition > = scaled_adjustments
37043731 . get ( "masks" )
37053732 . and_then ( |m| serde_json:: from_value ( m. clone ( ) ) . ok ( ) )
37063733 . unwrap_or_else ( Vec :: new) ;
37073734
3708- let warped_image =
3709- resolve_warped_image_for_masks ( & state, js_adjustments, & mask_definitions) ;
3735+ let unscaled_crop_offset = js_adjustments
3736+ . get ( "crop" )
3737+ . and_then ( |c| serde_json:: from_value :: < Crop > ( c. clone ( ) ) . ok ( ) )
3738+ . map_or ( ( 0.0 , 0.0 ) , |c| ( c. x as f32 , c. y as f32 ) ) ;
3739+ let actual_scaled_crop_offset = (
3740+ unscaled_crop_offset. 0 * base_scale,
3741+ unscaled_crop_offset. 1 * base_scale,
3742+ ) ;
3743+
37103744 let mask_bitmaps: Vec < ImageBuffer < Luma < u8 > , Vec < u8 > > > = mask_definitions
37113745 . iter ( )
37123746 . filter_map ( |def| {
37133747 generate_mask_bitmap (
37143748 def,
37153749 img_w,
37163750 img_h,
3717- 1.0 ,
3718- unscaled_crop_offset ,
3719- warped_image . as_deref ( ) ,
3751+ * base_scale ,
3752+ actual_scaled_crop_offset ,
3753+ None ,
37203754 )
37213755 } )
37223756 . collect ( ) ;
37233757
3724- let all_adjustments = get_all_adjustments_from_json ( js_adjustments , * is_raw) ;
3758+ let all_adjustments = get_all_adjustments_from_json ( & scaled_adjustments , * is_raw) ;
37253759 let lut_path = js_adjustments[ "lutPath" ] . as_str ( ) ;
37263760 let lut = lut_path. and_then ( |p| get_or_load_lut ( & state, p) . ok ( ) ) ;
37273761
0 commit comments